diff --git a/app/src/main/java/code/name/monkey/retromusic/App.kt b/app/src/main/java/code/name/monkey/retromusic/App.kt index 0c3d590d..7dd3084d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/App.kt +++ b/app/src/main/java/code/name/monkey/retromusic/App.kt @@ -3,6 +3,8 @@ package code.name.monkey.retromusic import android.content.Context import androidx.multidex.MultiDexApplication import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.appthemehelper.util.VersionUtils +import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager import com.anjlab.android.iab.v3.BillingProcessor import com.anjlab.android.iab.v3.TransactionDetails import com.bumptech.glide.Glide @@ -25,6 +27,10 @@ class App : MultiDexApplication() { .commit() } + if (VersionUtils.hasNougatMR()) + DynamicShortcutManager(this).initDynamicShortcuts() + + // automatically restores purchases billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSE_KEY, object : BillingProcessor.IBillingHandler { diff --git a/app/src/main/java/code/name/monkey/retromusic/Injection.kt b/app/src/main/java/code/name/monkey/retromusic/Injection.kt index 349d029f..768a9862 100644 --- a/app/src/main/java/code/name/monkey/retromusic/Injection.kt +++ b/app/src/main/java/code/name/monkey/retromusic/Injection.kt @@ -10,7 +10,7 @@ import code.name.monkey.retromusic.util.schedulers.SchedulerProvider object Injection { fun provideRepository(): Repository { - return RepositoryImpl.getInstance() + return RepositoryImpl.instance } fun provideSchedulerProvider(): BaseSchedulerProvider { diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.java b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.java new file mode 100644 index 00000000..6e51c31e --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.java @@ -0,0 +1,70 @@ +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; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.java b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.java new file mode 100644 index 00000000..85e9c402 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.java @@ -0,0 +1,77 @@ +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); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/DynamicShortcutManager.java b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/DynamicShortcutManager.java new file mode 100644 index 00000000..2c4975e3 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/DynamicShortcutManager.java @@ -0,0 +1,63 @@ +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 getDefaultShortcuts() { + return (Arrays.asList( + new ShuffleAllShortcutType(context).getShortcutInfo(), + new TopTracksShortcutType(context).getShortcutInfo(), + new LastAddedShortcutType(context).getShortcutInfo() + )); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/BaseShortcutType.java b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/BaseShortcutType.java new file mode 100644 index 00000000..28f16a7e --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/BaseShortcutType.java @@ -0,0 +1,50 @@ +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; + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/LastAddedShortcutType.java b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/LastAddedShortcutType.java new file mode 100644 index 00000000..72db3eeb --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/LastAddedShortcutType.java @@ -0,0 +1,34 @@ +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(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/ShuffleAllShortcutType.java b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/ShuffleAllShortcutType.java new file mode 100644 index 00000000..be3ba008 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/ShuffleAllShortcutType.java @@ -0,0 +1,35 @@ +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(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/TopTracksShortcutType.java b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/TopTracksShortcutType.java new file mode 100644 index 00000000..3e78db33 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/shortcuttype/TopTracksShortcutType.java @@ -0,0 +1,35 @@ +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(); + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetBig.kt b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetBig.kt new file mode 100644 index 00000000..f6e7360e --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetBig.kt @@ -0,0 +1,167 @@ +package code.name.monkey.retromusic.appwidgets + +import android.app.PendingIntent +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import android.text.TextUtils +import android.view.View +import android.widget.RemoteViews +import code.name.monkey.appthemehelper.util.MaterialValueHelper +import code.name.monkey.retromusic.Constants +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget +import code.name.monkey.retromusic.glide.SongGlideRequest +import code.name.monkey.retromusic.service.MusicService +import code.name.monkey.retromusic.ui.activities.MainActivity +import code.name.monkey.retromusic.util.RetroUtil +import com.bumptech.glide.Glide +import com.bumptech.glide.request.animation.GlideAnimation +import com.bumptech.glide.request.target.SimpleTarget +import com.bumptech.glide.request.target.Target + +class AppWidgetBig : BaseAppWidget() { + private var target: Target? = null // for cancellation + + /** + * Initialize given widgets to default state, where we launch Music on default click and hide + * actions if service not running. + */ + override fun defaultAppWidget(context: Context, appWidgetIds: IntArray) { + val appWidgetView = RemoteViews(context.packageName, + R.layout.app_widget_big) + + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE) + appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art) + appWidgetView.setImageViewBitmap(R.id.button_next, BaseAppWidget.createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, + MaterialValueHelper.getPrimaryTextColor(context, false))!!, 1f)) + appWidgetView.setImageViewBitmap(R.id.button_prev, BaseAppWidget.Companion.createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, + MaterialValueHelper.getPrimaryTextColor(context, false))!!, 1f)) + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, BaseAppWidget.Companion.createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, + MaterialValueHelper.getPrimaryTextColor(context, false))!!, 1f)) + + linkButtons(context, appWidgetView) + pushUpdate(context, appWidgetIds, appWidgetView) + } + + /** + * Update all active widget instances by pushing changes + */ + override fun performUpdate(service: MusicService, appWidgetIds: IntArray?) { + val appWidgetView = RemoteViews(service.packageName, + R.layout.app_widget_big) + + val isPlaying = service.isPlaying + val song = service.currentSong + + // Set the titles and artwork + if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) { + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE) + } else { + appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE) + appWidgetView.setTextViewText(R.id.title, song.title) + appWidgetView.setTextViewText(R.id.text, getSongArtistAndAlbum(song)) + } + + // Set correct drawable for pause state + val playPauseRes = if (isPlaying) R.drawable.ic_pause_white_24dp else R.drawable.ic_play_arrow_white_24dp + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, BaseAppWidget.createBitmap( + RetroUtil.getTintedVectorDrawable(service, playPauseRes, + MaterialValueHelper.getPrimaryTextColor(service, false))!!, 1f)) + + // Set prev/next button drawables + appWidgetView.setImageViewBitmap(R.id.button_next, BaseAppWidget.Companion.createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, + MaterialValueHelper.getPrimaryTextColor(service, false))!!, 1f)) + appWidgetView.setImageViewBitmap(R.id.button_prev, BaseAppWidget.Companion.createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, + MaterialValueHelper.getPrimaryTextColor(service, false))!!, 1f)) + + // Link actions buttons to intents + linkButtons(service, appWidgetView) + + // Load the album cover async and push the update on completion + val p = RetroUtil.getScreenSize(service) + val widgetImageSize = Math.min(p.x, p.y) + val appContext = service.applicationContext + service.runOnUiThread { + if (target != null) { + Glide.clear(target!!) + } + target = SongGlideRequest.Builder.from(Glide.with(appContext), song) + .checkIgnoreMediaStore(appContext) + .asBitmap().build() + .into(object : SimpleTarget(widgetImageSize, widgetImageSize) { + override fun onResourceReady(resource: Bitmap, + glideAnimation: GlideAnimation) { + update(resource) + } + + override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) { + super.onLoadFailed(e, errorDrawable) + update(null) + } + + private fun update(bitmap: Bitmap?) { + if (bitmap == null) { + appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art) + } else { + appWidgetView.setImageViewBitmap(R.id.image, bitmap) + } + pushUpdate(appContext, appWidgetIds, appWidgetView) + } + }) + } + } + + /** + * Link up various button actions using [PendingIntent]. + */ + private fun linkButtons(context: Context, views: RemoteViews) { + val action = Intent(context, MainActivity::class.java).putExtra("expand", true) + var pendingIntent: PendingIntent + + val serviceName = ComponentName(context, MusicService::class.java) + + // Home + action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + pendingIntent = PendingIntent.getActivity(context, 0, action, 0) + views.setOnClickPendingIntent(R.id.clickable_area, pendingIntent) + + // Previous track + pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName) + views.setOnClickPendingIntent(R.id.button_prev, pendingIntent) + + // Play and pause + pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName) + views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent) + + // Next track + pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName) + views.setOnClickPendingIntent(R.id.button_next, pendingIntent) + + + } + + companion object { + + + const val NAME: String = "app_widget_big" + + private var mInstance: AppWidgetBig? = null + + val instance: AppWidgetBig + @Synchronized get() { + if (mInstance == null) { + mInstance = AppWidgetBig() + } + return mInstance!! + } + + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCard.kt b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCard.kt new file mode 100644 index 00000000..dba76542 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCard.kt @@ -0,0 +1,182 @@ +package code.name.monkey.retromusic.appwidgets + +import android.app.PendingIntent +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import android.text.TextUtils +import android.view.View +import android.widget.RemoteViews +import code.name.monkey.appthemehelper.util.MaterialValueHelper +import code.name.monkey.retromusic.Constants +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget +import code.name.monkey.retromusic.glide.SongGlideRequest +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper +import code.name.monkey.retromusic.service.MusicService +import code.name.monkey.retromusic.ui.activities.MainActivity +import code.name.monkey.retromusic.util.RetroUtil +import com.bumptech.glide.Glide +import com.bumptech.glide.request.animation.GlideAnimation +import com.bumptech.glide.request.target.SimpleTarget +import com.bumptech.glide.request.target.Target + +class AppWidgetCard : BaseAppWidget() { + private var target: Target? = null // for cancellation + + /** + * Initialize given widgets to default state, where we launch Music on default click and hide + * actions if service not running. + */ + override fun defaultAppWidget(context: Context, appWidgetIds: IntArray) { + val appWidgetView = RemoteViews(context.packageName, + R.layout.app_widget_card) + + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE) + appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art) + appWidgetView.setImageViewBitmap(R.id.button_next, BaseAppWidget.Companion.createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, + MaterialValueHelper.getSecondaryTextColor(context, true))!!, 1f)) + appWidgetView.setImageViewBitmap(R.id.button_prev, BaseAppWidget.Companion.createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, + MaterialValueHelper.getSecondaryTextColor(context, true))!!, 1f)) + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, BaseAppWidget.Companion.createBitmap( + RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, + MaterialValueHelper.getSecondaryTextColor(context, true))!!, 1f)) + + linkButtons(context, appWidgetView) + pushUpdate(context, appWidgetIds, appWidgetView) + } + + /** + * Update all active widget instances by pushing changes + */ + override fun performUpdate(service: MusicService, appWidgetIds: IntArray?) { + val appWidgetView = RemoteViews(service.packageName, + R.layout.app_widget_card) + + val isPlaying = service.isPlaying + val song = service.currentSong + + // Set the titles and artwork + if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) { + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE) + } else { + appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE) + appWidgetView.setTextViewText(R.id.title, song.title) + appWidgetView.setTextViewText(R.id.text, getSongArtistAndAlbum(song)) + } + + // Set correct drawable for pause state + val playPauseRes = if (isPlaying) R.drawable.ic_pause_white_24dp else R.drawable.ic_play_arrow_white_24dp + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, BaseAppWidget.Companion.createBitmap( + RetroUtil.getTintedVectorDrawable(service, playPauseRes, + MaterialValueHelper.getSecondaryTextColor(service, true))!!, 1f)) + + // Set prev/next button drawables + appWidgetView.setImageViewBitmap(R.id.button_next, BaseAppWidget.Companion.createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, + MaterialValueHelper.getSecondaryTextColor(service, true))!!, 1f)) + appWidgetView.setImageViewBitmap(R.id.button_prev, BaseAppWidget.Companion.createBitmap( + RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, + MaterialValueHelper.getSecondaryTextColor(service, true))!!, 1f)) + + // Link actions buttons to intents + linkButtons(service, appWidgetView) + + if (imageSize == 0) { + imageSize = service.resources.getDimensionPixelSize(R.dimen.app_widget_card_image_size) + } + if (cardRadius == 0f) { + cardRadius = service.resources.getDimension(R.dimen.app_widget_card_radius) + } + + // Load the album cover async and push the update on completion + service.runOnUiThread { + if (target != null) { + Glide.clear(target!!) + } + target = SongGlideRequest.Builder.from(Glide.with(service), song) + .checkIgnoreMediaStore(service) + .generatePalette(service).build() + .centerCrop() + .into(object : SimpleTarget(imageSize, imageSize) { + override fun onResourceReady(resource: BitmapPaletteWrapper, + glideAnimation: GlideAnimation) { + val palette = resource.palette + update(resource.bitmap, palette.getVibrantColor(palette + .getMutedColor(MaterialValueHelper.getSecondaryTextColor(service, true)))) + } + + override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) { + super.onLoadFailed(e, errorDrawable) + update(null, MaterialValueHelper.getSecondaryTextColor(service, true)) + } + + private fun update(bitmap: Bitmap?, color: Int) { + // Set correct drawable for pause state + val playPauseRest = if (isPlaying) R.drawable.ic_pause_white_24dp + else + R.drawable.ic_play_arrow_white_24dp + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, BaseAppWidget.createBitmap(RetroUtil.getTintedVectorDrawable(service, playPauseRest, color)!!, 1f)) + // Set prev/next button drawables + appWidgetView.setImageViewBitmap(R.id.button_next, BaseAppWidget.createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, color)!!, 1f)) + appWidgetView.setImageViewBitmap(R.id.button_prev, BaseAppWidget.createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, color)!!, 1f)) + + val image = getAlbumArtDrawable(service.resources, bitmap) + val roundedBitmap = BaseAppWidget.Companion.createRoundedBitmap(image, imageSize, imageSize, cardRadius, 0f, cardRadius, 0f) + appWidgetView.setImageViewBitmap(R.id.image, roundedBitmap) + + pushUpdate(service, appWidgetIds, appWidgetView) + } + }) + } + } + + /** + * Link up various button actions using [PendingIntent]. + */ + private fun linkButtons(context: Context, views: RemoteViews) { + val action: Intent = Intent(context, MainActivity::class.java).putExtra("expand", true) + var pendingIntent: PendingIntent + + val serviceName = ComponentName(context, MusicService::class.java) + + // Home + action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + pendingIntent = PendingIntent.getActivity(context, 0, action, 0) + views.setOnClickPendingIntent(R.id.image, pendingIntent) + views.setOnClickPendingIntent(R.id.media_titles, pendingIntent) + + // Previous track + pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName) + views.setOnClickPendingIntent(R.id.button_prev, pendingIntent) + + // Play and pause + pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName) + views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent) + + // Next track + pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName) + views.setOnClickPendingIntent(R.id.button_next, pendingIntent) + } + + companion object { + + const val NAME = "app_widget_card" + + private var mInstance: AppWidgetCard? = null + private var imageSize = 0 + private var cardRadius = 0f + + val instance: AppWidgetCard + @Synchronized get() { + if (mInstance == null) { + mInstance = AppWidgetCard() + } + return mInstance!! + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetClassic.kt b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetClassic.kt new file mode 100644 index 00000000..c1c47871 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetClassic.kt @@ -0,0 +1,166 @@ +package code.name.monkey.retromusic.appwidgets + +import android.app.PendingIntent +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import android.text.TextUtils +import android.view.View +import android.widget.RemoteViews +import code.name.monkey.appthemehelper.util.MaterialValueHelper +import code.name.monkey.retromusic.Constants +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget +import code.name.monkey.retromusic.glide.SongGlideRequest +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper +import code.name.monkey.retromusic.service.MusicService +import code.name.monkey.retromusic.ui.activities.MainActivity +import code.name.monkey.retromusic.util.RetroUtil +import com.bumptech.glide.Glide +import com.bumptech.glide.request.animation.GlideAnimation +import com.bumptech.glide.request.target.SimpleTarget +import com.bumptech.glide.request.target.Target + +class AppWidgetClassic : BaseAppWidget() { + private var target: Target? = null // for cancellation + + /** + * Initialize given widgets to default state, where we launch Music on default click and hide + * actions if service not running. + */ + override fun defaultAppWidget(context: Context, appWidgetIds: IntArray) { + val appWidgetView = RemoteViews(context.packageName, R.layout.app_widget_classic) + + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE) + appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art) + appWidgetView.setImageViewBitmap(R.id.button_next, BaseAppWidget.Companion.createBitmap(RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))!!, 1f)) + appWidgetView.setImageViewBitmap(R.id.button_prev, BaseAppWidget.Companion.createBitmap(RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))!!, 1f)) + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, BaseAppWidget.Companion.createBitmap(RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))!!, 1f)) + + linkButtons(context, appWidgetView) + pushUpdate(context, appWidgetIds, appWidgetView) + } + + /** + * Update all active widget instances by pushing changes + */ + override fun performUpdate(service: MusicService, appWidgetIds: IntArray?) { + val appWidgetView = RemoteViews(service.packageName, + R.layout.app_widget_classic) + + val isPlaying = service.isPlaying + val song = service.currentSong + + // Set the titles and artwork + if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) { + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE) + } else { + appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE) + appWidgetView.setTextViewText(R.id.title, song.title) + appWidgetView.setTextViewText(R.id.text, getSongArtistAndAlbum(song)) + } + + // Link actions buttons to intents + linkButtons(service, appWidgetView) + + if (imageSize == 0) { + imageSize = service.resources + .getDimensionPixelSize(R.dimen.app_widget_classic_image_size) + } + if (cardRadius == 0f) { + cardRadius = service.resources.getDimension(R.dimen.app_widget_card_radius) + } + + // Load the album cover async and push the update on completion + val appContext = service.applicationContext + service.runOnUiThread { + if (target != null) { + Glide.clear(target!!) + } + target = SongGlideRequest.Builder.from(Glide.with(appContext), song) + .checkIgnoreMediaStore(appContext) + .generatePalette(service).build() + .centerCrop() + .into(object : SimpleTarget(imageSize, imageSize) { + override fun onResourceReady(resource: BitmapPaletteWrapper, + glideAnimation: GlideAnimation) { + val palette = resource.palette + update(resource.bitmap, palette.getVibrantColor(palette.getMutedColor(MaterialValueHelper.getSecondaryTextColor(appContext, true)))) + } + + override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) { + super.onLoadFailed(e, errorDrawable) + update(null, MaterialValueHelper.getSecondaryTextColor(appContext, true)) + } + + private fun update(bitmap: Bitmap?, color: Int) { + // Set correct drawable for pause state + val playPauseRes = if (isPlaying) + R.drawable.ic_pause_white_24dp + else + R.drawable.ic_play_arrow_white_24dp + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, + BaseAppWidget.createBitmap(RetroUtil.getTintedVectorDrawable(service, playPauseRes, color)!!, 1f)) + + // Set prev/next button drawables + appWidgetView.setImageViewBitmap(R.id.button_next, BaseAppWidget.createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, color)!!, 1f)) + appWidgetView.setImageViewBitmap(R.id.button_prev, BaseAppWidget.createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, color)!!, 1f)) + + val image = getAlbumArtDrawable(service.resources, bitmap) + val roundedBitmap = BaseAppWidget.createRoundedBitmap(image, imageSize, imageSize, + cardRadius, 0f, cardRadius, 0f) + appWidgetView.setImageViewBitmap(R.id.image, roundedBitmap) + + pushUpdate(appContext, appWidgetIds, appWidgetView) + } + }) + } + } + + /** + * Link up various button actions using [PendingIntent]. + */ + private fun linkButtons(context: Context, views: RemoteViews) { + val action = Intent(context, MainActivity::class.java).putExtra("expand", true) + var pendingIntent: PendingIntent + + val serviceName = ComponentName(context, MusicService::class.java) + + // Home + action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + pendingIntent = PendingIntent.getActivity(context, 0, action, 0) + views.setOnClickPendingIntent(R.id.image, pendingIntent) + views.setOnClickPendingIntent(R.id.media_titles, pendingIntent) + + // Previous track + pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName) + views.setOnClickPendingIntent(R.id.button_prev, pendingIntent) + + // Play and pause + pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName) + views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent) + + // Next track + pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName) + views.setOnClickPendingIntent(R.id.button_next, pendingIntent) + } + + companion object { + + const val NAME = "app_widget_classic" + + private var mInstance: AppWidgetClassic? = null + private var imageSize = 0 + private var cardRadius = 0f + + val instance: AppWidgetClassic + @Synchronized get() { + if (mInstance == null) { + mInstance = AppWidgetClassic() + } + return mInstance!! + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetSmall.kt b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetSmall.kt new file mode 100644 index 00000000..391c07c4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetSmall.kt @@ -0,0 +1,170 @@ +package code.name.monkey.retromusic.appwidgets + +import android.app.PendingIntent +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import android.text.TextUtils +import android.view.View +import android.widget.RemoteViews +import code.name.monkey.appthemehelper.util.MaterialValueHelper +import code.name.monkey.retromusic.Constants +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget +import code.name.monkey.retromusic.glide.SongGlideRequest +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper +import code.name.monkey.retromusic.service.MusicService +import code.name.monkey.retromusic.ui.activities.MainActivity +import code.name.monkey.retromusic.util.RetroUtil +import com.bumptech.glide.Glide +import com.bumptech.glide.request.animation.GlideAnimation +import com.bumptech.glide.request.target.SimpleTarget +import com.bumptech.glide.request.target.Target + +class AppWidgetSmall : BaseAppWidget() { + private var target: Target? = null // for cancellation + + /** + * Initialize given widgets to default state, where we launch Music on default click and hide + * actions if service not running. + */ + override fun defaultAppWidget(context: Context, appWidgetIds: IntArray) { + val appWidgetView = RemoteViews(context.packageName, R.layout.app_widget_small) + + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE) + appWidgetView.setImageViewResource(R.id.image, R.drawable.default_album_art) + appWidgetView.setImageViewBitmap(R.id.button_next, BaseAppWidget.Companion.createBitmap(RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_next_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))!!, 1f)) + appWidgetView.setImageViewBitmap(R.id.button_prev, BaseAppWidget.Companion.createBitmap(RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_skip_previous_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))!!, 1f)) + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, BaseAppWidget.Companion.createBitmap(RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_play_arrow_white_24dp, MaterialValueHelper.getSecondaryTextColor(context, true))!!, 1f)) + + linkButtons(context, appWidgetView) + pushUpdate(context, appWidgetIds, appWidgetView) + } + + /** + * Update all active widget instances by pushing changes + */ + override fun performUpdate(service: MusicService, appWidgetIds: IntArray?) { + val appWidgetView = RemoteViews(service.packageName, + R.layout.app_widget_small) + + val isPlaying = service.isPlaying + val song = service.currentSong + + // Set the titles and artwork + if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) { + appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE) + } else { + if (TextUtils.isEmpty(song.title) || TextUtils.isEmpty(song.artistName)) { + appWidgetView.setTextViewText(R.id.text_separator, "") + } else { + appWidgetView.setTextViewText(R.id.text_separator, "•") + } + + appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE) + appWidgetView.setTextViewText(R.id.title, song.title) + appWidgetView.setTextViewText(R.id.text, song.artistName) + } + + // Link actions buttons to intents + linkButtons(service, appWidgetView) + + if (imageSize == 0) { + imageSize = service.resources.getDimensionPixelSize(R.dimen.app_widget_small_image_size) + } + if (cardRadius == 0f) { + cardRadius = service.resources.getDimension(R.dimen.app_widget_card_radius) + } + + // Load the album cover async and push the update on completion + val appContext = service.applicationContext + service.runOnUiThread { + if (target != null) { + Glide.clear(target!!) + } + target = SongGlideRequest.Builder.from(Glide.with(appContext), song) + .checkIgnoreMediaStore(appContext) + .generatePalette(service).build() + .centerCrop() + .into(object : SimpleTarget(imageSize, imageSize) { + override fun onResourceReady(resource: BitmapPaletteWrapper, + glideAnimation: GlideAnimation) { + val palette = resource.palette + update(resource.bitmap, palette.getVibrantColor(palette + .getMutedColor(MaterialValueHelper.getSecondaryTextColor(appContext, true)))) + } + + override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) { + super.onLoadFailed(e, errorDrawable) + update(null, MaterialValueHelper.getSecondaryTextColor(appContext, true)) + } + + private fun update(bitmap: Bitmap?, color: Int) { + // Set correct drawable for pause state + val playPauseRes = if (isPlaying) + R.drawable.ic_pause_white_24dp + else + R.drawable.ic_play_arrow_white_24dp + appWidgetView.setImageViewBitmap(R.id.button_toggle_play_pause, BaseAppWidget.Companion.createBitmap(RetroUtil.getTintedVectorDrawable(service, playPauseRes, color)!!, 1f)) + + // Set prev/next button drawables + appWidgetView.setImageViewBitmap(R.id.button_next, BaseAppWidget.Companion.createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_next_white_24dp, color)!!, 1f)) + appWidgetView.setImageViewBitmap(R.id.button_prev, BaseAppWidget.Companion.createBitmap(RetroUtil.getTintedVectorDrawable(service, R.drawable.ic_skip_previous_white_24dp, color)!!, 1f)) + + val image = getAlbumArtDrawable(service.resources, bitmap) + val roundedBitmap = BaseAppWidget.createRoundedBitmap(image, imageSize, imageSize, cardRadius, 0f, 0f, 0f) + appWidgetView.setImageViewBitmap(R.id.image, roundedBitmap) + + pushUpdate(appContext, appWidgetIds, appWidgetView) + } + }) + } + } + + /** + * Link up various button actions using [PendingIntent]. + */ + private fun linkButtons(context: Context, views: RemoteViews) { + val action = Intent(context, MainActivity::class.java).putExtra("expand", true) + var pendingIntent: PendingIntent + + val serviceName = ComponentName(context, MusicService::class.java) + + // Home + action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + pendingIntent = PendingIntent.getActivity(context, 0, action, 0) + views.setOnClickPendingIntent(R.id.image, pendingIntent) + views.setOnClickPendingIntent(R.id.media_titles, pendingIntent) + + // Previous track + pendingIntent = buildPendingIntent(context, Constants.ACTION_REWIND, serviceName) + views.setOnClickPendingIntent(R.id.button_prev, pendingIntent) + + // Play and pause + pendingIntent = buildPendingIntent(context, Constants.ACTION_TOGGLE_PAUSE, serviceName) + views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent) + + // Next track + pendingIntent = buildPendingIntent(context, Constants.ACTION_SKIP, serviceName) + views.setOnClickPendingIntent(R.id.button_next, pendingIntent) + } + + companion object { + + const val NAME:String = "app_widget_small" + + private var mInstance: AppWidgetSmall? = null + private var imageSize = 0 + private var cardRadius = 0f + + val instance: AppWidgetSmall + @Synchronized get() { + if (mInstance == null) { + mInstance = AppWidgetSmall() + } + return mInstance!! + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/BootReceiver.kt b/app/src/main/java/code/name/monkey/retromusic/appwidgets/BootReceiver.kt new file mode 100644 index 00000000..8afd98c1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/BootReceiver.kt @@ -0,0 +1,31 @@ +package code.name.monkey.retromusic.appwidgets + +import android.appwidget.AppWidgetManager +import android.content.BroadcastReceiver +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.os.Build + +import code.name.monkey.retromusic.service.MusicService + + +/** + * @author Eugene Cheung (arkon) + */ +class BootReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val widgetManager = AppWidgetManager.getInstance(context) + + // Start music service if there are any existing widgets + if (widgetManager.getAppWidgetIds(ComponentName(context, AppWidgetBig::class.java)).isNotEmpty() || + widgetManager.getAppWidgetIds(ComponentName(context, AppWidgetClassic::class.java)).isNotEmpty() || + widgetManager.getAppWidgetIds(ComponentName(context, AppWidgetSmall::class.java)).isNotEmpty() || + widgetManager.getAppWidgetIds(ComponentName(context, AppWidgetCard::class.java)).isNotEmpty()) { + val serviceIntent = Intent(context, MusicService::class.java) + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { // not allowed on Oreo + context.startService(serviceIntent) + } + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/base/BaseAppWidget.kt b/app/src/main/java/code/name/monkey/retromusic/appwidgets/base/BaseAppWidget.kt new file mode 100644 index 00000000..f449893c --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/base/BaseAppWidget.kt @@ -0,0 +1,163 @@ +package code.name.monkey.retromusic.appwidgets.base + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.res.Resources +import android.graphics.* +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import android.os.Build +import android.text.TextUtils +import android.widget.RemoteViews +import androidx.core.content.ContextCompat +import code.name.monkey.retromusic.App +import code.name.monkey.retromusic.Constants +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.service.MusicService + +abstract class BaseAppWidget : AppWidgetProvider() { + + /** + * {@inheritDoc} + */ + override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, + appWidgetIds: IntArray) { + defaultAppWidget(context, appWidgetIds) + val updateIntent = Intent(Constants.APP_WIDGET_UPDATE) + updateIntent.putExtra(Constants.EXTRA_APP_WIDGET_NAME, NAME) + updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds) + updateIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY) + context.sendBroadcast(updateIntent) + } + + /** + * Handle a change notification coming over from [MusicService] + */ + fun notifyChange(service: MusicService, what: String) { + if (hasInstances(service)) { + if (Constants.META_CHANGED == what || Constants.PLAY_STATE_CHANGED == what) { + performUpdate(service, null) + } + } + } + + protected fun pushUpdate(context: Context, appWidgetIds: IntArray?, + views: RemoteViews) { + val appWidgetManager = AppWidgetManager.getInstance(context) + if (appWidgetIds != null) { + appWidgetManager.updateAppWidget(appWidgetIds, views) + } else { + appWidgetManager.updateAppWidget(ComponentName(context, javaClass), views) + } + } + + /** + * Check against [AppWidgetManager] if there are any instances of this widget. + */ + protected fun hasInstances(context: Context): Boolean { + val appWidgetManager = AppWidgetManager.getInstance(context) + val mAppWidgetIds = appWidgetManager.getAppWidgetIds(ComponentName(context, + javaClass)) + return mAppWidgetIds.size > 0 + } + + protected fun buildPendingIntent(context: Context, action: String, + serviceName: ComponentName): PendingIntent { + val intent = Intent(action) + intent.component = serviceName + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + PendingIntent.getForegroundService(context, 0, intent, 0) + } else { + PendingIntent.getService(context, 0, intent, 0) + } + } + + protected abstract fun defaultAppWidget(context: Context, appWidgetIds: IntArray) + + abstract fun performUpdate(service: MusicService, appWidgetIds: IntArray?) + + protected fun getAlbumArtDrawable(resources: Resources, bitmap: Bitmap?): Drawable { + return if (bitmap == null) { + ContextCompat.getDrawable(App.context, R.drawable.default_album_art)!! + } else { + BitmapDrawable(resources, bitmap) + } + } + + protected fun getSongArtistAndAlbum(song: Song): String { + val builder = StringBuilder() + builder.append(song.artistName) + if (!TextUtils.isEmpty(song.artistName) && !TextUtils.isEmpty(song.albumName)) { + builder.append(" • ") + } + builder.append(song.albumName) + return builder.toString() + } + + companion object { + + const val NAME: String = "app_widget" + + + fun createRoundedBitmap(drawable: Drawable?, width: Int, height: Int, tl: Float, + tr: Float, bl: Float, br: Float): Bitmap? { + if (drawable == null) { + return null + } + + val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) + val c = Canvas(bitmap) + drawable.setBounds(0, 0, width, height) + drawable.draw(c) + + val rounded = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) + + val canvas = Canvas(rounded) + val paint = Paint() + paint.shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) + paint.isAntiAlias = true + canvas.drawPath(composeRoundedRectPath(RectF(0f, 0f, width.toFloat(), height.toFloat()), tl, tr, bl, br), paint) + + return rounded + } + + fun createBitmap(drawable: Drawable, sizeMultiplier: Float): Bitmap { + val bitmap = Bitmap.createBitmap((drawable.intrinsicWidth * sizeMultiplier).toInt(), + (drawable.intrinsicHeight * sizeMultiplier).toInt(), Bitmap.Config.ARGB_8888) + val c = Canvas(bitmap) + drawable.setBounds(0, 0, c.width, c.height) + drawable.draw(c) + return bitmap + } + + 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) + path.lineTo(rect.right, rect.bottom - br) + path.quadTo(rect.right, rect.bottom, rect.right - br, rect.bottom) + path.lineTo(rect.left + bl, rect.bottom) + path.quadTo(rect.left, rect.bottom, rect.left, rect.bottom - bl) + path.lineTo(rect.left, rect.top + tl) + path.quadTo(rect.left, rect.top, rect.left + tl, rect.top) + path.close() + + return path + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.kt index f2b91e05..b6dcdc40 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.kt @@ -24,7 +24,7 @@ class DeletePlaylistDialog : RoundedBottomSheetDialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - val playlists = arguments!!.getParcelableArrayList("playlists") + val playlists = arguments!!.getParcelableArrayList("playlist") val content: CharSequence content = if (playlists!!.size > 1) { diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/SortOrder.kt b/app/src/main/java/code/name/monkey/retromusic/helper/SortOrder.kt index b2fb952e..e79a290f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/SortOrder.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/SortOrder.kt @@ -29,16 +29,16 @@ class SortOrder { companion object { /* Artist sort order A-Z */ - val ARTIST_A_Z = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER + const val ARTIST_A_Z = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER /* Artist sort order Z-A */ - val ARTIST_Z_A = "$ARTIST_A_Z DESC" + const val ARTIST_Z_A = "$ARTIST_A_Z DESC" /* Artist sort order number of songs */ - val ARTIST_NUMBER_OF_SONGS = MediaStore.Audio.Artists.NUMBER_OF_TRACKS + " DESC" + const val ARTIST_NUMBER_OF_SONGS = MediaStore.Audio.Artists.NUMBER_OF_TRACKS + " DESC" /* Artist sort order number of albums */ - val ARTIST_NUMBER_OF_ALBUMS = MediaStore.Audio.Artists.NUMBER_OF_ALBUMS + " DESC" + const val ARTIST_NUMBER_OF_ALBUMS = MediaStore.Audio.Artists.NUMBER_OF_ALBUMS + " DESC" } } @@ -49,20 +49,20 @@ class SortOrder { companion object { /* Album sort order A-Z */ - val ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER + const val ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER /* Album sort order Z-A */ - val ALBUM_Z_A = "$ALBUM_A_Z DESC" + const val ALBUM_Z_A = "$ALBUM_A_Z DESC" /* Album sort order songs */ - val ALBUM_NUMBER_OF_SONGS = MediaStore.Audio.Albums.NUMBER_OF_SONGS + " DESC" + const val ALBUM_NUMBER_OF_SONGS = MediaStore.Audio.Albums.NUMBER_OF_SONGS + " DESC" /* Album sort order artist */ - val ALBUM_ARTIST = (MediaStore.Audio.Artists.DEFAULT_SORT_ORDER + const val ALBUM_ARTIST = (MediaStore.Audio.Artists.DEFAULT_SORT_ORDER + ", " + MediaStore.Audio.Albums.DEFAULT_SORT_ORDER) /* Album sort order year */ - val ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC" + const val ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC" } } @@ -73,25 +73,25 @@ class SortOrder { companion object { /* Song sort order A-Z */ - val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER + const val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER /* Song sort order Z-A */ - val SONG_Z_A = "$SONG_A_Z DESC" + const val SONG_Z_A = "$SONG_A_Z DESC" /* Song sort order artist */ - val SONG_ARTIST = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER + const val SONG_ARTIST = MediaStore.Audio.Artists.DEFAULT_SORT_ORDER /* Song sort order album */ - val SONG_ALBUM = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER + const val SONG_ALBUM = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER /* Song sort order year */ - val SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC" + const val SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC" /* Song sort order duration */ - val SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC" + const val SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC" /* Song sort order date */ - val SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC" + const val SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC" } } @@ -102,17 +102,17 @@ class SortOrder { companion object { /* Album song sort order A-Z */ - val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER + const val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER /* Album song sort order Z-A */ - val SONG_Z_A = "$SONG_A_Z DESC" + const val SONG_Z_A = "$SONG_A_Z DESC" /* Album song sort order track list */ - val SONG_TRACK_LIST = (MediaStore.Audio.Media.TRACK + ", " + const val SONG_TRACK_LIST = (MediaStore.Audio.Media.TRACK + ", " + MediaStore.Audio.Media.DEFAULT_SORT_ORDER) /* Album song sort order duration */ - val SONG_DURATION = SongSortOrder.SONG_DURATION + const val SONG_DURATION = SongSortOrder.SONG_DURATION } } @@ -123,22 +123,22 @@ class SortOrder { companion object { /* Artist song sort order A-Z */ - val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER + const val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER /* Artist song sort order Z-A */ - val SONG_Z_A = "$SONG_A_Z DESC" + const val SONG_Z_A = "$SONG_A_Z DESC" /* Artist song sort order album */ - val SONG_ALBUM = MediaStore.Audio.Media.ALBUM + const val SONG_ALBUM = MediaStore.Audio.Media.ALBUM /* Artist song sort order year */ - val SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC" + const val SONG_YEAR = MediaStore.Audio.Media.YEAR + " DESC" /* Artist song sort order duration */ - val SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC" + const val SONG_DURATION = MediaStore.Audio.Media.DURATION + " DESC" /* Artist song sort order date */ - val SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC" + const val SONG_DATE = MediaStore.Audio.Media.DATE_ADDED + " DESC" } } @@ -149,16 +149,16 @@ class SortOrder { companion object { /* Artist album sort order A-Z */ - val ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER + const val ALBUM_A_Z = MediaStore.Audio.Albums.DEFAULT_SORT_ORDER /* Artist album sort order Z-A */ - val ALBUM_Z_A = "$ALBUM_A_Z DESC" + const val ALBUM_Z_A = "$ALBUM_A_Z DESC" /* Artist album sort order year */ - val ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC" + const val ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC" /* Artist album sort order year */ - val ALBUM_YEAR_ASC = MediaStore.Audio.Media.YEAR + " ASC" + const val ALBUM_YEAR_ASC = MediaStore.Audio.Media.YEAR + " ASC" } } @@ -169,10 +169,10 @@ class SortOrder { companion object { /* Genre sort order A-Z */ - val GENRE_A_Z = MediaStore.Audio.Genres.DEFAULT_SORT_ORDER + const val GENRE_A_Z = MediaStore.Audio.Genres.DEFAULT_SORT_ORDER /* Genre sort order Z-A */ - val ALBUM_Z_A = "$GENRE_A_Z DESC" + const val ALBUM_Z_A = "$GENRE_A_Z DESC" } } diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/SearchLoader.kt b/app/src/main/java/code/name/monkey/retromusic/loaders/SearchLoader.kt index adbb8599..b36dd4f5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/loaders/SearchLoader.kt +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/SearchLoader.kt @@ -2,18 +2,17 @@ package code.name.monkey.retromusic.loaders import android.content.Context import android.text.TextUtils -import java.util.ArrayList - import code.name.monkey.retromusic.R import io.reactivex.Observable +import java.util.* object SearchLoader { - fun searchAll(context: Context, query: String): Observable> { + fun searchAll(context: Context, query: String?): Observable> { val results = ArrayList() return Observable.create { e -> if (!TextUtils.isEmpty(query)) { - SongLoader.getSongs(context, query) + SongLoader.getSongs(context, query!!) .subscribe { songs -> if (!songs.isEmpty()) { results.add(context.resources.getString(R.string.songs)) diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/SongLoader.kt b/app/src/main/java/code/name/monkey/retromusic/loaders/SongLoader.kt index 9359e339..19365196 100644 --- a/app/src/main/java/code/name/monkey/retromusic/loaders/SongLoader.kt +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/SongLoader.kt @@ -114,7 +114,7 @@ object SongLoader { return newSelectionValues } - fun getSong(cursor: Cursor?): Observable { + private fun getSong(cursor: Cursor?): Observable { return Observable.create { e -> val song: Song = if (cursor != null && cursor.moveToFirst()) { getSongFromCursorImpl(cursor) diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/contract/SearchContract.kt b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/SearchContract.kt index 193b9247..f4aea76c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/mvp/contract/SearchContract.kt +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/contract/SearchContract.kt @@ -2,8 +2,7 @@ package code.name.monkey.retromusic.mvp.contract import code.name.monkey.retromusic.mvp.BasePresenter import code.name.monkey.retromusic.mvp.BaseView - -import java.util.ArrayList +import java.util.* /** @@ -14,6 +13,6 @@ interface SearchContract { interface SearchView : BaseView> interface SearchPresenter : BasePresenter { - fun search(query: String) + fun search(query: String?) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SearchPresenter.kt b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SearchPresenter.kt index 064d858c..85b48e3e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SearchPresenter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SearchPresenter.kt @@ -27,7 +27,7 @@ class SearchPresenter(private val view: SearchContract.SearchView) : Presenter() } } - override fun search(query: String) { + override fun search(query: String?) { disposable.add(repository.search(query) .debounce(500, TimeUnit.MILLISECONDS) .subscribeOn(schedulerProvider.computation()) diff --git a/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.java b/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.java deleted file mode 100644 index d65c7b6b..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.java +++ /dev/null @@ -1,169 +0,0 @@ -package code.name.monkey.retromusic.providers; - -import android.content.Context; - -import java.io.File; -import java.util.ArrayList; - -import code.name.monkey.retromusic.Injection; -import code.name.monkey.retromusic.App; -import code.name.monkey.retromusic.loaders.AlbumLoader; -import code.name.monkey.retromusic.loaders.ArtistLoader; -import code.name.monkey.retromusic.loaders.GenreLoader; -import code.name.monkey.retromusic.loaders.HomeLoader; -import code.name.monkey.retromusic.loaders.LastAddedSongsLoader; -import code.name.monkey.retromusic.loaders.PlaylistLoader; -import code.name.monkey.retromusic.loaders.PlaylistSongsLoader; -import code.name.monkey.retromusic.loaders.SearchLoader; -import code.name.monkey.retromusic.loaders.SongLoader; -import code.name.monkey.retromusic.loaders.TopAndRecentlyPlayedTracksLoader; -import code.name.monkey.retromusic.model.Album; -import code.name.monkey.retromusic.model.Artist; -import code.name.monkey.retromusic.model.Genre; -import code.name.monkey.retromusic.model.Playlist; -import code.name.monkey.retromusic.model.Song; -import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist; -import code.name.monkey.retromusic.providers.interfaces.Repository; -import code.name.monkey.retromusic.rest.model.KuGouRawLyric; -import code.name.monkey.retromusic.rest.model.KuGouSearchLyricResult; -import code.name.monkey.retromusic.rest.service.KuGouApiService; -import code.name.monkey.retromusic.util.LyricUtil; -import io.reactivex.Observable; -import io.reactivex.schedulers.Schedulers; - -public class RepositoryImpl implements Repository { - private static RepositoryImpl INSTANCE; - private Context context; - - public RepositoryImpl(Context context) { - this.context = context; - } - - public static synchronized RepositoryImpl getInstance() { - if (INSTANCE == null) { - INSTANCE = new RepositoryImpl(App.Companion.getInstance()); - } - return INSTANCE; - } - - @Override - public Observable> getAllSongs() { - return SongLoader.INSTANCE.getAllSongs(context); - } - - @Override - public Observable> getSuggestionSongs() { - return SongLoader.INSTANCE.suggestSongs(context); - } - - @Override - public Observable getSong(int id) { - return SongLoader.INSTANCE.getSong(context, id); - } - - @Override - public Observable> getAllAlbums() { - return AlbumLoader.Companion.getAllAlbums(context); - } - - @Override - public Observable> getRecentAlbums() { - return LastAddedSongsLoader.INSTANCE.getLastAddedAlbums(context); - } - - @Override - public Observable> getTopAlbums() { - return TopAndRecentlyPlayedTracksLoader.INSTANCE.getTopAlbums(context); - } - - @Override - public Observable getAlbum(int albumId) { - return AlbumLoader.Companion.getAlbum(context, albumId); - } - - @Override - public Observable> getAllArtists() { - return ArtistLoader.INSTANCE.getAllArtists(context); - } - - @Override - public Observable> getRecentArtists() { - return LastAddedSongsLoader.INSTANCE.getLastAddedArtists(context); - } - - @Override - public Observable> getTopArtists() { - return TopAndRecentlyPlayedTracksLoader.INSTANCE.getTopArtists(context); - } - - @Override - public Observable getArtistById(long artistId) { - return ArtistLoader.INSTANCE.getArtist(context, (int) artistId); - } - - @Override - public Observable> getAllPlaylists() { - return PlaylistLoader.INSTANCE.getAllPlaylists(context); - } - - @Override - public Observable> getFavoriteSongs() { - return null; - } - - @Override - public Observable> search(String query) { - return SearchLoader.INSTANCE.searchAll(context, query); - } - - @Override - public Observable> getPlaylistSongs(Playlist playlist) { - return PlaylistSongsLoader.INSTANCE.getPlaylistSongList(context, playlist); - } - - @Override - public Observable> getHomeList() { - return HomeLoader.INSTANCE.getHomeLoader(context); - } - - @Override - public Observable> getAllThings() { - return HomeLoader.INSTANCE.getRecentAndTopThings(context); - } - - @Override - public Observable> getAllGenres() { - return GenreLoader.INSTANCE.getAllGenres(context); - } - - @Override - public Observable> getGenre(int genreId) { - return GenreLoader.INSTANCE.getSongs(context, genreId); - } - - @Override - public Observable downloadLrcFile(String title, String artist, long duration) { - KuGouApiService service = Injection.INSTANCE.provideKuGouApiService(); - return service.searchLyric(title, String.valueOf(duration)) - .subscribeOn(Schedulers.io()) - .flatMap(kuGouSearchLyricResult -> { - if (kuGouSearchLyricResult.status == 200 - && kuGouSearchLyricResult.candidates != null - && kuGouSearchLyricResult.candidates.size() != 0) { - KuGouSearchLyricResult.Candidates candidates = kuGouSearchLyricResult.candidates.get(0); - return service.getRawLyric(candidates.id, candidates.accesskey); - } else { - return Observable.just(new KuGouRawLyric()); - } - }).map(kuGouRawLyric -> { - if (kuGouRawLyric == null) { - return null; - } - String rawLyric = LyricUtil.decryptBASE64(kuGouRawLyric.content); - if (rawLyric != null && rawLyric.isEmpty()) { - return null; - } - return LyricUtil.writeLrcToLoc(title, artist, rawLyric); - }); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.kt b/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.kt new file mode 100644 index 00000000..e9037ec8 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.kt @@ -0,0 +1,86 @@ +package code.name.monkey.retromusic.providers + +import android.content.Context +import code.name.monkey.retromusic.App +import code.name.monkey.retromusic.loaders.* +import code.name.monkey.retromusic.model.* +import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist +import code.name.monkey.retromusic.providers.interfaces.Repository +import io.reactivex.Observable +import java.util.* + +class RepositoryImpl(private val context: Context) : Repository { + + override val allSongs: Observable> + get() = SongLoader.getAllSongs(context) + + override val suggestionSongs: Observable> + get() = SongLoader.suggestSongs(context) + + override val allAlbums: Observable> + get() = AlbumLoader.getAllAlbums(context) + + override val recentAlbums: Observable> + get() = LastAddedSongsLoader.getLastAddedAlbums(context) + + override val topAlbums: Observable> + get() = TopAndRecentlyPlayedTracksLoader.getTopAlbums(context) + + override val allArtists: Observable> + get() = ArtistLoader.getAllArtists(context) + + override val recentArtists: Observable> + get() = LastAddedSongsLoader.getLastAddedArtists(context) + + override val topArtists: Observable> + get() = TopAndRecentlyPlayedTracksLoader.getTopArtists(context) + + override val allPlaylists: Observable> + get() = PlaylistLoader.getAllPlaylists(context) + + override val homeList: Observable> + get() = HomeLoader.getHomeLoader(context) + + override val allThings: Observable> + get() = HomeLoader.getRecentAndTopThings(context) + + override val allGenres: Observable> + get() = GenreLoader.getAllGenres(context) + + override fun getSong(id: Int): Observable { + return SongLoader.getSong(context, id) + } + + override fun getAlbum(albumId: Int): Observable { + return AlbumLoader.getAlbum(context, albumId) + } + + override fun getArtistById(artistId: Long): Observable { + return ArtistLoader.getArtist(context, artistId.toInt()) + } + + override fun search(query: String?): Observable> { + return SearchLoader.searchAll(context, query) + } + + override fun getPlaylistSongs(playlist: Playlist): Observable> { + return PlaylistSongsLoader.getPlaylistSongList(context, playlist) + } + + override fun getGenre(genreId: Int): Observable> { + return GenreLoader.getSongs(context, genreId) + } + + + companion object { + private var INSTANCE: RepositoryImpl? = null + + val instance: RepositoryImpl + @Synchronized get() { + if (INSTANCE == null) { + INSTANCE = RepositoryImpl(App.instance) + } + return INSTANCE!! + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/providers/interfaces/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/providers/interfaces/Repository.kt index f76a7ca0..58c5f026 100644 --- a/app/src/main/java/code/name/monkey/retromusic/providers/interfaces/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/providers/interfaces/Repository.kt @@ -1,14 +1,9 @@ package code.name.monkey.retromusic.providers.interfaces -import code.name.monkey.retromusic.model.Album -import code.name.monkey.retromusic.model.Artist -import code.name.monkey.retromusic.model.Genre -import code.name.monkey.retromusic.model.Playlist -import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist import io.reactivex.Observable -import java.io.File -import java.util.ArrayList +import java.util.* /** * Created by hemanths on 11/08/17. @@ -34,8 +29,6 @@ interface Repository { val allPlaylists: Observable> - val favoriteSongs: Observable> - val homeList: Observable> val allThings: Observable> @@ -46,15 +39,13 @@ interface Repository { fun getAlbum(albumId: Int): Observable - fun getArtistById(artistId: Long): Observable - fun search(query: String): Observable> + fun search(query: String?): Observable> fun getPlaylistSongs(playlist: Playlist): Observable> fun getGenre(genreId: Int): Observable> - fun downloadLrcFile(title: String, artist: String, duration: Long): Observable } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java index 9cc5fa2a..94e35495 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java +++ b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java @@ -2,6 +2,7 @@ package code.name.monkey.retromusic.service; import android.app.PendingIntent; import android.app.Service; +import android.appwidget.AppWidgetManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -47,6 +48,10 @@ import java.util.Random; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.appwidgets.AppWidgetBig; +import code.name.monkey.retromusic.appwidgets.AppWidgetCard; +import code.name.monkey.retromusic.appwidgets.AppWidgetClassic; +import code.name.monkey.retromusic.appwidgets.AppWidgetSmall; import code.name.monkey.retromusic.glide.BlurTransformation; import code.name.monkey.retromusic.glide.SongGlideRequest; import code.name.monkey.retromusic.helper.ShuffleHelper; @@ -92,12 +97,10 @@ import static code.name.monkey.retromusic.Constants.SHUFFLE_MODE_CHANGED; */ public class MusicService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener, Playback.PlaybackCallbacks { public static final String TAG = MusicService.class.getSimpleName(); - public static final String SAVED_POSITION = "POSITION"; public static final String SAVED_POSITION_IN_TRACK = "POSITION_IN_TRACK"; public static final String SAVED_SHUFFLE_MODE = "SHUFFLE_MODE"; public static final String SAVED_REPEAT_MODE = "REPEAT_MODE"; - public static final int RELEASE_WAKELOCK = 0; public static final int TRACK_ENDED = 1; public static final int TRACK_WENT_TO_NEXT = 2; @@ -122,11 +125,35 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP | PlaybackStateCompat.ACTION_STOP | PlaybackStateCompat.ACTION_SEEK_TO; private final IBinder musicBind = new MusicBinder(); + private AppWidgetBig appWidgetBig = AppWidgetBig.Companion.getInstance(); + private AppWidgetClassic appWidgetClassic = AppWidgetClassic.Companion.getInstance(); + private AppWidgetSmall appWidgetSmall = AppWidgetSmall.Companion.getInstance(); + private AppWidgetCard appWidgetCard = AppWidgetCard.Companion.getInstance(); private final BroadcastReceiver widgetIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { final String command = intent.getStringExtra(EXTRA_APP_WIDGET_NAME); + final int[] ids = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); + switch (command) { + case AppWidgetClassic.NAME: { + appWidgetClassic.performUpdate(MusicService.this, ids); + break; + } + case AppWidgetSmall.NAME: { + appWidgetSmall.performUpdate(MusicService.this, ids); + break; + } + case AppWidgetBig.NAME: { + appWidgetBig.performUpdate(MusicService.this, ids); + break; + } + case AppWidgetCard.NAME: { + appWidgetCard.performUpdate(MusicService.this, ids); + break; + } + } + } }; private Playback playback; @@ -1083,7 +1110,10 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP private void sendChangeInternal(final String what) { sendBroadcast(new Intent(what)); - + appWidgetBig.notifyChange(this, what); + appWidgetClassic.notifyChange(this, what); + appWidgetSmall.notifyChange(this, what); + appWidgetCard.notifyChange(this, what); } private void handleChangeInternal(@NonNull final String what) { diff --git a/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl.kt b/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl.kt index 92f1e333..3ca71102 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl.kt @@ -45,10 +45,8 @@ class PlayingNotificationImpl : PlayingNotification() { val isPlaying = service.isPlaying - val notificationLayout = RemoteViews(service.packageName, - R.layout.notification) - val notificationLayoutBig = RemoteViews(service.packageName, - R.layout.notification_big) + val notificationLayout = RemoteViews(service.packageName, R.layout.notification) + val notificationLayoutBig = RemoteViews(service.packageName, R.layout.notification_big) if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) { notificationLayout.setViewVisibility(R.id.media_titles, View.INVISIBLE) @@ -58,8 +56,7 @@ class PlayingNotificationImpl : PlayingNotification() { notificationLayout.setTextViewText(R.id.text, song.artistName) } - if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName) && TextUtils - .isEmpty(song.albumName)) { + if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName) && TextUtils.isEmpty(song.albumName)) { notificationLayoutBig.setViewVisibility(R.id.media_titles, View.INVISIBLE) } else { notificationLayoutBig.setViewVisibility(R.id.media_titles, View.VISIBLE) diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/LockScreenActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/LockScreenActivity.kt new file mode 100644 index 00000000..eb9574dd --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/LockScreenActivity.kt @@ -0,0 +1,82 @@ +package code.name.monkey.retromusic.ui.activities + +import android.os.Bundle +import android.view.View +import androidx.core.view.ViewCompat +import android.view.WindowManager +import android.widget.ImageView + +import com.bumptech.glide.Glide +import com.r0adkll.slidr.Slidr +import com.r0adkll.slidr.model.SlidrConfig +import com.r0adkll.slidr.model.SlidrPosition + +import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget +import code.name.monkey.retromusic.glide.SongGlideRequest +import code.name.monkey.retromusic.helper.MusicPlayerRemote +import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.ui.activities.base.AbsMusicServiceActivity +import code.name.monkey.retromusic.ui.fragments.player.lockscreen.LockScreenPlayerControlsFragment + +class LockScreenActivity : AbsMusicServiceActivity() { + private var mFragment: LockScreenPlayerControlsFragment? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD + or WindowManager.LayoutParams.FLAG_FULLSCREEN + or WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS + or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED) + + setDrawUnderStatusBar() + setContentView(R.layout.activity_lock_screen_old_style) + + hideStatusBar() + setStatusbarColorAuto() + setNavigationbarColorAuto() + setTaskDescriptionColorAuto() + setLightNavigationBar(true) + + val config = SlidrConfig.Builder() + .position(SlidrPosition.BOTTOM) + .build() + + Slidr.attach(this, config) + + mFragment = supportFragmentManager.findFragmentById(R.id.playback_controls_fragment) as LockScreenPlayerControlsFragment? + + findViewById(R.id.slide).setTranslationY(100f) + findViewById(R.id.slide).setAlpha(0f) + ViewCompat.animate(findViewById(R.id.slide)) + .translationY(0f) + .alpha(1f) + .setDuration(1500) + .start() + + findViewById(R.id.root_layout).setBackgroundColor(ThemeStore.primaryColor(this)) + } + + override fun onPlayingMetaChanged() { + super.onPlayingMetaChanged() + updateSongs() + } + + override fun onServiceConnected() { + super.onServiceConnected() + updateSongs() + } + + private fun updateSongs() { + val song = MusicPlayerRemote.currentSong + SongGlideRequest.Builder.from(Glide.with(this), song) + .checkIgnoreMediaStore(this) + .generatePalette(this) + .build().into(object : RetroMusicColoredTarget(findViewById(R.id.image)) { + override fun onColorReady(color: Int) { + mFragment!!.setDark(color) + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/LyricsActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/LyricsActivity.kt index 5741f080..419798aa 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/LyricsActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/LyricsActivity.kt @@ -1,168 +1,104 @@ package code.name.monkey.retromusic.ui.activities import android.annotation.SuppressLint -import android.content.res.ColorStateList -import android.graphics.Color -import android.graphics.PorterDuff -import android.graphics.drawable.Drawable import android.os.AsyncTask import android.os.Bundle import android.text.InputType import android.text.TextUtils -import android.view.MenuItem -import android.view.View -import android.view.WindowManager -import android.widget.RadioButton +import android.view.* import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentStatePagerAdapter import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.util.TintHelper +import code.name.monkey.retromusic.App import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.glide.RetroMusicColoredTarget -import code.name.monkey.retromusic.glide.SongGlideRequest import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.lyrics.Lyrics import code.name.monkey.retromusic.ui.activities.base.AbsMusicServiceActivity 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 com.bumptech.glide.Glide -import io.reactivex.disposables.CompositeDisposable import kotlinx.android.synthetic.main.activity_lyrics.* +import kotlinx.android.synthetic.main.fragment_lyrics.* +import kotlinx.android.synthetic.main.fragment_synced.* import org.jaudiotagger.tag.FieldKey import java.io.File import java.util.* -class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper.Callback, View.OnClickListener { +class LyricsActivity : AbsMusicServiceActivity(), View.OnClickListener { + override fun onClick(v: View?) { + when (viewPager.currentItem) { + 0 -> showSyncedLyrics() + 1 -> showLyricsSaveDialog() + } + } - private var updateHelper: MusicProgressViewUpdateHelper? = null - private var updateLyricsAsyncTask: AsyncTask<*, *, *>? = null - private var disposable: CompositeDisposable? = null - private var song: Song? = null + private lateinit var song: Song private var lyrics: Lyrics? = null private val googleSearchLrcUrl: String get() { var baseUrl = "http://www.google.com/search?" - var query = song!!.title + "+" + song!!.artistName + var query = song.title + "+" + song.artistName query = "q=" + query.replace(" ", "+") + " .lrc" baseUrl += query return baseUrl } override fun onCreate(savedInstanceState: Bundle?) { - setDrawUnderStatusBar() - //setDrawUnderNavigationBar(); super.onCreate(savedInstanceState) - setContentView(R.layout.activity_lyrics) - + setStatusbarColorAuto() setTaskDescriptionColorAuto() setNavigationbarColorAuto() + setLightStatusbar(true) - container.isFit = !PreferenceUtil.getInstance().fullScreenMode + toolbar.setBackgroundColor(ThemeStore.primaryColor(this)) + toolbar.navigationIcon = TintHelper.createTintedDrawable(ContextCompat.getDrawable(this@LyricsActivity, R.drawable.ic_keyboard_backspace_black_24dp), ThemeStore.textColorSecondary(this@LyricsActivity)) + appBarLayout.setBackgroundColor(ThemeStore.primaryColor(this)) + setSupportActionBar(toolbar) - setSupportActionBar(bottomAppBar) - Objects.requireNonNull(bottomAppBar!!.navigationIcon) - .setColorFilter(ThemeStore.textColorPrimary(this), PorterDuff.Mode.SRC_IN) - bottomAppBar!!.backgroundTint = ColorStateList.valueOf(ThemeStore.primaryColor(this)) TintHelper.setTintAuto(fab, ThemeStore.accentColor(this), true) - - updateHelper = MusicProgressViewUpdateHelper(this, 500, 1000) - - setupLyricsView() setupWakelock() - loadLrcFile() - - actions.setOnCheckedChangeListener { _, checkedId -> selectLyricsTye(checkedId) } - actions.check(PreferenceUtil.getInstance().lastLyricsType) + viewPager.apply { + adapter = PagerAdapter(supportFragmentManager) + } + tabs.apply { + setupWithViewPager(viewPager) + setSelectedTabIndicator(TintHelper.createTintedDrawable(ContextCompat.getDrawable(this@LyricsActivity, R.drawable.tab_indicator), ThemeStore.accentColor(this@LyricsActivity))) + setTabTextColors(ThemeStore.textColorSecondary(this@LyricsActivity), ThemeStore.accentColor(this@LyricsActivity)) + setSelectedTabIndicatorColor(ThemeStore.accentColor(context)) + } fab.setOnClickListener(this) } - private fun selectLyricsTye(group: Int) { - PreferenceUtil.getInstance().lastLyricsType = group - val radioButton = actions.findViewById(group) - if (radioButton != null) { - radioButton.backgroundTintList = ColorStateList.valueOf(Color.WHITE) - //radioButton.setTextColor(ThemeStore.textColorPrimary(this)); - } - - offlineLyrics!!.visibility = View.GONE - lyricsView.visibility = View.GONE - - when (group) { - R.id.syncedLyrics -> { - loadLRCLyrics() - lyricsView!!.visibility = View.VISIBLE - } - R.id.normalLyrics -> { - loadSongLyrics() - offlineLyrics!!.visibility = View.VISIBLE - } - else -> { - loadSongLyrics() - offlineLyrics!!.visibility = View.VISIBLE - } - } - } - - private fun loadLRCLyrics() { - if (LyricUtil.isLrcFileExist(song!!.title, song!!.artistName)) { - showLyricsLocal(LyricUtil.getLocalLyricFile(song!!.title, song!!.artistName)) - } - } - - private fun setupWakelock() { - window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) - } - - private fun setupLyricsView() { - disposable = CompositeDisposable() - - lyricsView!!.apply { - setOnPlayerClickListener { progress, _ -> MusicPlayerRemote.seekTo(progress.toInt()) } - //lyricView.setHighLightTextColor(ThemeStore.accentColor(this)); - setDefaultColor(ContextCompat.getColor(this@LyricsActivity, R.color.md_grey_400)) - //lyricView.setTouchable(false); - setHintColor(Color.WHITE) - } - } - override fun onPlayingMetaChanged() { super.onPlayingMetaChanged() - loadLrcFile() - } - - override fun onResume() { - super.onResume() - updateHelper!!.start() - } - - override fun onPause() { - super.onPause() - updateHelper!!.stop() + song = MusicPlayerRemote.currentSong + toolbar.title = song.title + toolbar.subtitle = song.artistName } override fun onServiceConnected() { super.onServiceConnected() - loadLrcFile() + song = MusicPlayerRemote.currentSong + toolbar.title = song.title + toolbar.subtitle = song.artistName } - override fun onDestroy() { - super.onDestroy() - disposable!!.clear() - - if (updateLyricsAsyncTask != null && !updateLyricsAsyncTask!!.isCancelled) { - updateLyricsAsyncTask!!.cancel(true) - } + private fun setupWakelock() { + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } override fun onOptionsItemSelected(item: MenuItem): Boolean { @@ -172,84 +108,10 @@ class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper. return super.onOptionsItemSelected(item) } - override fun onUpdateProgressViews(progress: Int, total: Int) { - lyricsView!!.setCurrentTimeMillis(progress.toLong()) - } - - private fun loadLrcFile() { - song = MusicPlayerRemote.currentSong - bottomAppBar.title = song!!.title - bottomAppBar.subtitle = song!!.artistName - SongGlideRequest.Builder.from(Glide.with(this), song!!) - .checkIgnoreMediaStore(this) - .generatePalette(this) - .build() - .into(object : RetroMusicColoredTarget(findViewById(R.id.image)) { - override fun onColorReady(color: Int) { - if (PreferenceUtil.getInstance().adaptiveColor) { - //background.setBackgroundColor(color); - } - } - }) - } - - private fun showLyricsLocal(file: File?) { - if (file == null) { - lyricsView!!.reset() - } else { - lyricsView!!.setLyricFile(file, "UTF-8") - } - } - - override fun onClick(view: View) { - when (view.id) { - android.R.id.home -> onBackPressed() - R.id.fab -> when (actions.checkedRadioButtonId) { - R.id.syncedLyrics -> showSyncedLyrics() - R.id.normalLyrics -> showLyricsSaveDialog() - } - } - } - - @SuppressLint("StaticFieldLeak") - private fun loadSongLyrics() { - if (updateLyricsAsyncTask != null) { - updateLyricsAsyncTask!!.cancel(false) - } - val song = MusicPlayerRemote.currentSong - updateLyricsAsyncTask = object : AsyncTask() { - 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 - } - offlineLyrics!!.text = l.data - } - - override fun onCancelled(s: Lyrics) { - onPostExecute(null) - } - }.execute() - } - private fun showSyncedLyrics() { var content = "" try { - content = LyricUtil.getStringFromFile(song!!.title, song!!.artistName) + content = LyricUtil.getStringFromFile(song.title, song.artistName) } catch (e: Exception) { e.printStackTrace() } @@ -260,14 +122,12 @@ class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper. .content("Add time frame lyrics") .negativeText("Delete") .onNegative { _, _ -> - LyricUtil.deleteLrcFile(song!!.title, song!!.artistName) - loadLrcFile() + LyricUtil.deleteLrcFile(song.title, song.artistName) } .onNeutral { _, _ -> RetroUtil.openUrl(this@LyricsActivity, googleSearchLrcUrl) } .inputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE) .input("Paste lyrics here", content) { _, input -> - LyricUtil.writeLrcToLoc(song!!.title, song!!.artistName, input.toString()) - loadLrcFile() + LyricUtil.writeLrcToLoc(song.title, song.artistName, input.toString()) }.show() } @@ -280,13 +140,12 @@ class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper. MaterialDialog.Builder(this) .title("Add lyrics") .neutralText("Search") - .onNeutral { _, _ -> RetroUtil.openUrl(this@LyricsActivity, getGoogleSearchUrl(song!!.title, song!!.artistName)) } + .onNeutral { _, _ -> RetroUtil.openUrl(this@LyricsActivity, getGoogleSearchUrl(song.title, song.artistName)) } .inputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE) .input("Paste lyrics here", content) { _, input -> val fieldKeyValueMap = EnumMap(FieldKey::class.java) fieldKeyValueMap[FieldKey.LYRICS] = input.toString() - WriteTagsAsyncTask(this@LyricsActivity).execute(WriteTagsAsyncTask.LoadingInfo(getSongPaths(song!!), fieldKeyValueMap, null)) - loadLrcFile() + WriteTagsAsyncTask(this@LyricsActivity).execute(WriteTagsAsyncTask.LoadingInfo(getSongPaths(song), fieldKeyValueMap, null)) } .show() } @@ -305,3 +164,154 @@ class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper. return baseUrl } } + +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() { + 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 + } + 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 onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + loadSongLyrics() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_lyrics, container, false) + } +} + +class SyncedLyricsFragment : AbsMusicServiceFragment(), MusicProgressViewUpdateHelper.Callback { + + 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 onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + updateHelper = MusicProgressViewUpdateHelper(this, 500, 1000) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupLyricsView() + } + + 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 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") + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/MainActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/MainActivity.kt index 9378b030..a26973be 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/MainActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/MainActivity.kt @@ -11,6 +11,7 @@ import android.util.Log import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.core.app.ActivityCompat import androidx.core.app.ShareCompat import androidx.fragment.app.Fragment import code.name.monkey.appthemehelper.ThemeStore @@ -49,10 +50,10 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP val action = intent.action if (action != null && action == Intent.ACTION_SCREEN_OFF) { if (PreferenceUtil.getInstance().lockScreen && MusicPlayerRemote.isPlaying) { - /*Intent activity = new Intent(context, LockScreenActivity.class); - activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - activity.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - ActivityCompat.startActivity(context, activity, null);*/ + val activity = Intent(context, LockScreenActivity::class.java) + activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + activity.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY) + ActivityCompat.startActivity(context, activity, null) } } } @@ -210,8 +211,14 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP if (!hasPermissions()) { requestPermissions() } + checkSetUpPro(); // good chance that pro version check was delayed on first start } REQUEST_CODE_THEME, APP_USER_INFO_REQUEST -> postRecreate() + PURCHASE_REQUEST -> { + if (resultCode == RESULT_OK) { + checkSetUpPro(); + } + } } } @@ -369,10 +376,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP return super.onOptionsItemSelected(item) } - private fun updateNavigationDrawerHeader() { - - } - companion object { const val APP_INTRO_REQUEST = 2323 const val LIBRARY = 1 diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlayingQueueActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlayingQueueActivity.kt index ec549e2c..c4b66f96 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlayingQueueActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlayingQueueActivity.kt @@ -21,7 +21,7 @@ class PlayingQueueActivity : AbsMusicServiceActivity() { private var wrappedAdapter: RecyclerView.Adapter<*>? = null private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null private var playingQueueAdapter: PlayingQueueAdapter? = null - private lateinit var layoutManager: LinearLayoutManager + private lateinit var linearLayoutManager: LinearLayoutManager private val upNextAndQueueTime: String get() = resources.getString(R.string.up_next) + " • " + MusicUtil.getReadableDurationString(MusicPlayerRemote.getQueueDurationMillis(MusicPlayerRemote.position)) @@ -54,16 +54,16 @@ class PlayingQueueActivity : AbsMusicServiceActivity() { R.layout.item_queue) wrappedAdapter = recyclerViewDragDropManager!!.createWrappedAdapter(playingQueueAdapter!!) - layoutManager = LinearLayoutManager(this) + linearLayoutManager = LinearLayoutManager(this) recyclerView.apply { - layoutManager = layoutManager + layoutManager = linearLayoutManager adapter = wrappedAdapter itemAnimator = animator recyclerViewDragDropManager!!.attachRecyclerView(this) } - layoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0) + linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0) recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { @@ -109,7 +109,7 @@ class PlayingQueueActivity : AbsMusicServiceActivity() { private fun resetToCurrentPosition() { recyclerView.stopScroll() - layoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0) + linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0) } override fun onPause() { diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/ProVersionActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/ProVersionActivity.kt index 4dd03b97..a567e856 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/ProVersionActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/ProVersionActivity.kt @@ -78,14 +78,13 @@ class ProVersionActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler { override fun onProductPurchased(productId: String, details: TransactionDetails?) { Toast.makeText(this, R.string.thank_you, Toast.LENGTH_SHORT).show() - setResult(Activity.RESULT_OK) + setResult(RESULT_OK) } override fun onPurchaseHistoryRestored() { if (App.isProVersion) { - Toast.makeText(this, R.string.restored_previous_purchase_please_restart, Toast.LENGTH_LONG) - .show() - setResult(Activity.RESULT_OK) + Toast.makeText(this, R.string.restored_previous_purchase_please_restart, Toast.LENGTH_LONG).show() + setResult(RESULT_OK) } else { Toast.makeText(this, R.string.no_purchase_found, Toast.LENGTH_SHORT).show() } @@ -161,7 +160,6 @@ class ProVersionActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler { } companion object { - - private val TAG: String = "ProVersionActivity" + private const val TAG: String = "ProVersionActivity" } } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/SearchActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/SearchActivity.kt index 31a80aef..4b3837be 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/SearchActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/SearchActivity.kt @@ -55,7 +55,7 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, SearchCon if (intent.getBooleanExtra("mic_search", false)) { startMicSearch() } - + back.setOnClickListener { onBackPressed() } voiceSearch.setOnClickListener { startMicSearch() } } @@ -83,7 +83,7 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, SearchCon override fun onResume() { super.onResume() searchPresenter!!.subscribe() - searchPresenter!!.search(query!!) + searchPresenter!!.search(query) } override fun onDestroy() { diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/SettingsActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/SettingsActivity.kt index 6a480286..cdc2d0a4 100755 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/SettingsActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/SettingsActivity.kt @@ -9,7 +9,9 @@ import androidx.fragment.app.Fragment 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.R +import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager import code.name.monkey.retromusic.ui.activities.base.AbsBaseActivity import code.name.monkey.retromusic.ui.fragments.settings.MainSettingsFragment import code.name.monkey.retromusic.util.PreferenceUtil @@ -32,6 +34,8 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback, Sh } R.string.accent_color -> ThemeStore.editTheme(this).accentColor(selectedColor).commit() } + if (VersionUtils.hasNougatMR()) + DynamicShortcutManager(this).updateDynamicShortcuts() recreate() } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/UserInfoActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/UserInfoActivity.kt index 182e4c23..7a27ef17 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/UserInfoActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/UserInfoActivity.kt @@ -12,6 +12,7 @@ import android.text.TextUtils import android.view.MenuItem import android.widget.Toast import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.Constants.USER_BANNER import code.name.monkey.retromusic.Constants.USER_PROFILE @@ -32,13 +33,11 @@ import java.util.* class UserInfoActivity : AbsBaseActivity() { - private var disposable: CompositeDisposable? = null + private var disposable = CompositeDisposable() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_user_info) - - setStatusbarColorAuto() setNavigationbarColorAuto() setTaskDescriptionColorAuto() @@ -46,8 +45,6 @@ class UserInfoActivity : AbsBaseActivity() { setupToolbar() - disposable = CompositeDisposable() - bannerTitle.setTextColor(ThemeStore.textColorPrimary(this)) nameContainer.boxStrokeColor = ThemeStore.accentColor(this) name!!.setText(PreferenceUtil.getInstance().userName) @@ -58,7 +55,7 @@ class UserInfoActivity : AbsBaseActivity() { if (!PreferenceUtil.getInstance().bannerImage.isEmpty()) { loadBannerFromStorage(PreferenceUtil.getInstance().bannerImage) } - bannerImage.setOnClickListener { + userImage.setOnClickListener { MaterialDialog.Builder(this) .title("Set a profile photo") .items(Arrays.asList(getString(R.string.new_profile_photo), getString(R.string.remove_profile_photo))) @@ -82,6 +79,7 @@ class UserInfoActivity : AbsBaseActivity() { setResult(Activity.RESULT_OK) finish() } + TintHelper.setTintAuto(next, ThemeStore.accentColor(this), true) } override fun onOptionsItemSelected(item: MenuItem): Boolean { @@ -96,11 +94,11 @@ class UserInfoActivity : AbsBaseActivity() { toolbar.apply { setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp) setBackgroundColor(primaryColor) + ToolbarContentTintHelper.colorBackButton(this, ThemeStore.accentColor(this@UserInfoActivity)) + setSupportActionBar(this) } appBarLayout.setBackgroundColor(primaryColor) - ToolbarContentTintHelper.colorBackButton(toolbar, ThemeStore.accentColor(this)) title = null - setSupportActionBar(toolbar) } private fun showBannerOptions() { @@ -226,8 +224,8 @@ class UserInfoActivity : AbsBaseActivity() { companion object { - private val PICK_IMAGE_REQUEST = 9002 - private val PICK_BANNER_REQUEST = 9003 - private val PROFILE_ICON_SIZE = 400 + private const val PICK_IMAGE_REQUEST = 9002 + private const val PICK_BANNER_REQUEST = 9003 + private const val PROFILE_ICON_SIZE = 400 } } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/WhatsNewActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/WhatsNewActivity.java new file mode 100644 index 00000000..53e8f9af --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/WhatsNewActivity.java @@ -0,0 +1,94 @@ +package code.name.monkey.retromusic.ui.activities; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.webkit.WebView; +import android.widget.TextView; + +import com.afollestad.materialdialogs.internal.ThemeSingleton; +import com.google.android.material.appbar.AppBarLayout; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; + +import androidx.annotation.NonNull; +import androidx.appcompat.widget.Toolbar; +import code.name.monkey.appthemehelper.ThemeStore; +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.ui.activities.base.AbsBaseActivity; +import code.name.monkey.retromusic.util.PreferenceUtil; + +public class WhatsNewActivity extends AbsBaseActivity { + WebView webView; + TextView title; + Toolbar toolbar; + AppBarLayout appBarLayout; + + + private static void setChangelogRead(@NonNull Context context) { + try { + PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); + int currentVersion = pInfo.versionCode; + PreferenceUtil.getInstance().setLastChangeLogVersion(currentVersion); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + } + + private static String colorToHex(int color) { + return Integer.toHexString(color).substring(2); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_whats_new); + + webView = findViewById(R.id.webView); + title = findViewById(R.id.bannerTitle); + toolbar = findViewById(R.id.toolbar); + appBarLayout= findViewById(R.id.appBarLayout); + + + setStatusbarColorAuto(); + setNavigationbarColorAuto(); + setTaskDescriptionColorAuto(); + + toolbar.setBackgroundColor(ThemeStore.primaryColor(this)); + appBarLayout.setBackgroundColor(ThemeStore.primaryColor(this)); + setSupportActionBar(toolbar); + setTitle(null); + toolbar.setNavigationOnClickListener(v -> onBackPressed()); + title.setTextColor(ThemeStore.textColorPrimary(this)); + ToolbarContentTintHelper.colorBackButton(toolbar, ThemeStore.accentColor(this)); + + try { + // Load from phonograph-changelog.html in the assets folder + StringBuilder buf = new StringBuilder(); + InputStream json = getAssets().open("retro-changelog.html"); + BufferedReader in = new BufferedReader(new InputStreamReader(json, "UTF-8")); + String str; + while ((str = in.readLine()) != null) + buf.append(str); + in.close(); + + // Inject color values for WebView body background and links + final String backgroundColor = colorToHex(ThemeStore.primaryColor(this)); + final String contentColor = ThemeSingleton.get().darkTheme ? "#ffffff" : "#000000"; + webView.loadData(buf.toString() + .replace("{style-placeholder}", + String.format("body { background-color: %s; color: %s; }", backgroundColor, contentColor)) + .replace("{link-color}", colorToHex(ThemeSingleton.get().positiveColor.getDefaultColor())) + .replace("{link-color-active}", colorToHex(ColorUtil.lightenColor(ThemeSingleton.get().positiveColor.getDefaultColor()))) + , "text/html", "UTF-8"); + } catch (Throwable e) { + webView.loadData("

Unable to load

" + e.getLocalizedMessage() + "

", "text/html", "UTF-8"); + } + setChangelogRead(this); + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/WhatsNewActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/WhatsNewActivity.kt deleted file mode 100644 index 58f1d66a..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/WhatsNewActivity.kt +++ /dev/null @@ -1,74 +0,0 @@ -package code.name.monkey.retromusic.ui.activities - -import android.content.Context -import android.content.pm.PackageManager -import android.os.Bundle -import code.name.monkey.appthemehelper.ThemeStore -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.ui.activities.base.AbsBaseActivity -import code.name.monkey.retromusic.util.PreferenceUtil -import com.afollestad.materialdialogs.internal.ThemeSingleton -import kotlinx.android.synthetic.main.activity_whats_new.* -import java.io.BufferedReader -import java.io.InputStreamReader - -class WhatsNewActivity : AbsBaseActivity() { - - - private fun setChangelogRead(context: Context) { - try { - val pInfo = context.packageManager.getPackageInfo(context.packageName, 0) - val currentVersion = pInfo.versionCode - PreferenceUtil.getInstance().setLastChangeLogVersion(currentVersion) - } catch (e: PackageManager.NameNotFoundException) { - e.printStackTrace() - } - - } - - private fun colorToHex(color: Int): String { - return Integer.toHexString(color).substring(2) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_whats_new) - - - setStatusbarColorAuto() - setNavigationbarColorAuto() - setTaskDescriptionColorAuto() - - toolbar.setBackgroundColor(ThemeStore.primaryColor(this)) - appBarLayout.setBackgroundColor(ThemeStore.primaryColor(this)) - setSupportActionBar(toolbar) - title = null - toolbar.setNavigationOnClickListener { onBackPressed() } - whatNewtitle.setTextColor(ThemeStore.textColorPrimary(this)) - ToolbarContentTintHelper.colorBackButton(toolbar, ThemeStore.accentColor(this)) - - try { - val buf = StringBuilder() - val json = assets.open("retro-changelog.html") - val inputStream = BufferedReader(InputStreamReader(json, "UTF-8")) - while (inputStream.readLine() != null) { - buf.append(inputStream.readLine()) - } - inputStream.close() - // Inject color values for WebView body background and links - val backgroundColor = colorToHex(ThemeStore.primaryColor(this)) - val contentColor = if (ThemeSingleton.get().darkTheme) "#ffffff" else "#000000" - webView.loadData(buf.toString() - .replace("{style-placeholder}", - String.format("body { background-color: %s; color: %s; }", backgroundColor, contentColor)) - .replace("{link-color}", colorToHex(ThemeSingleton.get().positiveColor.defaultColor)) - .replace("{link-color-active}", colorToHex(ColorUtil.lightenColor(ThemeSingleton.get().positiveColor.defaultColor))), "text/html", "UTF-8") - } catch (e: Throwable) { - webView.loadData("

Unable to load

" + e.localizedMessage + "

", "text/html", "UTF-8") - } - - setChangelogRead(this) - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsSlidingMusicPanelActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsSlidingMusicPanelActivity.kt index 8e0b14fa..93279a4c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsSlidingMusicPanelActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsSlidingMusicPanelActivity.kt @@ -10,6 +10,7 @@ import android.view.ViewTreeObserver import androidx.annotation.FloatRange import androidx.annotation.LayoutRes import androidx.fragment.app.Fragment +import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.retromusic.R import code.name.monkey.retromusic.helper.MusicPlayerRemote @@ -28,6 +29,7 @@ import code.name.monkey.retromusic.ui.fragments.player.material.MaterialFragment import code.name.monkey.retromusic.ui.fragments.player.normal.PlayerFragment 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.ColorUtils import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.views.BottomNavigationBarTinted import com.google.android.material.bottomnavigation.BottomNavigationView @@ -268,6 +270,13 @@ abstract class AbsSlidingMusicPanelActivity protected constructor() : AbsMusicSe currentNowPlayingScreen == NowPlayingScreen.BLUR || currentNowPlayingScreen == NowPlayingScreen.BLUR_CARD) { super.setLightStatusbar(false) super.setLightNavigationBar(true) + } else if (currentNowPlayingScreen == NowPlayingScreen.COLOR) { + super.setNavigationbarColor(paletteColor) + super.setLightNavigationBar(isColorLight) + super.setLightStatusbar(isColorLight) + } else { + super.setLightStatusbar(ColorUtil.isColorLight(ThemeStore.primaryColor(this))) + super.setLightNavigationBar(true) } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/base/MediaEntryViewHolder.kt b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/base/MediaEntryViewHolder.kt index bac037a1..9c6d6690 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/base/MediaEntryViewHolder.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/base/MediaEntryViewHolder.kt @@ -59,7 +59,7 @@ open class MediaEntryViewHolder(w: View) : RecyclerView.ViewHolder(w), View.OnCl recyclerView = w.findViewById(R.id.recycler_view) mask = w.findViewById(R.id.mask) - playSongs = w.findViewById(R.id.play_songs) + playSongs = w.findViewById(R.id.playSongs) w.setOnClickListener(this) w.setOnLongClickListener(this) diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/SongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/SongAdapter.kt index ee15f1be..a88b6338 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/SongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/SongAdapter.kt @@ -177,17 +177,19 @@ open class SongAdapter @JvmOverloads constructor(protected val activity: AppComp init { setImageTransitionName(activity.getString(R.string.transition_album_art)) - menu!!.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) { - override val song: Song - get() = this@ViewHolder.song + if (menu != null) { + menu!!.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) { + override val song: Song + get() = this@ViewHolder.song - override val menuRes: Int - get() = songMenuRes + override val menuRes: Int + get() = songMenuRes - override fun onMenuItemClick(item: MenuItem): Boolean { - return onSongMenuItemClick(item) || super.onMenuItemClick(item) - } - }) + override fun onMenuItemClick(item: MenuItem): Boolean { + return onSongMenuItemClick(item) || super.onMenuItemClick(item) + } + }) + } } protected open fun onSongMenuItemClick(item: MenuItem): Boolean { diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/NowPlayingScreen.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/NowPlayingScreen.kt index 49497b4f..f933a2d7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/NowPlayingScreen.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/NowPlayingScreen.kt @@ -9,17 +9,18 @@ enum class NowPlayingScreen constructor(@param:StringRes @field:StringRes val titleRes: Int, @param:DrawableRes @field:DrawableRes val drawableResId: Int, val id: Int) { - NORMAL(R.string.normal, R.drawable.np_normal, 0), + ADAPTIVE(R.string.adaptive, R.drawable.np_adaptive, 10), + BLUR(R.string.blur, R.drawable.np_blur, 4), + BLUR_CARD(R.string.blur_card, R.drawable.np_blur_card, 9), + CARD(R.string.card, R.drawable.np_card, 6), + COLOR(R.string.color, R.drawable.np_color, 5), + FIT(R.string.fit, R.drawable.np_adaptive, 12), FLAT(R.string.flat, R.drawable.np_flat, 1), FULL(R.string.full, R.drawable.np_full, 2), - PLAIN(R.string.plain, R.drawable.np_plain, 3), - BLUR(R.string.blur, R.drawable.np_blur, 4), - COLOR(R.string.color, R.drawable.np_color, 5), - CARD(R.string.card, R.drawable.np_card, 6), - //TINY(R.string.tiny, R.drawable.np_tiny, 7), - SIMPLE(R.string.simple, R.drawable.np_simple, 8), - BLUR_CARD(R.string.blur_card, R.drawable.np_blur_card, 9), - ADAPTIVE(R.string.adaptive, R.drawable.np_adaptive, 10), MATERIAL(R.string.material, R.drawable.np_material, 11), - FIT(R.string.fit, R.drawable.np_adaptive, 12) + NORMAL(R.string.normal, R.drawable.np_normal, 0), + PLAIN(R.string.plain, R.drawable.np_plain, 3), + //TINY(R.string.tiny, R.drawable.np_tiny, 7), + SIMPLE(R.string.simple, R.drawable.np_simple, 8) + } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerFragment.kt index b5b5123d..f7949319 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerFragment.kt @@ -1,7 +1,6 @@ package code.name.monkey.retromusic.ui.fragments.base import android.os.Bundle - import code.name.monkey.retromusic.ui.fragments.mainactivity.LibraryFragment open class AbsLibraryPagerFragment : AbsMusicServiceFragment() { diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerRecyclerViewCustomGridSizeFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerRecyclerViewCustomGridSizeFragment.kt index e2c8ad05..35343204 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerRecyclerViewCustomGridSizeFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsLibraryPagerRecyclerViewCustomGridSizeFragment.kt @@ -41,15 +41,15 @@ abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment + getMainActivity().setLightStatusbar(!ATHUtil.isWindowBackgroundDark(getContext()))); + getMainActivity().setTitle(null); + getMainActivity().setSupportActionBar(toolbar); + } + + private Fragment getCurrentFragment() { + if (fragmentManager == null) { + return SongsFragment.Companion.newInstance(); + } + return fragmentManager.findFragmentByTag(LibraryFragment.TAG); + } + + @Override + public boolean handleBackPress() { + if (cab != null && cab.isActive()) { + cab.finish(); + return true; + } + return false; + } + + private void selectedFragment(Fragment fragment) { + fragmentManager = getChildFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + + fragmentTransaction + .replace(R.id.fragmentContainer, fragment, TAG) + .commit(); + } + + @NonNull + @Override + public MaterialCab openCab(int menuRes, MaterialCab.Callback callback) { + if (cab != null && cab.isActive()) { + cab.finish(); + } + //noinspection ConstantConditions + cab = new MaterialCab(getMainActivity(), R.id.cab_stub) + .setMenu(menuRes) + .setCloseDrawableRes(R.drawable.ic_close_white_24dp) + .setBackgroundColor( + RetroColorUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor(getActivity()))) + .start(callback); + return cab; + } + + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.menu_main, menu); + + Fragment currentFragment = getCurrentFragment(); + if (currentFragment instanceof AbsLibraryPagerRecyclerViewCustomGridSizeFragment + && currentFragment.isAdded()) { + AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment = (AbsLibraryPagerRecyclerViewCustomGridSizeFragment) currentFragment; + + MenuItem gridSizeItem = menu.findItem(R.id.action_grid_size); + if (RetroUtil.isLandscape()) { + gridSizeItem.setTitle(R.string.action_grid_size_land); + } + setUpGridSizeMenu(fragment, gridSizeItem.getSubMenu()); + + setUpSortOrderMenu(fragment, menu.findItem(R.id.action_sort_order).getSubMenu()); + + } else { + menu.add(0, R.id.action_new_playlist, 0, R.string.new_playlist_title); + menu.removeItem(R.id.action_grid_size); + } + Activity activity = getActivity(); + if (activity == null) { + return; + } + ToolbarContentTintHelper.handleOnCreateOptionsMenu(getActivity(), toolbar, menu, ATHToolbarActivity.getToolbarBackgroundColor(toolbar)); + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + Activity activity = getActivity(); + if (activity == null) { + return; + } + ToolbarContentTintHelper.handleOnPrepareOptionsMenu(activity, toolbar); + } + + + private void setUpSortOrderMenu( + @NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment, + @NonNull SubMenu sortOrderMenu) { + String currentSortOrder = fragment.getSortOrder(); + sortOrderMenu.clear(); + + if (fragment instanceof AlbumsFragment) { + sortOrderMenu.add(0, R.id.action_album_sort_order_asc, 0, R.string.sort_order_a_z) + .setChecked(currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_A_Z)); + sortOrderMenu.add(0, R.id.action_album_sort_order_desc, 1, R.string.sort_order_z_a) + .setChecked(currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_Z_A)); + sortOrderMenu.add(0, R.id.action_album_sort_order_artist, 2, R.string.sort_order_artist) + .setChecked(currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_ARTIST)); + sortOrderMenu.add(0, R.id.action_album_sort_order_year, 3, R.string.sort_order_year) + .setChecked(currentSortOrder.equals(SortOrder.AlbumSortOrder.ALBUM_YEAR)); + } else if (fragment instanceof ArtistsFragment) { + sortOrderMenu.add(0, R.id.action_artist_sort_order_asc, 0, R.string.sort_order_a_z) + .setChecked(currentSortOrder.equals(SortOrder.ArtistSortOrder.ARTIST_A_Z)); + sortOrderMenu.add(0, R.id.action_artist_sort_order_desc, 1, R.string.sort_order_z_a) + .setChecked(currentSortOrder.equals(SortOrder.ArtistSortOrder.ARTIST_Z_A)); + } else if (fragment instanceof SongsFragment) { + sortOrderMenu.add(0, R.id.action_song_sort_order_asc, 0, R.string.sort_order_a_z) + .setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_A_Z)); + sortOrderMenu.add(0, R.id.action_song_sort_order_desc, 1, R.string.sort_order_z_a) + .setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_Z_A)); + sortOrderMenu.add(0, R.id.action_song_sort_order_artist, 2, R.string.sort_order_artist) + .setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_ARTIST)); + sortOrderMenu.add(0, R.id.action_song_sort_order_album, 3, R.string.sort_order_album) + .setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_ALBUM)); + sortOrderMenu.add(0, R.id.action_song_sort_order_year, 4, R.string.sort_order_year) + .setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_YEAR)); + sortOrderMenu.add(0, R.id.action_song_sort_order_date, 4, R.string.sort_order_date) + .setChecked(currentSortOrder.equals(SortOrder.SongSortOrder.SONG_DATE)); + + } + + sortOrderMenu.setGroupCheckable(0, true, true); + } + + private boolean handleSortOrderMenuItem( + @NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment + fragment, @NonNull MenuItem item) { + String sortOrder = null; + if (fragment instanceof AlbumsFragment) { + switch (item.getItemId()) { + case R.id.action_album_sort_order_asc: + sortOrder = SortOrder.AlbumSortOrder.ALBUM_A_Z; + break; + case R.id.action_album_sort_order_desc: + sortOrder = SortOrder.AlbumSortOrder.ALBUM_Z_A; + break; + case R.id.action_album_sort_order_artist: + sortOrder = SortOrder.AlbumSortOrder.ALBUM_ARTIST; + break; + case R.id.action_album_sort_order_year: + sortOrder = SortOrder.AlbumSortOrder.ALBUM_YEAR; + break; + } + } else if (fragment instanceof ArtistsFragment) { + switch (item.getItemId()) { + case R.id.action_artist_sort_order_asc: + sortOrder = SortOrder.ArtistSortOrder.ARTIST_A_Z; + break; + case R.id.action_artist_sort_order_desc: + sortOrder = SortOrder.ArtistSortOrder.ARTIST_Z_A; + break; + } + } else if (fragment instanceof SongsFragment) { + switch (item.getItemId()) { + case R.id.action_song_sort_order_asc: + sortOrder = SortOrder.SongSortOrder.SONG_A_Z; + break; + case R.id.action_song_sort_order_desc: + sortOrder = SortOrder.SongSortOrder.SONG_Z_A; + break; + case R.id.action_song_sort_order_artist: + sortOrder = SortOrder.SongSortOrder.SONG_ARTIST; + break; + case R.id.action_song_sort_order_album: + sortOrder = SortOrder.SongSortOrder.SONG_ALBUM; + break; + case R.id.action_song_sort_order_year: + sortOrder = SortOrder.SongSortOrder.SONG_YEAR; + break; + case R.id.action_song_sort_order_date: + sortOrder = SortOrder.SongSortOrder.SONG_DATE; + break; + + } + } + + if (sortOrder != null) { + item.setChecked(true); + fragment.setAndSaveSortOrder(sortOrder); + return true; + } + + return false; + } + + + @SuppressWarnings("ConstantConditions") + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + //if (pager == null) return false; + Fragment currentFragment = getCurrentFragment(); + if (currentFragment instanceof AbsLibraryPagerRecyclerViewCustomGridSizeFragment) { + AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment = (AbsLibraryPagerRecyclerViewCustomGridSizeFragment) currentFragment; + if (handleGridSizeMenuItem(fragment, item)) { + return true; + } + if (handleSortOrderMenuItem(fragment, item)) { + return true; + } + } + int id = item.getItemId(); + switch (id) { + case R.id.action_new_playlist: + CreatePlaylistDialog.Companion.create().show(getChildFragmentManager(), "CREATE_PLAYLIST"); + return true; + case R.id.action_shuffle_all: + MusicPlayerRemote.INSTANCE.openAndShuffleQueue(SongLoader.INSTANCE.getAllSongs(getContext()) + .blockingFirst(), true); + return true; + case R.id.action_search: + NavigationUtil.goToSearch(getMainActivity()); + break; + case R.id.action_equalizer: + NavigationUtil.openEqualizer(getActivity()); + return true; + case R.id.action_sleep_timer: + if (getFragmentManager() != null) { + new SleepTimerDialog().show(getFragmentManager(), TAG); + } + return true; + case R.id.action_settings: + startActivity(new Intent(getContext(), SettingsActivity.class)); + break; + } + return super.onOptionsItemSelected(item); + } + + + private void setUpGridSizeMenu( + @NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment, + @NonNull SubMenu gridSizeMenu) { + switch (fragment.getGridSize()) { + case 1: + gridSizeMenu.findItem(R.id.action_grid_size_1).setChecked(true); + break; + case 2: + gridSizeMenu.findItem(R.id.action_grid_size_2).setChecked(true); + break; + case 3: + gridSizeMenu.findItem(R.id.action_grid_size_3).setChecked(true); + break; + case 4: + gridSizeMenu.findItem(R.id.action_grid_size_4).setChecked(true); + break; + case 5: + gridSizeMenu.findItem(R.id.action_grid_size_5).setChecked(true); + break; + case 6: + gridSizeMenu.findItem(R.id.action_grid_size_6).setChecked(true); + break; + case 7: + gridSizeMenu.findItem(R.id.action_grid_size_7).setChecked(true); + break; + case 8: + gridSizeMenu.findItem(R.id.action_grid_size_8).setChecked(true); + break; + } + int maxGridSize = fragment.getMaxGridSize(); + if (maxGridSize < 8) { + gridSizeMenu.findItem(R.id.action_grid_size_8).setVisible(false); + } + if (maxGridSize < 7) { + gridSizeMenu.findItem(R.id.action_grid_size_7).setVisible(false); + } + if (maxGridSize < 6) { + gridSizeMenu.findItem(R.id.action_grid_size_6).setVisible(false); + } + if (maxGridSize < 5) { + gridSizeMenu.findItem(R.id.action_grid_size_5).setVisible(false); + } + if (maxGridSize < 4) { + gridSizeMenu.findItem(R.id.action_grid_size_4).setVisible(false); + } + if (maxGridSize < 3) { + gridSizeMenu.findItem(R.id.action_grid_size_3).setVisible(false); + } + } + + + private boolean handleGridSizeMenuItem( + @NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment + fragment, @NonNull MenuItem item) { + int gridSize = 0; + switch (item.getItemId()) { + case R.id.action_grid_size_1: + gridSize = 1; + break; + case R.id.action_grid_size_2: + gridSize = 2; + break; + case R.id.action_grid_size_3: + gridSize = 3; + break; + case R.id.action_grid_size_4: + gridSize = 4; + break; + case R.id.action_grid_size_5: + gridSize = 5; + break; + case R.id.action_grid_size_6: + gridSize = 6; + break; + case R.id.action_grid_size_7: + gridSize = 7; + break; + case R.id.action_grid_size_8: + gridSize = 8; + break; + } + + if (gridSize > 0) { + item.setChecked(true); + fragment.setAndSaveGridSize(gridSize); + return true; + } + return false; + } + + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/LibraryFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/LibraryFragment.kt deleted file mode 100644 index 267ebb5d..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/LibraryFragment.kt +++ /dev/null @@ -1,364 +0,0 @@ -package code.name.monkey.retromusic.ui.fragments.mainactivity - -import android.content.Intent -import android.os.Bundle -import android.view.* -import android.widget.TextView -import androidx.annotation.StringRes -import androidx.appcompat.widget.Toolbar -import androidx.fragment.app.Fragment -import code.name.monkey.appthemehelper.ThemeStore -import code.name.monkey.appthemehelper.common.ATHToolbarActivity -import code.name.monkey.appthemehelper.util.ATHUtil -import code.name.monkey.appthemehelper.util.TintHelper -import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper -import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog -import code.name.monkey.retromusic.dialogs.SleepTimerDialog -import code.name.monkey.retromusic.helper.MusicPlayerRemote -import code.name.monkey.retromusic.helper.SortOrder -import code.name.monkey.retromusic.interfaces.CabHolder -import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks -import code.name.monkey.retromusic.loaders.SongLoader -import code.name.monkey.retromusic.ui.activities.SettingsActivity -import code.name.monkey.retromusic.ui.fragments.base.AbsLibraryPagerRecyclerViewCustomGridSizeFragment -import code.name.monkey.retromusic.ui.fragments.base.AbsMainActivityFragment -import code.name.monkey.retromusic.util.NavigationUtil -import code.name.monkey.retromusic.util.RetroColorUtil -import code.name.monkey.retromusic.util.RetroUtil -import com.afollestad.materialcab.MaterialCab -import com.google.android.material.appbar.AppBarLayout - -class LibraryFragment : AbsMainActivityFragment(), CabHolder, MainActivityFragmentCallbacks, AppBarLayout.OnOffsetChangedListener { - override fun onOffsetChanged(p0: AppBarLayout?, p1: Int) { - mainActivity.setLightStatusbar(!ATHUtil.isWindowBackgroundDark(context)) - } - - - lateinit var toolbar: Toolbar - lateinit var appbar: AppBarLayout - lateinit var title: TextView - lateinit var contentContainer: View - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle?): View? { - val view = inflater.inflate(R.layout.fragment_library, container, false) - toolbar = view.findViewById(R.id.toolbar) - appbar = view.findViewById(R.id.app_bar) - title = view.findViewById(R.id.title) - contentContainer = view.findViewById(R.id.fragment_container) - return view - } - - private var cab: MaterialCab? = null - - - val totalAppBarScrollingRange: Int - get() = appbar.totalScrollRange - - private fun getCurrentFragment(): Fragment? { - return if (fragmentManager == null) { - SongsFragment.newInstance() - } else fragmentManager!!.findFragmentById(R.id.fragment_container) - } - - private fun selectedFragment(fragment: Fragment) { - val fragmentManager = childFragmentManager - val fragmentTransaction = fragmentManager.beginTransaction() - - fragmentTransaction - .replace(R.id.fragment_container, fragment, TAG) - .commit() - - fragmentManager.executePendingTransactions() - } - - fun setTitle(@StringRes name: Int) { - title.text = getString(name) - } - - fun addOnAppBarOffsetChangedListener(onOffsetChangedListener: AppBarLayout.OnOffsetChangedListener) { - appbar.addOnOffsetChangedListener(onOffsetChangedListener) - } - - fun removeOnAppBarOffsetChangedListener(onOffsetChangedListener: AppBarLayout.OnOffsetChangedListener) { - appbar.removeOnOffsetChangedListener(onOffsetChangedListener) - } - - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - setStatusbarColorAuto(view) - setupToolbar() - inflateFragment() - - } - - private fun inflateFragment() { - if (arguments == null) { - selectedFragment(SongsFragment.newInstance()) - return - } - when (arguments!!.getInt(CURRENT_TAB_ID)) { - R.id.action_song -> selectedFragment(SongsFragment.newInstance()) - R.id.action_album -> selectedFragment(AlbumsFragment.newInstance()) - R.id.action_artist -> selectedFragment(ArtistsFragment.newInstance()) - R.id.action_playlist -> selectedFragment(PlaylistsFragment.newInstance()) - else -> selectedFragment(SongsFragment.newInstance()) - } - } - - private fun setupToolbar() { - title.setTextColor(ThemeStore.textColorPrimary(context!!)) - - val primaryColor = ThemeStore.primaryColor(context!!) - TintHelper.setTintAuto(contentContainer, primaryColor, true) - - toolbar.setBackgroundColor(primaryColor) - appbar.setBackgroundColor(primaryColor) - appbar.addOnOffsetChangedListener(this) - mainActivity.title = null - mainActivity.setSupportActionBar(toolbar) - toolbar.navigationIcon = RetroUtil.getTintedDrawable(mainActivity, R.drawable.ic_menu_white_24dp, ThemeStore.textColorPrimary(mainActivity)) - } - - - override fun handleBackPress(): Boolean { - if (cab != null && cab!!.isActive) { - cab!!.finish() - return true - } - return false - } - - - override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab { - if (cab != null && cab!!.isActive) { - cab!!.finish() - } - - cab = MaterialCab(mainActivity, R.id.cab_stub) - .setMenu(menuRes) - .setCloseDrawableRes(R.drawable.ic_close_white_24dp) - .setBackgroundColor( - RetroColorUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor(activity!!))) - .start(callback) - return cab as MaterialCab - } - - private fun isPlaylistFragment(): Boolean { - return true - } - - override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { - super.onCreateOptionsMenu(menu, inflater) - inflater!!.inflate(R.menu.menu_main, menu) - if (isPlaylistFragment()) { - menu!!.add(0, R.id.action_new_playlist, 0, R.string.new_playlist_title) - } - val currentFragment = getCurrentFragment() - if (currentFragment is AbsLibraryPagerRecyclerViewCustomGridSizeFragment<*, *> && currentFragment.isAdded) { - val fragment = currentFragment as AbsLibraryPagerRecyclerViewCustomGridSizeFragment<*, *>? - - val gridSizeItem = menu!!.findItem(R.id.action_grid_size) - if (RetroUtil.isLandscape()) { - gridSizeItem.setTitle(R.string.action_grid_size_land) - } - setUpGridSizeMenu(fragment!!, gridSizeItem.subMenu) - - setUpSortOrderMenu(fragment, menu.findItem(R.id.action_sort_order).subMenu) - - } else { - menu!!.removeItem(R.id.action_grid_size) - } - ToolbarContentTintHelper.handleOnCreateOptionsMenu(activity!!, toolbar, menu, ATHToolbarActivity.getToolbarBackgroundColor(toolbar)) - } - - override fun onPrepareOptionsMenu(menu: Menu?) { - super.onPrepareOptionsMenu(menu) - val activity = activity ?: return - ToolbarContentTintHelper.handleOnPrepareOptionsMenu(activity, toolbar) - } - - - private fun setUpSortOrderMenu( - fragment: AbsLibraryPagerRecyclerViewCustomGridSizeFragment<*, *>, - sortOrderMenu: SubMenu) { - val currentSortOrder = fragment.getSortOrder() - sortOrderMenu.clear() - - when (fragment) { - is AlbumsFragment -> { - sortOrderMenu.add(0, R.id.action_album_sort_order_asc, 0, R.string.sort_order_a_z).isChecked = currentSortOrder == SortOrder.AlbumSortOrder.ALBUM_A_Z - sortOrderMenu.add(0, R.id.action_album_sort_order_desc, 1, R.string.sort_order_z_a).isChecked = currentSortOrder == SortOrder.AlbumSortOrder.ALBUM_Z_A - sortOrderMenu.add(0, R.id.action_album_sort_order_artist, 2, R.string.sort_order_artist).isChecked = currentSortOrder == SortOrder.AlbumSortOrder.ALBUM_ARTIST - sortOrderMenu.add(0, R.id.action_album_sort_order_year, 3, R.string.sort_order_year).isChecked = currentSortOrder == SortOrder.AlbumSortOrder.ALBUM_YEAR - } - is ArtistsFragment -> { - sortOrderMenu.add(0, R.id.action_artist_sort_order_asc, 0, R.string.sort_order_a_z).isChecked = currentSortOrder == SortOrder.ArtistSortOrder.ARTIST_A_Z - sortOrderMenu.add(0, R.id.action_artist_sort_order_desc, 1, R.string.sort_order_z_a).isChecked = currentSortOrder == SortOrder.ArtistSortOrder.ARTIST_Z_A - } - is SongsFragment -> { - sortOrderMenu.add(0, R.id.action_song_sort_order_asc, 0, R.string.sort_order_a_z).isChecked = currentSortOrder == SortOrder.SongSortOrder.SONG_A_Z - sortOrderMenu.add(0, R.id.action_song_sort_order_desc, 1, R.string.sort_order_z_a).isChecked = currentSortOrder == SortOrder.SongSortOrder.SONG_Z_A - sortOrderMenu.add(0, R.id.action_song_sort_order_artist, 2, R.string.sort_order_artist).isChecked = currentSortOrder == SortOrder.SongSortOrder.SONG_ARTIST - sortOrderMenu.add(0, R.id.action_song_sort_order_album, 3, R.string.sort_order_album).isChecked = currentSortOrder == SortOrder.SongSortOrder.SONG_ALBUM - sortOrderMenu.add(0, R.id.action_song_sort_order_year, 4, R.string.sort_order_year).isChecked = currentSortOrder == SortOrder.SongSortOrder.SONG_YEAR - sortOrderMenu.add(0, R.id.action_song_sort_order_date, 4, R.string.sort_order_date).isChecked = currentSortOrder == SortOrder.SongSortOrder.SONG_DATE - - } - } - - sortOrderMenu.setGroupCheckable(0, true, true) - } - - private fun handleSortOrderMenuItem( - fragment: AbsLibraryPagerRecyclerViewCustomGridSizeFragment<*, *>, item: MenuItem): Boolean { - var sortOrder: String? = null - when (fragment) { - is AlbumsFragment -> when (item.itemId) { - R.id.action_album_sort_order_asc -> sortOrder = SortOrder.AlbumSortOrder.ALBUM_A_Z - R.id.action_album_sort_order_desc -> sortOrder = SortOrder.AlbumSortOrder.ALBUM_Z_A - R.id.action_album_sort_order_artist -> sortOrder = SortOrder.AlbumSortOrder.ALBUM_ARTIST - R.id.action_album_sort_order_year -> sortOrder = SortOrder.AlbumSortOrder.ALBUM_YEAR - } - is ArtistsFragment -> when (item.itemId) { - R.id.action_artist_sort_order_asc -> sortOrder = SortOrder.ArtistSortOrder.ARTIST_A_Z - R.id.action_artist_sort_order_desc -> sortOrder = SortOrder.ArtistSortOrder.ARTIST_Z_A - } - is SongsFragment -> when (item.itemId) { - R.id.action_song_sort_order_asc -> sortOrder = SortOrder.SongSortOrder.SONG_A_Z - R.id.action_song_sort_order_desc -> sortOrder = SortOrder.SongSortOrder.SONG_Z_A - R.id.action_song_sort_order_artist -> sortOrder = SortOrder.SongSortOrder.SONG_ARTIST - R.id.action_song_sort_order_album -> sortOrder = SortOrder.SongSortOrder.SONG_ALBUM - R.id.action_song_sort_order_year -> sortOrder = SortOrder.SongSortOrder.SONG_YEAR - R.id.action_song_sort_order_date -> sortOrder = SortOrder.SongSortOrder.SONG_DATE - } - } - - if (sortOrder != null) { - item.isChecked = true - fragment.setAndSaveSortOrder(sortOrder) - return true - } - - return false - } - - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - //if (pager == null) return false; - val currentFragment = getCurrentFragment() - if (currentFragment is AbsLibraryPagerRecyclerViewCustomGridSizeFragment<*, *>) { - val fragment = currentFragment as AbsLibraryPagerRecyclerViewCustomGridSizeFragment<*, *>? - if (handleGridSizeMenuItem(fragment!!, item)) { - return true - } - if (handleSortOrderMenuItem(fragment, item)) { - return true - } - } - val id = item.itemId - when (id) { - R.id.action_new_playlist -> { - CreatePlaylistDialog.create().show(childFragmentManager, "CREATE_PLAYLIST") - return true - } - R.id.action_shuffle_all -> { - MusicPlayerRemote.openAndShuffleQueue(SongLoader.getAllSongs(context!!).blockingFirst(), true) - return true - } - R.id.action_equalizer -> { - NavigationUtil.openEqualizer(activity!!) - return true - } - R.id.action_sleep_timer -> { - if (fragmentManager != null) { - SleepTimerDialog().show(fragmentManager!!, TAG) - } - return true - } - R.id.action_settings -> startActivity(Intent(context, SettingsActivity::class.java)) - } - return super.onOptionsItemSelected(item) - } - - - private fun setUpGridSizeMenu( - fragment: AbsLibraryPagerRecyclerViewCustomGridSizeFragment<*, *>, - gridSizeMenu: SubMenu) { - when (fragment.getGridSize()) { - 1 -> gridSizeMenu.findItem(R.id.action_grid_size_1).isChecked = true - 2 -> gridSizeMenu.findItem(R.id.action_grid_size_2).isChecked = true - 3 -> gridSizeMenu.findItem(R.id.action_grid_size_3).isChecked = true - 4 -> gridSizeMenu.findItem(R.id.action_grid_size_4).isChecked = true - 5 -> gridSizeMenu.findItem(R.id.action_grid_size_5).isChecked = true - 6 -> gridSizeMenu.findItem(R.id.action_grid_size_6).isChecked = true - 7 -> gridSizeMenu.findItem(R.id.action_grid_size_7).isChecked = true - 8 -> gridSizeMenu.findItem(R.id.action_grid_size_8).isChecked = true - } - val maxGridSize = fragment.maxGridSize - if (maxGridSize < 8) { - gridSizeMenu.findItem(R.id.action_grid_size_8).isVisible = false - } - if (maxGridSize < 7) { - gridSizeMenu.findItem(R.id.action_grid_size_7).isVisible = false - } - if (maxGridSize < 6) { - gridSizeMenu.findItem(R.id.action_grid_size_6).isVisible = false - } - if (maxGridSize < 5) { - gridSizeMenu.findItem(R.id.action_grid_size_5).isVisible = false - } - if (maxGridSize < 4) { - gridSizeMenu.findItem(R.id.action_grid_size_4).isVisible = false - } - if (maxGridSize < 3) { - gridSizeMenu.findItem(R.id.action_grid_size_3).isVisible = false - } - } - - - private fun handleGridSizeMenuItem( - fragment: AbsLibraryPagerRecyclerViewCustomGridSizeFragment<*, *>, item: MenuItem): Boolean { - var gridSize = 0 - when (item.itemId) { - R.id.action_grid_size_1 -> gridSize = 1 - R.id.action_grid_size_2 -> gridSize = 2 - R.id.action_grid_size_3 -> gridSize = 3 - R.id.action_grid_size_4 -> gridSize = 4 - R.id.action_grid_size_5 -> gridSize = 5 - R.id.action_grid_size_6 -> gridSize = 6 - R.id.action_grid_size_7 -> gridSize = 7 - R.id.action_grid_size_8 -> gridSize = 8 - } - - if (gridSize > 0) { - item.isChecked = true - fragment.setAndSaveGridSize(gridSize) - return true - } - return false - } - - companion object { - - const val TAG: String = "LibraryFragment" - private const val CURRENT_TAB_ID = "current_tab_id" - - fun newInstance(tab: Int): Fragment { - val args = Bundle() - args.putInt(CURRENT_TAB_ID, tab) - val fragment = LibraryFragment() - fragment.arguments = args - return fragment - } - - fun newInstance(): Fragment { - return LibraryFragment() - } - } - - -} - diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/home/BannerHomeFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/home/BannerHomeFragment.kt index 7615a697..35471ea0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/home/BannerHomeFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/home/BannerHomeFragment.kt @@ -40,6 +40,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.schedulers.Schedulers +import kotlinx.android.synthetic.main.abs_playlists.* import kotlinx.android.synthetic.main.fragment_banner_home.* import kotlinx.android.synthetic.main.home_section_content.* import java.io.File @@ -181,6 +182,10 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba loadImageFromStorage(userImage) getTimeOfTheDay() + + searchView.setOnClickListener { + NavigationUtil.goToSearch(activity!!) + } } private fun setupToolbar() { @@ -212,7 +217,7 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba } - override fun showData(homes: ArrayList) { + override fun showData(list: ArrayList) { //homeAdapter.swapDataSet(homes); } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/PlayerAlbumCoverFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/PlayerAlbumCoverFragment.kt index 008fa552..700918f2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/PlayerAlbumCoverFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/PlayerAlbumCoverFragment.kt @@ -7,8 +7,10 @@ import android.view.ViewGroup import androidx.viewpager.widget.ViewPager import code.name.monkey.retromusic.R import code.name.monkey.retromusic.helper.MusicPlayerRemote +import code.name.monkey.retromusic.transform.CarousalPagerTransformer import code.name.monkey.retromusic.transform.ParallaxPagerTransformer import code.name.monkey.retromusic.ui.adapter.album.AlbumCoverPagerAdapter +import code.name.monkey.retromusic.ui.fragments.NowPlayingScreen import code.name.monkey.retromusic.ui.fragments.base.AbsMusicServiceFragment import code.name.monkey.retromusic.util.PreferenceUtil import kotlinx.android.synthetic.main.fragment_player_album_cover.* @@ -40,7 +42,15 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(), ViewPager.OnPageChan override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewPager.addOnPageChangeListener(this) - viewPager.setPageTransformer(true, PreferenceUtil.getInstance().getAlbumCoverTransform(context)) + //noinspection ConstantConditions + if (PreferenceUtil.getInstance().carouselEffect() && !((PreferenceUtil.getInstance().nowPlayingScreen == NowPlayingScreen.FULL) || (PreferenceUtil.getInstance().nowPlayingScreen == NowPlayingScreen.FIT))) { + viewPager.clipToPadding = false; + viewPager.setPadding(96, 0, 96, 0); + viewPager.pageMargin = 18; + viewPager.setPageTransformer(false, CarousalPagerTransformer(context!!)); + } else { + viewPager.setPageTransformer(true, PreferenceUtil.getInstance().getAlbumCoverTransform(context!!)); + } } override fun onDestroyView() { diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptiveFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptiveFragment.kt index 5735ebfd..ef8f8926 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptiveFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptiveFragment.kt @@ -34,8 +34,8 @@ class AdaptiveFragment : AbsPlayerFragment(), PlayerAlbumCoverFragment.Callbacks } private fun setUpSubFragments() { - playbackControlsFragment = childFragmentManager.findFragmentById(R.id.playback_controls_fragment) as AdaptivePlaybackControlsFragment - val playerAlbumCoverFragment = childFragmentManager.findFragmentById(R.id.player_album_cover_fragment) as PlayerAlbumCoverFragment + playbackControlsFragment = childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as AdaptivePlaybackControlsFragment + val playerAlbumCoverFragment = childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment playerAlbumCoverFragment.apply { removeSlideEffect() }.setCallbacks(this) diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/color/ColorFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/color/ColorFragment.kt index ee42ef4c..64d3a8f1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/color/ColorFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/color/ColorFragment.kt @@ -210,14 +210,14 @@ class ColorFragment : AbsPlayerFragment() { updateLyricsAsyncTask!!.cancel(false) } val song = MusicPlayerRemote.currentSong - updateLyricsAsyncTask = object : AsyncTask() { + updateLyricsAsyncTask = object : AsyncTask() { override fun onPreExecute() { super.onPreExecute() lyrics = null playerToolbar.menu.removeItem(R.id.action_show_lyrics) } - override fun doInBackground(vararg params: Void): Lyrics? { + override fun doInBackground(vararg params: Void?): Lyrics? { val data = MusicUtil.getLyrics(song) return if (TextUtils.isEmpty(data)) { null @@ -233,7 +233,7 @@ class ColorFragment : AbsPlayerFragment() { } } - override fun onCancelled(s: Lyrics) { + override fun onCancelled(s: Lyrics?) { onPostExecute(null) } }.execute() diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/lockscreen/LockScreenPlayerControlsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/lockscreen/LockScreenPlayerControlsFragment.kt new file mode 100644 index 00000000..4837e6a6 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/lockscreen/LockScreenPlayerControlsFragment.kt @@ -0,0 +1,229 @@ +package code.name.monkey.retromusic.ui.fragments.player.lockscreen + +import android.animation.ObjectAnimator +import android.graphics.PorterDuff +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.animation.DecelerateInterpolator +import android.view.animation.LinearInterpolator +import android.widget.SeekBar +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.appthemehelper.util.TintHelper +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.helper.MusicPlayerRemote +import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper +import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler +import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener +import code.name.monkey.retromusic.service.MusicService +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment +import code.name.monkey.retromusic.util.MusicUtil +import kotlinx.android.synthetic.main.fragment_lock_screen_playback_controls.* +import kotlinx.android.synthetic.main.media_button.* +import kotlinx.android.synthetic.main.player_time.* + +/** + * @author Hemanth S (h4h13). + */ +class LockScreenPlayerControlsFragment : AbsPlayerControlsFragment() { + + private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null + private var lastPlaybackControlsColor: Int = 0 + private var lastDisabledPlaybackControlsColor: Int = 0 + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + progressViewUpdateHelper = MusicProgressViewUpdateHelper(this) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + val view = inflater.inflate(R.layout.fragment_lock_screen_playback_controls, container, false) + + return view + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setUpMusicControllers() + } + + private fun updateSong() { + val song = MusicPlayerRemote.currentSong + + title.text = song.title + text.text = String.format("%s - %s", song.artistName, song.albumName) + + } + + override fun onResume() { + super.onResume() + progressViewUpdateHelper!!.start() + } + + override fun onPause() { + super.onPause() + progressViewUpdateHelper!!.stop() + } + + override fun onServiceConnected() { + updatePlayPauseDrawableState() + updateRepeatState() + updateShuffleState() + updateSong() + } + + override fun onPlayingMetaChanged() { + super.onPlayingMetaChanged() + updateSong() + } + + override fun onPlayStateChanged() { + updatePlayPauseDrawableState() + } + + override fun onRepeatModeChanged() { + updateRepeatState() + } + + override fun onShuffleModeChanged() { + updateShuffleState() + } + + override fun setDark(color: Int) { + setProgressBarColor(progressSlider, color) + + val colorBg = ATHUtil.resolveColor(activity, android.R.attr.colorBackground) + if (ColorUtil.isColorLight(colorBg)) { + lastPlaybackControlsColor = MaterialValueHelper.getSecondaryTextColor(activity, true) + lastDisabledPlaybackControlsColor = MaterialValueHelper.getSecondaryDisabledTextColor(activity, true) + } else { + lastPlaybackControlsColor = MaterialValueHelper.getPrimaryTextColor(activity, false) + lastDisabledPlaybackControlsColor = MaterialValueHelper.getPrimaryDisabledTextColor(activity, false) + } + + updatePrevNextColor() + + val isDark = ColorUtil.isColorLight(color) + text!!.setTextColor(color) + TintHelper.setTintAuto(playPauseButton, MaterialValueHelper.getPrimaryTextColor(context, isDark), false) + TintHelper.setTintAuto(playPauseButton, color, true) + } + + fun setProgressBarColor(progressBar: SeekBar?, newColor: Int) { + TintHelper.setTintAuto(progressBar!!, newColor, false) + //LayerDrawable ld = (LayerDrawable) progressBar.getProgressDrawable(); + //ClipDrawable clipDrawable = (ClipDrawable) ld.findDrawableByLayerId(android.R.id.progress); + //clipDrawable.setColorFilter(newColor, PorterDuff.Mode.SRC_IN); + } + + private fun setUpPlayPauseFab() { + playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler()) + } + + private fun updatePlayPauseDrawableState() { + if (MusicPlayerRemote.isPlaying) { + playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp) + } else { + playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp) + } + } + + + private fun setUpMusicControllers() { + setUpPlayPauseFab() + setUpPrevNext() + setUpProgressSlider() + setUpShuffleButton() + setUpRepeatButton() + } + + private fun setUpPrevNext() { + updatePrevNextColor() + nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() } + previousButton.setOnClickListener { MusicPlayerRemote.back() } + } + + private fun updatePrevNextColor() { + nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + } + + private fun setUpShuffleButton() { + shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() } + } + + override fun updateShuffleState() { + when (MusicPlayerRemote.shuffleMode) { + MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + else -> shuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + } + } + + private fun setUpRepeatButton() { + repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() } + } + + override fun updateRepeatState() { + when (MusicPlayerRemote.repeatMode) { + MusicService.REPEAT_MODE_NONE -> { + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp) + repeatButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + } + MusicService.REPEAT_MODE_ALL -> { + repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp) + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + } + MusicService.REPEAT_MODE_THIS -> { + repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp) + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + } + } + } + + public override fun show() { + playPauseButton!!.animate() + .scaleX(1f) + .scaleY(1f) + .rotation(360f) + .setInterpolator(DecelerateInterpolator()) + .start() + } + + public override fun hide() { + if (playPauseButton != null) { + playPauseButton!!.apply { + scaleX = 0f + scaleY = 0f + rotation = 0f + } + } + } + + override fun setUpProgressSlider() { + progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() { + override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { + if (fromUser) { + MusicPlayerRemote.seekTo(progress) + onUpdateProgressViews(MusicPlayerRemote.songProgressMillis, + MusicPlayerRemote.songDurationMillis) + } + } + }) + } + + override fun onUpdateProgressViews(progress: Int, total: Int) { + progressSlider.max = total + + val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress) + animator.duration = 1500 + animator.interpolator = LinearInterpolator() + animator.start() + + songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong()) + songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong()) + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/material/MaterialControlsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/material/MaterialControlsFragment.kt index fb0299cc..7f74fba5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/material/MaterialControlsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/material/MaterialControlsFragment.kt @@ -121,9 +121,9 @@ class MaterialControlsFragment : AbsPlayerControlsFragment() { private fun updatePlayPauseDrawableState() { if (MusicPlayerRemote.isPlaying) { - playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp) + playPauseButton.setImageResource(R.drawable.ic_pause_white_big); } else { - playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp) + playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_big); } } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/normal/PlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/normal/PlayerFragment.kt index 04ccc628..378cdaa1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/normal/PlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/normal/PlayerFragment.kt @@ -96,6 +96,7 @@ class PlayerFragment : AbsPlayerFragment(), PlayerAlbumCoverFragment.Callbacks { super.onViewCreated(view, savedInstanceState) setUpSubFragments() setUpPlayerToolbar() + snowfall.visibility= if (PreferenceUtil.getInstance().isSnowFall) View.VISIBLE else View.GONE } private fun setUpSubFragments() { diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/MainSettingsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/MainSettingsFragment.kt index 8bafb141..bd20e266 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/MainSettingsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/MainSettingsFragment.kt @@ -1,16 +1,28 @@ package code.name.monkey.retromusic.ui.fragments.settings +import android.graphics.Bitmap import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView import androidx.annotation.StringRes +import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.retromusic.Constants.USER_PROFILE import code.name.monkey.retromusic.R import code.name.monkey.retromusic.ui.activities.SettingsActivity +import code.name.monkey.retromusic.util.Compressor +import code.name.monkey.retromusic.util.NavigationUtil +import code.name.monkey.retromusic.util.PreferenceUtil +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.schedulers.Schedulers import kotlinx.android.synthetic.main.fragment_main_settings.* +import java.io.File +import java.util.* + class MainSettingsFragment : Fragment(), View.OnClickListener { override fun onClick(v: View) { @@ -44,6 +56,12 @@ class MainSettingsFragment : Fragment(), View.OnClickListener { imageSettings.setOnClickListener(this) notificationSettings.setOnClickListener(this) otherSettings.setOnClickListener(this) + + text.setTextColor(ThemeStore.textColorSecondary(context!!)); + titleWelcome.setTextColor(ThemeStore.textColorPrimary(context!!)); + titleWelcome.text = String.format("%s %s!", getTimeOfTheDay(), PreferenceUtil.getInstance().userName); + loadImageFromStorage(); + userInfoContainer.setOnClickListener { NavigationUtil.goToUserInfo(activity!!) } } private fun inflateFragment(fragment: Fragment, @StringRes title: Int) { @@ -51,4 +69,42 @@ class MainSettingsFragment : Fragment(), View.OnClickListener { (activity as SettingsActivity).setupFragment(fragment, title) } } + + private fun getTimeOfTheDay(): String { + var message = getString(R.string.title_good_day) + val c = Calendar.getInstance() + val timeOfDay = c.get(Calendar.HOUR_OF_DAY) + + when (timeOfDay) { + in 0..5 -> message = getString(R.string.title_good_night) + in 6..11 -> message = getString(R.string.title_good_morning) + in 12..15 -> message = getString(R.string.title_good_afternoon) + in 16..19 -> message = getString(R.string.title_good_evening) + in 20..23 -> message = getString(R.string.title_good_night) + } + return message + } + + override fun onDestroyView() { + super.onDestroyView() + disposable.clear() + } + + private val disposable = CompositeDisposable() + + private fun loadImageFromStorage() { + + disposable.add(Compressor(context!!) + .setMaxHeight(300) + .setMaxWidth(300) + .setQuality(75) + .setCompressFormat(Bitmap.CompressFormat.WEBP) + .compressToBitmapAsFlowable( + File(PreferenceUtil.getInstance().profileImage, USER_PROFILE)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ userImage.setImageBitmap(it) }, { + userImage.setImageDrawable(ContextCompat.getDrawable(context!!, R.drawable.ic_person_flat)) + })) + } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ThemeSettingsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ThemeSettingsFragment.kt index 889d9fd4..38ca63be 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ThemeSettingsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ThemeSettingsFragment.kt @@ -11,6 +11,7 @@ import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.retromusic.App import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager import code.name.monkey.retromusic.util.PreferenceUtil import com.afollestad.materialdialogs.color.ColorChooserDialog @@ -64,6 +65,7 @@ class ThemeSettingsFragment : AbsSettingsFragment() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { activity!!.setTheme(PreferenceUtil.getThemeResFromPrefValue(theme)) + DynamicShortcutManager(activity!!).updateDynamicShortcuts() } activity!!.recreate() //invalidateSettings(); @@ -92,6 +94,7 @@ class ThemeSettingsFragment : AbsSettingsFragment() { colorAppShortcuts.setOnPreferenceChangeListener { _, newValue -> // Save preference PreferenceUtil.getInstance().setColoredAppShortcuts(newValue as Boolean) + DynamicShortcutManager(activity!!).updateDynamicShortcuts() true } } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.java index 12c639e1..d6a300ea 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.java @@ -113,6 +113,7 @@ public final class PreferenceUtil { private static final String ALBUM_DETAIL_STYLE = "album_detail_style"; private static final String PAUSE_ON_ZERO_VOLUME = "pause_on_zero_volume"; private static final String NOW_PLAYING_SCREEN = "now_playing_screen"; + private static final String SNOW_FALL_EFFECT = "snow_fall_effect"; private static PreferenceUtil sInstance; private final SharedPreferences mPreferences; @@ -144,8 +145,12 @@ public final class PreferenceUtil { } } + public boolean isSnowFall() { + return mPreferences.getBoolean(SNOW_FALL_EFFECT, false); + } + public final String getArtistSortOrder() { - return mPreferences.getString(ARTIST_SORT_ORDER, SortOrder.ArtistSortOrder.Companion.getARTIST_A_Z()); + return mPreferences.getString(ARTIST_SORT_ORDER, SortOrder.ArtistSortOrder.ARTIST_A_Z); } public void setArtistSortOrder(final String sortOrder) { @@ -155,7 +160,7 @@ public final class PreferenceUtil { } public final String getArtistSongSortOrder() { - return mPreferences.getString(ARTIST_SONG_SORT_ORDER, SortOrder.ArtistSongSortOrder.Companion.getSONG_A_Z()); + return mPreferences.getString(ARTIST_SONG_SORT_ORDER, SortOrder.ArtistSongSortOrder.SONG_A_Z); } public final boolean isHomeBanner() { @@ -164,11 +169,11 @@ public final class PreferenceUtil { public final String getArtistAlbumSortOrder() { return mPreferences - .getString(ARTIST_ALBUM_SORT_ORDER, SortOrder.ArtistAlbumSortOrder.Companion.getALBUM_YEAR()); + .getString(ARTIST_ALBUM_SORT_ORDER, SortOrder.ArtistAlbumSortOrder.ALBUM_YEAR); } public final String getAlbumSortOrder() { - return mPreferences.getString(ALBUM_SORT_ORDER, SortOrder.AlbumSortOrder.Companion.getALBUM_A_Z()); + return mPreferences.getString(ALBUM_SORT_ORDER, SortOrder.AlbumSortOrder.ALBUM_A_Z); } public void setAlbumSortOrder(final String sortOrder) { @@ -179,11 +184,11 @@ public final class PreferenceUtil { public final String getAlbumSongSortOrder() { return mPreferences - .getString(ALBUM_SONG_SORT_ORDER, SortOrder.AlbumSongSortOrder.Companion.getSONG_TRACK_LIST()); + .getString(ALBUM_SONG_SORT_ORDER, SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST); } public final String getSongSortOrder() { - return mPreferences.getString(SONG_SORT_ORDER, SortOrder.SongSortOrder.Companion.getSONG_A_Z()); + return mPreferences.getString(SONG_SORT_ORDER, SortOrder.SongSortOrder.SONG_A_Z); } public void setSongSortOrder(final String sortOrder) { @@ -193,7 +198,7 @@ public final class PreferenceUtil { } public final String getGenreSortOrder() { - return mPreferences.getString(GENRE_SORT_ORDER, SortOrder.GenreSortOrder.Companion.getGENRE_A_Z()); + return mPreferences.getString(GENRE_SORT_ORDER, SortOrder.GenreSortOrder.GENRE_A_Z); } public boolean isScreenOnEnabled() { @@ -288,9 +293,6 @@ public final class PreferenceUtil { editor.apply(); } - public int getLastLyricsType() { - return mPreferences.getInt(LAST_KNOWN_LYRICS_TYPE, R.id.normalLyrics); - } public void setLastLyricsType(int group) { final SharedPreferences.Editor editor = mPreferences.edit(); @@ -632,7 +634,7 @@ public final class PreferenceUtil { public String getAlbumDetailSongSortOrder() { return mPreferences - .getString(ALBUM_DETAIL_SONG_SORT_ORDER, SortOrder.AlbumSongSortOrder.Companion.getSONG_TRACK_LIST()); + .getString(ALBUM_DETAIL_SONG_SORT_ORDER, SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST); } public void setAlbumDetailSongSortOrder(String sortOrder) { @@ -643,7 +645,7 @@ public final class PreferenceUtil { public String getArtistDetailSongSortOrder() { return mPreferences - .getString(ARTIST_DETAIL_SONG_SORT_ORDER, SortOrder.ArtistSongSortOrder.Companion.getSONG_A_Z()); + .getString(ARTIST_DETAIL_SONG_SORT_ORDER, SortOrder.ArtistSongSortOrder.SONG_A_Z); } public void setArtistDetailSongSortOrder(String sortOrder) {