diff --git a/app/app.iml b/app/app.iml index 2566dab7..e41380a5 100644 --- a/app/app.iml +++ b/app/app.iml @@ -8,16 +8,16 @@ - @@ -25,87 +25,90 @@ - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -148,13 +151,16 @@ + + + - + @@ -166,7 +172,6 @@ - @@ -189,87 +194,86 @@ - + - - + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - + + + + - - - + + - - - - - + + + + + + + + - - - - + + + + - - - - - + + - + + - - - + + - - + + + + + - - - - - - - - + + + - + + - - - - - + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 32115020..9b55926c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -142,7 +142,6 @@ dependencies { implementation 'com.anjlab.android.iab.v3:library:1.0.44' /*UI Library*/ - implementation 'uk.co.chrisjenx:calligraphy:2.3.0' implementation 'me.zhanghai.android.materialprogressbar:library:1.4.2' implementation 'com.r0adkll:slidableactivity:2.0.6' /*Backend all*/ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ca258b34..f9c70b14 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,7 +14,7 @@ + android:windowSoftInputMode="stateVisible"/> diff --git a/app/src/main/assets/retro-changelog.html b/app/src/main/assets/retro-changelog.html index 281b5626..9f5329b3 100644 --- a/app/src/main/assets/retro-changelog.html +++ b/app/src/main/assets/retro-changelog.html @@ -1 +1 @@ -

Version 2.2.100

  • Click new music mix to play songs
  • Gradient image option for gird list
  • Clear button for playing queue
  • Click toolbar (Library) to open options
  • Folder list back button
  • New theme Fit
  • On library click on toolbar for accessing main menu
  • On home click on toolbar for accessing search
  • BottomSheetDialogue is now adaptable to screens, background colour and text size consistency.
  • Removed coloured navigation bar option to making app adapt the primary colour
  • Swipe up gesture for now playing removed, replaced with "tap to open", To achieve transparent navigation bar for desired themes.
  • Improved tablet UI and home screen by adding suggestions toggle banner issues.
  • Improving lyrics page

FAQ's

*If you face any UI related issues you clear app data and cache, if its not working try to uninstall and install again.

\ No newline at end of file +

Version 2.2.100

  • Click new music mix to play songs
  • Gradient image option for gird list
  • Clear button for playing queue
  • Click toolbar (Library) to open options
  • Folder list back button
  • New theme Fit
  • On library click on toolbar for accessing main menu
  • On home click on toolbar for accessing search
  • BottomSheetDialogue is now adaptable to screens, background colour and text size consistency.
  • Removed coloured navigation bar option to making app adapt the primary colour
  • Swipe up gesture for now playing removed, replaced with "tap to open", To achieve transparent navigation bar for desired themes.
  • Improved tablet UI and home screen by adding suggestions toggle banner issues.
  • Improving lyrics page

FAQ's

*If you face any UI related issues you clear app data and cache, if its not working try to uninstall and install again.

\ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/RetroApplication.kt b/app/src/main/java/code/name/monkey/retromusic/App.kt similarity index 94% rename from app/src/main/java/code/name/monkey/retromusic/RetroApplication.kt rename to app/src/main/java/code/name/monkey/retromusic/App.kt index 176e6a03..0c3d590d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/RetroApplication.kt +++ b/app/src/main/java/code/name/monkey/retromusic/App.kt @@ -6,9 +6,8 @@ import code.name.monkey.appthemehelper.ThemeStore import com.anjlab.android.iab.v3.BillingProcessor import com.anjlab.android.iab.v3.TransactionDetails import com.bumptech.glide.Glide -import uk.co.chrisjenx.calligraphy.CalligraphyConfig -class RetroApplication : MultiDexApplication() { +class App : MultiDexApplication() { lateinit var billingProcessor: BillingProcessor @@ -67,7 +66,7 @@ class RetroApplication : MultiDexApplication() { const val PRO_VERSION_PRODUCT_ID = "pro_version" - lateinit var instance: RetroApplication + lateinit var instance: App private set val context: Context diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.java deleted file mode 100644 index 2a8cfa7c..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.java +++ /dev/null @@ -1,84 +0,0 @@ -package code.name.monkey.retromusic.dialogs; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import java.util.ArrayList; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.DefaultItemAnimator; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import code.name.monkey.appthemehelper.ThemeStore; -import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.loaders.PlaylistLoader; -import code.name.monkey.retromusic.model.Playlist; -import code.name.monkey.retromusic.model.Song; -import code.name.monkey.retromusic.ui.adapter.playlist.AddToPlaylist; -import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; - -/** - * @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad) - */ -public class AddToPlaylistDialog extends RoundedBottomSheetDialogFragment { - - @BindView(R.id.playlists) - RecyclerView playlist; - - @BindView(R.id.title) - TextView title; - - @NonNull - public static AddToPlaylistDialog create(Song song) { - ArrayList list = new ArrayList<>(); - list.add(song); - return create(list); - } - - @NonNull - public static AddToPlaylistDialog create(ArrayList songs) { - AddToPlaylistDialog dialog = new AddToPlaylistDialog(); - Bundle args = new Bundle(); - args.putParcelableArrayList("songs", songs); - dialog.setArguments(args); - return dialog; - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.dialog_add_to_playlist, container, false); - ButterKnife.bind(this, layout); - return layout; - } - - @SuppressWarnings("ConstantConditions") - @OnClick(R.id.action_add_playlist) - void newPlaylist() { - final ArrayList songs = getArguments().getParcelableArrayList("songs"); - CreatePlaylistDialog.create(songs) - .show(getActivity().getSupportFragmentManager(), "ADD_TO_PLAYLIST"); - dismiss(); - } - - @SuppressWarnings("ConstantConditions") - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - title.setTextColor(ThemeStore.textColorPrimary(getContext())); - final ArrayList songs = getArguments().getParcelableArrayList("songs"); - final ArrayList playlists = PlaylistLoader.INSTANCE.getAllPlaylists(getActivity()).blockingFirst(); - final AddToPlaylist playlistAdapter = new AddToPlaylist(getActivity(), playlists, R.layout.item_playlist, songs, getDialog()); - playlist.setLayoutManager(new LinearLayoutManager(getContext())); - playlist.setItemAnimator(new DefaultItemAnimator()); - playlist.setAdapter(playlistAdapter); - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt new file mode 100644 index 00000000..b8b68391 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt @@ -0,0 +1,68 @@ +package code.name.monkey.retromusic.dialogs + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.DefaultItemAnimator +import androidx.recyclerview.widget.LinearLayoutManager +import butterknife.ButterKnife +import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.loaders.PlaylistLoader +import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.ui.adapter.playlist.AddToPlaylist +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment +import kotlinx.android.synthetic.main.dialog_add_to_playlist.* +import java.util.* + +/** + * @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad) + */ +class AddToPlaylistDialog : RoundedBottomSheetDialogFragment() { + + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + val layout = inflater.inflate(R.layout.dialog_add_to_playlist, container, false) + ButterKnife.bind(this, layout) + return layout + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + actionAddPlaylist.setOnClickListener { + val songs = arguments!!.getParcelableArrayList("songs") + CreatePlaylistDialog.create(songs).show(activity!!.supportFragmentManager, "ADD_TO_PLAYLIST") + dismiss() + } + + bannerTitle.setTextColor(ThemeStore.textColorPrimary(context!!)) + val songs = arguments!!.getParcelableArrayList("songs") + val playlists = PlaylistLoader.getAllPlaylists(activity!!).blockingFirst() + val playlistAdapter = AddToPlaylist(activity!!, playlists, R.layout.item_playlist, songs!!, dialog) + recyclerView.apply { + layoutManager = LinearLayoutManager(context) + itemAnimator = DefaultItemAnimator() + adapter = playlistAdapter + } + } + + companion object { + + fun create(song: Song): AddToPlaylistDialog { + val list = ArrayList() + list.add(song) + return create(list) + } + + fun create(songs: ArrayList): AddToPlaylistDialog { + val dialog = AddToPlaylistDialog() + val args = Bundle() + args.putParcelableArrayList("songs", songs) + dialog.arguments = args + return dialog + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/ClearSmartPlaylistDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/ClearSmartPlaylistDialog.java deleted file mode 100644 index 735b0f9d..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/ClearSmartPlaylistDialog.java +++ /dev/null @@ -1,52 +0,0 @@ -package code.name.monkey.retromusic.dialogs; - -import android.app.Dialog; -import android.os.Bundle; -import android.text.Html; - -import com.afollestad.materialdialogs.DialogAction; -import com.afollestad.materialdialogs.MaterialDialog; - -import androidx.annotation.NonNull; -import androidx.fragment.app.DialogFragment; -import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist; - - -public class ClearSmartPlaylistDialog extends DialogFragment { - - @NonNull - public static ClearSmartPlaylistDialog create(AbsSmartPlaylist playlist) { - ClearSmartPlaylistDialog dialog = new ClearSmartPlaylistDialog(); - Bundle args = new Bundle(); - args.putParcelable("playlist", playlist); - dialog.setArguments(args); - return dialog; - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - //noinspection unchecked - final AbsSmartPlaylist playlist = getArguments().getParcelable("playlist"); - int title = R.string.clear_playlist_title; - //noinspection ConstantConditions - CharSequence content = Html.fromHtml(getString(R.string.clear_playlist_x, playlist.name)); - - return new MaterialDialog.Builder(getActivity()) - .title(title) - .content(content) - .positiveText(R.string.clear_action) - .negativeText(android.R.string.cancel) - .onPositive(new MaterialDialog.SingleButtonCallback() { - @Override - public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { - if (getActivity() == null) { - return; - } - playlist.clear(getActivity()); - } - }) - .build(); - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/ClearSmartPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/ClearSmartPlaylistDialog.kt new file mode 100644 index 00000000..500d95dc --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/ClearSmartPlaylistDialog.kt @@ -0,0 +1,45 @@ +package code.name.monkey.retromusic.dialogs + +import android.app.Dialog +import android.os.Bundle +import android.text.Html +import androidx.fragment.app.DialogFragment +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist +import com.afollestad.materialdialogs.MaterialDialog + + +class ClearSmartPlaylistDialog : DialogFragment() { + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + + val playlist = arguments!!.getParcelable("playlist") + val title = R.string.clear_playlist_title + + val content = Html.fromHtml(getString(R.string.clear_playlist_x, playlist!!.name)) + + return MaterialDialog.Builder(activity!!) + .title(title) + .content(content) + .positiveText(R.string.clear_action) + .negativeText(android.R.string.cancel) + .onPositive { _, _ -> + if (activity == null) { + return@onPositive + } + playlist.clear(activity) + } + .build() + } + + companion object { + + fun create(playlist: AbsSmartPlaylist): ClearSmartPlaylistDialog { + val dialog = ClearSmartPlaylistDialog() + val args = Bundle() + args.putParcelable("playlist", playlist) + dialog.arguments = args + return dialog + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.java deleted file mode 100644 index b1b7cf45..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.java +++ /dev/null @@ -1,123 +0,0 @@ -package code.name.monkey.retromusic.dialogs; - -import android.content.res.ColorStateList; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import com.google.android.material.button.MaterialButton; -import com.google.android.material.textfield.TextInputEditText; -import com.google.android.material.textfield.TextInputLayout; - -import java.util.ArrayList; -import java.util.Objects; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import code.name.monkey.appthemehelper.ThemeStore; -import code.name.monkey.appthemehelper.util.MaterialUtil; -import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.model.Song; -import code.name.monkey.retromusic.util.PlaylistsUtil; -import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; - -/** - * @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad) - */ -public class CreatePlaylistDialog extends RoundedBottomSheetDialogFragment { - - @BindView(R.id.option_1) - TextInputEditText playlistName; - - @BindView(R.id.action_new_playlist) - TextInputLayout textInputLayout; - - @BindView(R.id.action_cancel) - MaterialButton actionCancel; - - @BindView(R.id.action_create) - MaterialButton actionCreate; - - @BindView(R.id.title) - TextView title; - - @NonNull - public static CreatePlaylistDialog create() { - return create((Song) null); - } - - @NonNull - public static CreatePlaylistDialog create(@Nullable Song song) { - ArrayList list = new ArrayList<>(); - if (song != null) { - list.add(song); - } - return create(list); - } - - @NonNull - public static CreatePlaylistDialog create(ArrayList songs) { - CreatePlaylistDialog dialog = new CreatePlaylistDialog(); - Bundle args = new Bundle(); - args.putParcelableArrayList("songs", songs); - dialog.setArguments(args); - return dialog; - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.dialog_create_playlist, container, false); - ButterKnife.bind(this, layout); - return layout; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - int accentColor = ThemeStore.accentColor(Objects.requireNonNull(getContext())); - - MaterialUtil.setTint(actionCreate, true); - - MaterialUtil.setTint(actionCancel, false); - - MaterialUtil.setTint(textInputLayout, true); - - - playlistName.setHintTextColor(ColorStateList.valueOf(accentColor)); - playlistName.setTextColor(ThemeStore.textColorPrimary(getContext())); - - title.setTextColor(ThemeStore.textColorPrimary(getContext())); - } - - @OnClick({R.id.action_cancel, R.id.action_create}) - void actions(View view) { - switch (view.getId()) { - case R.id.action_cancel: - dismiss(); - break; - case R.id.action_create: - if (getActivity() == null) { - return; - } - if (!playlistName.getText().toString().trim().isEmpty()) { - final int playlistId = PlaylistsUtil - .createPlaylist(getActivity(), playlistName.getText().toString()); - if (playlistId != -1 && getActivity() != null) { - //noinspection unchecked - ArrayList songs = getArguments().getParcelableArrayList("songs"); - if (songs != null) { - PlaylistsUtil.addToPlaylist(getActivity(), songs, playlistId, true); - } - } - } - break; - } - dismiss(); - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt new file mode 100644 index 00000000..f2245eba --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt @@ -0,0 +1,83 @@ +package code.name.monkey.retromusic.dialogs + +import android.content.Context +import android.content.res.ColorStateList +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import butterknife.ButterKnife +import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.appthemehelper.util.MaterialUtil +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.util.PlaylistsUtil +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment +import kotlinx.android.synthetic.main.dialog_playlist.* +import java.util.* + +/** + * @author Karim Abou Zeid (kabouzeid), Aidan Follestad (afollestad) + */ +class CreatePlaylistDialog : RoundedBottomSheetDialogFragment() { + + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val layout = inflater.inflate(R.layout.dialog_playlist, container, false) + ButterKnife.bind(this, layout) + return layout + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val accentColor = ThemeStore.accentColor(Objects.requireNonNull(context)) + + MaterialUtil.setTint(actionCreate, true) + MaterialUtil.setTint(actionCancel, false) + MaterialUtil.setTint(actionNewPlaylistContainer, true) + + actionNewPlaylist.setHintTextColor(ColorStateList.valueOf(accentColor)) + actionNewPlaylist.setTextColor(ThemeStore.textColorPrimary(context!!)) + bannerTitle.setTextColor(ThemeStore.textColorPrimary(context!!)) + + + actionCancel.setOnClickListener { dismiss() } + actionCreate.setOnClickListener { + if (activity == null) { + return@setOnClickListener + } + if (!actionNewPlaylist!!.text!!.toString().trim { it <= ' ' }.isEmpty()) { + val playlistId = PlaylistsUtil + .createPlaylist(activity!!, actionNewPlaylist!!.text!!.toString()) + if (playlistId != -1 && activity != null) { + + val songs = arguments!!.getParcelableArrayList("songs") + if (songs != null) { + PlaylistsUtil.addToPlaylist(activity!!, songs, playlistId, true) + } + } + } + dismiss() + } + } + + companion object { + + @JvmOverloads + fun create(song: Song? = null): CreatePlaylistDialog { + val list = ArrayList() + if (song != null) { + list.add(song) + } + return create(list) + } + + fun create(songs: ArrayList): CreatePlaylistDialog { + val dialog = CreatePlaylistDialog() + val args = Bundle() + args.putParcelableArrayList("songs", songs) + dialog.arguments = args + return dialog + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.java deleted file mode 100644 index a7681518..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.java +++ /dev/null @@ -1,102 +0,0 @@ -package code.name.monkey.retromusic.dialogs; - -import android.os.Bundle; -import android.text.Html; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import com.google.android.material.button.MaterialButton; - -import java.util.ArrayList; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import code.name.monkey.appthemehelper.ThemeStore; -import code.name.monkey.appthemehelper.util.MaterialUtil; -import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.model.Playlist; -import code.name.monkey.retromusic.util.PlaylistsUtil; -import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; - - -public class DeletePlaylistDialog extends RoundedBottomSheetDialogFragment { - - @BindView(R.id.action_delete) - MaterialButton actionDelete; - - @BindView(R.id.title) - TextView title; - - @BindView(R.id.action_cancel) - MaterialButton actionCancel; - - @NonNull - public static DeletePlaylistDialog create(Playlist playlist) { - ArrayList list = new ArrayList<>(); - list.add(playlist); - return create(list); - } - - @NonNull - public static DeletePlaylistDialog create(ArrayList playlists) { - DeletePlaylistDialog dialog = new DeletePlaylistDialog(); - Bundle args = new Bundle(); - args.putParcelableArrayList("playlists", playlists); - dialog.setArguments(args); - return dialog; - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.dialog_delete, container, false); - ButterKnife.bind(this, layout); - return layout; - } - - @SuppressWarnings("ConstantConditions") - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - //noinspection unchecked - final ArrayList playlists = getArguments().getParcelableArrayList("playlists"); - int title; - CharSequence content; - //noinspection ConstantConditions - if (playlists.size() > 1) { - content = Html.fromHtml(getString(R.string.delete_x_playlists, playlists.size())); - } else { - content = Html.fromHtml(getString(R.string.delete_playlist_x, playlists.get(0).name)); - } - this.title.setText(content); - this.title.setTextColor(ThemeStore.textColorPrimary(getContext())); - - actionDelete.setText(R.string.action_delete); - - MaterialUtil.setTint(actionDelete, true); - MaterialUtil.setTint(actionCancel, false); - - - } - - @OnClick({R.id.action_cancel, R.id.action_delete}) - void actions(View view) { - final ArrayList playlists = getArguments().getParcelableArrayList("playlists"); - switch (view.getId()) { - case R.id.action_delete: - if (getActivity() == null) - return; - PlaylistsUtil.deletePlaylists(getActivity(), playlists); - break; - default: - } - dismiss(); - } - -} \ No newline at end of file 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 new file mode 100644 index 00000000..78a2969b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/DeletePlaylistDialog.kt @@ -0,0 +1,70 @@ +package code.name.monkey.retromusic.dialogs + +import android.os.Bundle +import android.text.Html +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import butterknife.ButterKnife +import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.model.Playlist +import code.name.monkey.retromusic.util.PlaylistsUtil +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment +import kotlinx.android.synthetic.main.dialog_remove_from_playlist.* +import java.util.* + + +class DeletePlaylistDialog : RoundedBottomSheetDialogFragment() { + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + val layout = inflater.inflate(R.layout.dialog_remove_from_playlist, container, false) + ButterKnife.bind(this, layout) + return layout + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val playlists = arguments!!.getParcelableArrayList("playlists") + val content: CharSequence + + content = if (playlists!!.size > 1) { + Html.fromHtml(getString(R.string.delete_x_playlists, playlists.size)) + } else { + Html.fromHtml(getString(R.string.delete_playlist_x, playlists[0].name)) + } + bannerTitle.text = content + bannerTitle.setTextColor(ThemeStore.textColorPrimary(context!!)) + + actionRemove.setText(R.string.action_delete) + actionRemove.setTextColor(ThemeStore.textColorSecondary(context!!)) + actionCancel.setTextColor(ThemeStore.textColorSecondary(context!!)) + + actionCancel.setOnClickListener { dismiss() } + actionRemove.setOnClickListener { + PlaylistsUtil.deletePlaylists(activity!!, playlists) + dismiss() + } + } + + + companion object { + + fun create(playlist: Playlist): DeletePlaylistDialog { + val list = ArrayList() + list.add(playlist) + return create(list) + } + + fun create(playlist: ArrayList): DeletePlaylistDialog { + val dialog = DeletePlaylistDialog() + val args = Bundle() + args.putParcelableArrayList("playlist", playlist) + dialog.arguments = args + return dialog + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/MainOptionsBottomSheetDialogFragment.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/MainOptionsBottomSheetDialogFragment.java deleted file mode 100644 index 0374f023..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/MainOptionsBottomSheetDialogFragment.java +++ /dev/null @@ -1,167 +0,0 @@ -package code.name.monkey.retromusic.dialogs; - -import android.content.res.ColorStateList; -import android.graphics.Bitmap; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.google.android.material.button.MaterialButton; - -import java.io.File; -import java.util.Calendar; -import java.util.List; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.widget.AppCompatTextView; -import androidx.core.content.ContextCompat; -import butterknife.BindView; -import butterknife.BindViews; -import butterknife.ButterKnife; -import butterknife.OnClick; -import code.name.monkey.appthemehelper.ThemeStore; -import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.RetroApplication; -import code.name.monkey.retromusic.ui.activities.MainActivity; -import code.name.monkey.retromusic.ui.fragments.mainactivity.folders.FoldersFragment; -import code.name.monkey.retromusic.util.Compressor; -import code.name.monkey.retromusic.util.NavigationUtil; -import code.name.monkey.retromusic.util.PreferenceUtil; -import code.name.monkey.retromusic.views.CircularImageView; -import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; - -import static code.name.monkey.retromusic.Constants.USER_PROFILE; - -public class MainOptionsBottomSheetDialogFragment extends RoundedBottomSheetDialogFragment { - - private static final String TAG = "MainOptionsBottomSheetD"; - private static ButterKnife.Setter textColor = (view, value, index) -> view.setTextColor(ColorStateList.valueOf(value)); - - - @BindViews({R.id.action_folders, R.id.action_about, R.id.action_buy_pro, R.id.action_rate, - R.id.action_sleep_timer}) - List materialButtons; - - @BindView(R.id.user_image_bottom) - CircularImageView userImageBottom; - - @BindView(R.id.title_welcome) - AppCompatTextView titleWelcome; - - @BindView(R.id.text) - AppCompatTextView text; - - private CompositeDisposable disposable = new CompositeDisposable(); - - public static MainOptionsBottomSheetDialogFragment newInstance(int selected_id) { - Bundle bundle = new Bundle(); - bundle.putInt("selected_id", selected_id); - MainOptionsBottomSheetDialogFragment fragment = new MainOptionsBottomSheetDialogFragment(); - fragment.setArguments(bundle); - return fragment; - } - - public static MainOptionsBottomSheetDialogFragment newInstance() { - return new MainOptionsBottomSheetDialogFragment(); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - disposable.clear(); - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.fragment_main_options, container, false); - ButterKnife.bind(this, layout); - layout.findViewById(R.id.action_buy_pro).setVisibility(RetroApplication.Companion.isProVersion() ? View.GONE : View.VISIBLE); - //ButterKnife.apply(materialButtons, textColor, ThemeStore.textColorPrimary(getContext())); - return layout; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - text.setTextColor(ThemeStore.textColorSecondary(getContext())); - titleWelcome.setTextColor(ThemeStore.textColorPrimary(getContext())); - titleWelcome.setText(String.format("%s %s!", getTimeOfTheDay(), PreferenceUtil.getInstance().getUserName())); - loadImageFromStorage(); - } - - @OnClick({R.id.action_folders, R.id.user_info_container, R.id.action_settings, R.id.action_sleep_timer, R.id.action_rate, - R.id.action_buy_pro, R.id.action_about}) - void onClick(View view) { - MainActivity mainActivity = (MainActivity) getActivity(); - if (mainActivity == null) { - return; - } - switch (view.getId()) { - case R.id.action_folders: - mainActivity.setCurrentFragment(FoldersFragment.newInstance(getContext()), true, FoldersFragment.TAG); - break; - case R.id.action_settings: - NavigationUtil.goToSettings(mainActivity); - break; - case R.id.action_about: - NavigationUtil.goToAbout(mainActivity); - break; - case R.id.action_buy_pro: - NavigationUtil.goToProVersion(mainActivity); - break; - case R.id.action_sleep_timer: - if (getFragmentManager() != null) { - new SleepTimerDialog().show(getFragmentManager(), TAG); - } - break; - case R.id.user_info_container: - NavigationUtil.goToUserInfo(getActivity()); - break; - case R.id.action_rate: - NavigationUtil.goToPlayStore(mainActivity); - break; - } - dismiss(); - } - - private String getTimeOfTheDay() { - String message = getString(R.string.title_good_day); - Calendar c = Calendar.getInstance(); - int timeOfDay = c.get(Calendar.HOUR_OF_DAY); - - if (timeOfDay >= 0 && timeOfDay < 6) { - message = getString(R.string.title_good_night); - } else if (timeOfDay >= 6 && timeOfDay < 12) { - message = getString(R.string.title_good_morning); - } else if (timeOfDay >= 12 && timeOfDay < 16) { - message = getString(R.string.title_good_afternoon); - } else if (timeOfDay >= 16 && timeOfDay < 20) { - message = getString(R.string.title_good_evening); - } else if (timeOfDay >= 20 && timeOfDay < 24) { - message = getString(R.string.title_good_night); - } - return message; - } - - private void loadImageFromStorage() { - //noinspection ConstantConditions - disposable.add(new Compressor(getContext()) - .setMaxHeight(300) - .setMaxWidth(300) - .setQuality(75) - .setCompressFormat(Bitmap.CompressFormat.WEBP) - .compressToBitmapAsFlowable( - new File(PreferenceUtil.getInstance().getProfileImage(),USER_PROFILE)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(userImageBottom::setImageBitmap, - throwable -> userImageBottom.setImageDrawable(ContextCompat - .getDrawable(getContext(), R.drawable.ic_person_flat)))); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/MainOptionsBottomSheetDialogFragment.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/MainOptionsBottomSheetDialogFragment.kt new file mode 100644 index 00000000..50f76b85 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/MainOptionsBottomSheetDialogFragment.kt @@ -0,0 +1,117 @@ +package code.name.monkey.retromusic.dialogs + +import android.graphics.Bitmap +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +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.MainActivity +import code.name.monkey.retromusic.util.Compressor +import code.name.monkey.retromusic.util.NavigationUtil +import code.name.monkey.retromusic.util.PreferenceUtil +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.schedulers.Schedulers +import kotlinx.android.synthetic.main.fragment_main_options.* +import java.io.File +import java.util.* + +class MainOptionsBottomSheetDialogFragment : RoundedBottomSheetDialogFragment(), View.OnClickListener { + + private val disposable = CompositeDisposable() + + private val timeOfTheDay: String + get() { + 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() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_main_options, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + text!!.setTextColor(ThemeStore.textColorSecondary(context!!)) + titleWelcome!!.setTextColor(ThemeStore.textColorPrimary(context!!)) + titleWelcome!!.text = String.format("%s %s!", timeOfTheDay, PreferenceUtil.getInstance().userName) + loadImageFromStorage() + + actionSettings.setOnClickListener(this) + actionAbout.setOnClickListener(this) + actionSleepTimer.setOnClickListener(this) + userInfoContainer.setOnClickListener(this) + actionRate.setOnClickListener(this) + } + + + override fun onClick(view: View) { + val mainActivity = activity as MainActivity? ?: return + when (view.id) { + R.id.actionSettings -> NavigationUtil.goToSettings(mainActivity) + R.id.actionAbout -> NavigationUtil.goToAbout(mainActivity) + R.id.actionSleepTimer -> if (fragmentManager != null) { + SleepTimerDialog().show(fragmentManager!!, TAG) + } + R.id.userInfoContainer -> NavigationUtil.goToUserInfo(activity!!) + R.id.actionRate -> NavigationUtil.goToPlayStore(mainActivity) + } + dismiss() + } + + 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)) + }, { + + })) + } + + companion object { + + private const val TAG: String = "MainOptionsBottomSheetD" + + fun newInstance(selected_id: Int): MainOptionsBottomSheetDialogFragment { + val bundle = Bundle() + bundle.putInt("selected_id", selected_id) + val fragment = MainOptionsBottomSheetDialogFragment() + fragment.arguments = bundle + return fragment + } + + fun newInstance(): MainOptionsBottomSheetDialogFragment { + return MainOptionsBottomSheetDialogFragment() + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveFromPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveFromPlaylistDialog.kt index 38726666..94988c5a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveFromPlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/RemoveFromPlaylistDialog.kt @@ -6,40 +6,17 @@ import android.text.Html import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.TextView -import butterknife.BindView import butterknife.ButterKnife -import butterknife.OnClick import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.retromusic.R import code.name.monkey.retromusic.model.PlaylistSong import code.name.monkey.retromusic.util.PlaylistsUtil import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment +import kotlinx.android.synthetic.main.dialog_remove_from_playlist.* import java.util.* class RemoveFromPlaylistDialog : RoundedBottomSheetDialogFragment() { - @BindView(R.id.action_remove) - internal var remove: TextView? = null - - @BindView(R.id.title) - internal var title: TextView? = null - - @BindView(R.id.action_cancel) - internal var cancel: TextView? = null - - @OnClick(R.id.action_cancel, R.id.action_remove) - internal fun actions(view: View) { - val songs = arguments!!.getParcelableArrayList("songs") - when (view.id) { - R.id.action_remove -> { - if (activity == null) - return - PlaylistsUtil.removeFromPlaylist(activity!!, songs!!) - } - } - dismiss() - } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val layout = inflater.inflate(R.layout.dialog_remove_from_playlist, container, false) @@ -64,12 +41,17 @@ class RemoveFromPlaylistDialog : RoundedBottomSheetDialogFragment() { title = R.string.remove_song_from_playlist_title content = Html.fromHtml(getString(R.string.remove_song_x_from_playlist, songs!![0].title)) } - this.remove!!.text = content - this.title!!.setText(title) + actionRemove.text = content + bannerTitle.setText(title) - this.title!!.setTextColor(ThemeStore.textColorPrimary(context!!)) - this.remove!!.setTextColor(ThemeStore.textColorSecondary(context!!)) - this.cancel!!.setTextColor(ThemeStore.textColorSecondary(context!!)) + bannerTitle.setTextColor(ThemeStore.textColorPrimary(context!!)) + actionRemove.setTextColor(ThemeStore.textColorSecondary(context!!)) + actionCancel.setTextColor(ThemeStore.textColorSecondary(context!!)) + + actionRemove.setOnClickListener { + PlaylistsUtil.removeFromPlaylist(activity!!, songs) + } + actionCancel.setOnClickListener { dismiss() } } companion object { diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.java b/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.java deleted file mode 100644 index 19d32f6c..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.java +++ /dev/null @@ -1,98 +0,0 @@ -package code.name.monkey.retromusic.dialogs; - -import android.content.res.ColorStateList; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import com.google.android.material.button.MaterialButton; -import com.google.android.material.textfield.TextInputEditText; -import com.google.android.material.textfield.TextInputLayout; - -import java.util.Objects; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import code.name.monkey.appthemehelper.ThemeStore; -import code.name.monkey.appthemehelper.util.MaterialUtil; -import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.util.PlaylistsUtil; -import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment; - -public class RenamePlaylistDialog extends RoundedBottomSheetDialogFragment { - - @BindView(R.id.title) - TextView title; - - @BindView(R.id.option_1) - TextInputEditText playlistName; - - @BindView(R.id.action_new_playlist) - TextInputLayout textInputLayout; - - @BindView(R.id.action_cancel) - MaterialButton actionCancel; - - @BindView(R.id.action_rename) - MaterialButton rename; - - @NonNull - public static RenamePlaylistDialog create(long playlistId) { - RenamePlaylistDialog dialog = new RenamePlaylistDialog(); - Bundle args = new Bundle(); - args.putLong("playlist_id", playlistId); - dialog.setArguments(args); - return dialog; - } - - @OnClick({R.id.action_cancel, R.id.action_rename}) - void actions(View view) { - switch (view.getId()) { - case R.id.action_cancel: - dismiss(); - break; - case R.id.action_rename: - if (!playlistName.toString().trim().equals("")) { - long playlistId = getArguments().getLong("playlist_id"); - PlaylistsUtil.renamePlaylist(getActivity(), playlistId, - playlistName.getText().toString()); - } - break; - } - dismiss(); - } - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.dialog_playlist_rename, container, false); - ButterKnife.bind(this, layout); - return layout; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - int accentColor = ThemeStore.accentColor(Objects.requireNonNull(getContext())); - MaterialUtil.setTint(rename,true); - MaterialUtil.setTint(actionCancel,false); - MaterialUtil.setTint(textInputLayout,false); - - playlistName.setHintTextColor(ColorStateList.valueOf(accentColor)); - playlistName.setTextColor(ThemeStore.textColorPrimary(getContext())); - - title.setTextColor(ThemeStore.textColorPrimary(getContext())); - - long playlistId = 0; - if (getArguments() != null) { - playlistId = getArguments().getLong("playlist_id"); - } - playlistName.setText(PlaylistsUtil.getNameForPlaylist(getActivity(), playlistId)); - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.kt new file mode 100644 index 00000000..53bc6cb5 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.kt @@ -0,0 +1,65 @@ +package code.name.monkey.retromusic.dialogs + +import android.content.res.ColorStateList +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import butterknife.ButterKnife +import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.appthemehelper.util.MaterialUtil +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.util.PlaylistsUtil +import code.name.monkey.retromusic.views.RoundedBottomSheetDialogFragment +import kotlinx.android.synthetic.main.dialog_playlist.* + +class RenamePlaylistDialog : RoundedBottomSheetDialogFragment() { + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + val layout = inflater.inflate(R.layout.dialog_playlist, container, false) + ButterKnife.bind(this, layout) + return layout + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val accentColor = ThemeStore.accentColor(context!!) + actionCreate.setText(R.string.action_rename) + + MaterialUtil.setTint(actionCreate, true) + MaterialUtil.setTint(actionCancel, false) + MaterialUtil.setTint(actionNewPlaylistContainer, false) + + actionNewPlaylist.apply { + var playlistId: Long = 0 + if (arguments != null) { + playlistId = arguments!!.getLong("playlist_id") + } + setText(PlaylistsUtil.getNameForPlaylist(activity!!, playlistId)) + setHintTextColor(ColorStateList.valueOf(accentColor)) + setTextColor(ThemeStore.textColorPrimary(context!!)) + } + + bannerTitle.setTextColor(ThemeStore.textColorPrimary(context!!)) + bannerTitle.setText(R.string.rename_playlist_title) + actionCancel.setOnClickListener { dismiss() } + actionCreate.setOnClickListener { + if (actionNewPlaylist.toString().trim { it <= ' ' } != "") { + val playlistId = arguments!!.getLong("playlist_id") + PlaylistsUtil.renamePlaylist(context!!, playlistId, actionNewPlaylist.text!!.toString()) + } + } + } + + companion object { + + fun create(playlistId: Long): RenamePlaylistDialog { + val dialog = RenamePlaylistDialog() + val args = Bundle() + args.putLong("playlist_id", playlistId) + dialog.arguments = args + return dialog + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/ArtistGlideRequest.java b/app/src/main/java/code/name/monkey/retromusic/glide/ArtistGlideRequest.java index 7bf2c1e9..2a779a2a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/glide/ArtistGlideRequest.java +++ b/app/src/main/java/code/name/monkey/retromusic/glide/ArtistGlideRequest.java @@ -15,7 +15,7 @@ import com.bumptech.glide.load.resource.drawable.GlideDrawable; import com.bumptech.glide.request.target.Target; import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.App; import code.name.monkey.retromusic.glide.artistimage.ArtistImage; import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder; import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper; @@ -31,7 +31,7 @@ public class ArtistGlideRequest { private static DrawableTypeRequest createBaseRequest(RequestManager requestManager, Artist artist, boolean noCustomImage, boolean forceDownload) { - boolean hasCustomImage = CustomArtistImageUtil.getInstance(RetroApplication.Companion.getInstance()) + boolean hasCustomImage = CustomArtistImageUtil.getInstance(App.Companion.getInstance()) .hasCustomArtistImage(artist); if (noCustomImage || !hasCustomImage) { return requestManager.load(new ArtistImage(artist.getName(), forceDownload)); @@ -41,7 +41,7 @@ public class ArtistGlideRequest { } private static Key createSignature(Artist artist) { - return ArtistSignatureUtil.getInstance(RetroApplication.Companion.getInstance()) + return ArtistSignatureUtil.getInstance(App.Companion.getInstance()) .getArtistSignature(artist.getName()); } diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/RetroMusicColoredTarget.kt b/app/src/main/java/code/name/monkey/retromusic/glide/RetroMusicColoredTarget.kt index 281dc96a..5defa713 100644 --- a/app/src/main/java/code/name/monkey/retromusic/glide/RetroMusicColoredTarget.kt +++ b/app/src/main/java/code/name/monkey/retromusic/glide/RetroMusicColoredTarget.kt @@ -7,7 +7,6 @@ import com.bumptech.glide.request.animation.GlideAnimation import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.RetroApplication import code.name.monkey.retromusic.glide.palette.BitmapPaletteTarget import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.util.PreferenceUtil diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt b/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt index cf685bb2..cec5bd45 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt @@ -12,7 +12,7 @@ import android.provider.MediaStore import android.util.Log import android.widget.Toast import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.RetroApplication +import code.name.monkey.retromusic.App import code.name.monkey.retromusic.loaders.SongLoader import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.service.MusicService @@ -33,7 +33,7 @@ object MusicPlayerRemote { private val castSession: CastSession? get() { - val castSession = CastContext.getSharedInstance(RetroApplication.instance).sessionManager.currentCastSession + val castSession = CastContext.getSharedInstance(App.instance).sessionManager.currentCastSession if (castSession != null) { playbackLocation = PlaybackLocation.REMOTE } else { @@ -48,7 +48,7 @@ object MusicPlayerRemote { val currentSong: Song get() = if (musicService != null) { musicService!!.currentSong - } else Song.EMPTY_SONG + } else Song.emptySong /** * Async diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt index 6796361f..f9c127ce 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/GenreMenuHelper.kt @@ -1,26 +1,22 @@ package code.name.monkey.retromusic.helper.menu import android.app.Activity -import androidx.appcompat.app.AppCompatActivity import android.view.MenuItem - -import java.util.ArrayList - -import code.name.monkey.retromusic.loaders.GenreLoader -import code.name.monkey.retromusic.model.Genre -import code.name.monkey.retromusic.model.Song +import androidx.appcompat.app.AppCompatActivity import code.name.monkey.retromusic.R import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog import code.name.monkey.retromusic.helper.MusicPlayerRemote +import code.name.monkey.retromusic.loaders.GenreLoader +import code.name.monkey.retromusic.model.Genre +import code.name.monkey.retromusic.model.Song +import java.util.* /** * @author Hemanth S (h4h13). */ object GenreMenuHelper { - fun handleMenuClick(activity: AppCompatActivity, - genre: Genre, - item: MenuItem): Boolean { + fun handleMenuClick(activity: AppCompatActivity, genre: Genre, item: MenuItem): Boolean { when (item.itemId) { R.id.action_play -> { MusicPlayerRemote.openQueue(getGenreSongs(activity, genre), 0, true) diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt index 5289ad31..44481a36 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/PlaylistMenuHelper.kt @@ -9,7 +9,7 @@ import android.widget.Toast import java.util.ArrayList import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.RetroApplication +import code.name.monkey.retromusic.App import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog import code.name.monkey.retromusic.dialogs.DeletePlaylistDialog import code.name.monkey.retromusic.dialogs.RenamePlaylistDialog @@ -76,8 +76,8 @@ object PlaylistMenuHelper { private class SavePlaylistAsyncTask internal constructor(context: Context) : WeakContextAsyncTask(context) { override fun doInBackground(vararg params: Playlist): String { - return String.format(RetroApplication.instance.applicationContext.getString(R.string - .saved_playlist_to), PlaylistsUtil.savePlaylist(RetroApplication.instance.applicationContext, params[0]).blockingFirst()) + return String.format(App.instance.applicationContext.getString(R.string + .saved_playlist_to), PlaylistsUtil.savePlaylist(App.instance.applicationContext, params[0]).blockingFirst()) } override fun onPostExecute(string: String) { 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 c6e7f40c..9359e339 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 @@ -119,7 +119,7 @@ object SongLoader { val song: Song = if (cursor != null && cursor.moveToFirst()) { getSongFromCursorImpl(cursor) } else { - Song.EMPTY_SONG + Song.emptySong } cursor?.close() e.onNext(song) diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Album.kt b/app/src/main/java/code/name/monkey/retromusic/model/Album.kt index 27405c44..dc9df05c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/Album.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/Album.kt @@ -36,6 +36,6 @@ class Album { } fun safeGetFirstSong(): Song { - return if (songs!!.isEmpty()) Song.EMPTY_SONG else songs[0] + return if (songs!!.isEmpty()) Song.emptySong else songs[0] } } diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Genre.java b/app/src/main/java/code/name/monkey/retromusic/model/Genre.java new file mode 100644 index 00000000..9522536d --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/model/Genre.java @@ -0,0 +1,86 @@ +package code.name.monkey.retromusic.model; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @author Hemanth S (h4h13). + */ + +public class Genre implements Parcelable { + + public static final Creator CREATOR = new Creator() { + @Override + public Genre createFromParcel(Parcel in) { + return new Genre(in); + } + + @Override + public Genre[] newArray(int size) { + return new Genre[size]; + } + }; + public final int id; + public final String name; + public final int songCount; + + public Genre(final int id, final String name, int songCount) { + this.id = id; + this.name = name; + this.songCount = songCount; + } + + + // For unknown genre + public Genre(final String name, final int songCount) { + this.id = -1; + this.name = name; + this.songCount = songCount; + } + + protected Genre(Parcel in) { + id = in.readInt(); + name = in.readString(); + songCount = in.readInt(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(id); + dest.writeString(name); + dest.writeInt(songCount); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Genre genre = (Genre) o; + + if (id != genre.id) return false; + return name != null ? name.equals(genre.name) : genre.name == null; + } + + @Override + public int hashCode() { + int result = id; + result = 31 * result + (name != null ? name.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Genre{" + + "id=" + id + + ", name='" + name + '\'' + + '}'; + } + + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Genre.kt b/app/src/main/java/code/name/monkey/retromusic/model/Genre.kt deleted file mode 100644 index 9448e18e..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/model/Genre.kt +++ /dev/null @@ -1,26 +0,0 @@ -package code.name.monkey.retromusic.model - -import java.io.Serializable - -/** - * @author Hemanth S (h4h13). - */ - -class Genre : Serializable { - val id: Int - val name: String? - val songCount: Int - - constructor(id: Int, name: String, songCount: Int) { - this.id = id - this.name = name - this.songCount = songCount - } - - // For unknown genre - constructor(name: String, songCount: Int) { - this.id = -1 - this.name = name - this.songCount = songCount - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/model/Song.kt b/app/src/main/java/code/name/monkey/retromusic/model/Song.kt index fab260e2..a395b699 100644 --- a/app/src/main/java/code/name/monkey/retromusic/model/Song.kt +++ b/app/src/main/java/code/name/monkey/retromusic/model/Song.kt @@ -64,7 +64,9 @@ open class Song : Parcelable { } companion object { - val EMPTY_SONG = Song(-1, "", -1, -1, -1, "", -1, -1, "", -1, "") + + var emptySong = Song(-1, "", -1, -1, -1, "", -1, -1, "", -1, "") + @JvmField val CREATOR: Parcelable.Creator = object : Parcelable.Creator { override fun createFromParcel(source: Parcel): Song { diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistDetailsPresenter.java b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistDetailsPresenter.java index 0885f68a..c09e12fc 100644 --- a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistDetailsPresenter.java +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistDetailsPresenter.java @@ -1,13 +1,12 @@ package code.name.monkey.retromusic.mvp.presenter; import android.os.Bundle; -import androidx.annotation.NonNull; +import androidx.annotation.NonNull; import code.name.monkey.retromusic.model.Artist; import code.name.monkey.retromusic.mvp.Presenter; import code.name.monkey.retromusic.mvp.contract.ArtistDetailContract; - -import static code.name.monkey.retromusic.ui.activities.ArtistDetailActivity.EXTRA_ARTIST_ID; +import code.name.monkey.retromusic.ui.activities.ArtistDetailActivity; /** @@ -38,7 +37,7 @@ public class ArtistDetailsPresenter extends Presenter implements ArtistDetailCon @Override public void loadArtistById() { - disposable.add(repository.getArtistById(bundle.getInt(EXTRA_ARTIST_ID)) + disposable.add(repository.getArtistById(bundle.getInt(ArtistDetailActivity.EXTRA_ARTIST_ID)) .subscribeOn(schedulerProvider.computation()) .observeOn(schedulerProvider.ui()) .doOnSubscribe(disposable1 -> view.loading()) diff --git a/app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreferenceDialog.java b/app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreferenceDialog.java index 6c68c8ca..59d7fde5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreferenceDialog.java +++ b/app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreferenceDialog.java @@ -21,7 +21,7 @@ import androidx.fragment.app.DialogFragment; import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager.widget.ViewPager; import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.App; import code.name.monkey.retromusic.ui.fragments.NowPlayingScreen; import code.name.monkey.retromusic.util.NavigationUtil; import code.name.monkey.retromusic.util.PreferenceUtil; @@ -97,8 +97,8 @@ public class NowPlayingScreenPreferenceDialog extends DialogFragment implements nowPlayingScreen.equals(NowPlayingScreen.TINY) || nowPlayingScreen.equals(NowPlayingScreen.BLUR_CARD)|| nowPlayingScreen.equals(NowPlayingScreen.ADAPTIVE)) - && !RetroApplication.Companion.isProVersion();*/ - return !RetroApplication.Companion.isProVersion(); + && !App.Companion.isProVersion();*/ + return !App.Companion.isProVersion(); } @Override 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 index 7deda91e..d65c7b6b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.java +++ b/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.java @@ -6,7 +6,7 @@ import java.io.File; import java.util.ArrayList; import code.name.monkey.retromusic.Injection; -import code.name.monkey.retromusic.RetroApplication; +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; @@ -41,7 +41,7 @@ public class RepositoryImpl implements Repository { public static synchronized RepositoryImpl getInstance() { if (INSTANCE == null) { - INSTANCE = new RepositoryImpl(RetroApplication.Companion.getInstance()); + INSTANCE = new RepositoryImpl(App.Companion.getInstance()); } return INSTANCE; } diff --git a/app/src/main/java/code/name/monkey/retromusic/rest/KogouClient.java b/app/src/main/java/code/name/monkey/retromusic/rest/KogouClient.java index fcf0c7cd..dca902fa 100644 --- a/app/src/main/java/code/name/monkey/retromusic/rest/KogouClient.java +++ b/app/src/main/java/code/name/monkey/retromusic/rest/KogouClient.java @@ -6,7 +6,7 @@ import java.io.File; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.App; import code.name.monkey.retromusic.rest.service.KuGouApiService; import okhttp3.Cache; import okhttp3.Call; @@ -69,7 +69,7 @@ public class KogouClient { return new OkHttpClient.Builder() .addInterceptor(interceptor) - .cache(createDefaultCache(RetroApplication.Companion.getInstance())) + .cache(createDefaultCache(App.Companion.getInstance())) .addInterceptor(createCacheControlInterceptor()); } diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.java b/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.java new file mode 100644 index 00000000..d725f40b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.java @@ -0,0 +1,334 @@ +package code.name.monkey.retromusic.service; + +import android.content.Context; +import android.content.Intent; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.media.audiofx.AudioEffect; +import android.net.Uri; +import android.os.PowerManager; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import android.util.Log; +import android.widget.Toast; + +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.service.playback.Playback; +import code.name.monkey.retromusic.util.PreferenceUtil; + +/** + * @author Andrew Neal, Karim Abou Zeid (kabouzeid) + */ +public class MultiPlayer implements Playback, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener { + public static final String TAG = MultiPlayer.class.getSimpleName(); + + private MediaPlayer mCurrentMediaPlayer = new MediaPlayer(); + private MediaPlayer mNextMediaPlayer; + + private Context context; + @Nullable + private Playback.PlaybackCallbacks callbacks; + + private boolean mIsInitialized = false; + + /** + * Constructor of MultiPlayer + */ + MultiPlayer(final Context context) { + this.context = context; + mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK); + } + + /** + * @param path The path of the file, or the http/rtsp URL of the stream + * you want to play + * @return True if the player has been prepared and is + * ready to play, false otherwise + */ + @Override + public boolean setDataSource(@NonNull final String path) { + mIsInitialized = false; + mIsInitialized = setDataSourceImpl(mCurrentMediaPlayer, path); + if (mIsInitialized) { + setNextDataSource(null); + } + return mIsInitialized; + } + + /** + * @param player The {@link MediaPlayer} to use + * @param path The path of the file, or the http/rtsp URL of the stream + * you want to play + * @return True if the player has been prepared and is + * ready to play, false otherwise + */ + private boolean setDataSourceImpl(@NonNull final MediaPlayer player, @NonNull final String path) { + if (context == null) { + return false; + } + try { + player.reset(); + player.setOnPreparedListener(null); + if (path.startsWith("content://")) { + player.setDataSource(context, Uri.parse(path)); + } else { + player.setDataSource(path); + } + player.setAudioStreamType(AudioManager.STREAM_MUSIC); + player.prepare(); + } catch (Exception e) { + return false; + } + player.setOnCompletionListener(this); + player.setOnErrorListener(this); + final Intent intent = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION); + intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId()); + intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName()); + intent.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC); + context.sendBroadcast(intent); + return true; + } + + /** + * Set the MediaPlayer to start when this MediaPlayer finishes playback. + * + * @param path The path of the file, or the http/rtsp URL of the stream + * you want to play + */ + @Override + public void setNextDataSource(@Nullable final String path) { + if (context == null) { + return; + } + try { + mCurrentMediaPlayer.setNextMediaPlayer(null); + } catch (IllegalArgumentException e) { + Log.i(TAG, "Next media player is current one, continuing"); + } catch (IllegalStateException e) { + Log.e(TAG, "Media player not initialized!"); + return; + } + if (mNextMediaPlayer != null) { + mNextMediaPlayer.release(); + mNextMediaPlayer = null; + } + if (path == null) { + return; + } + if (PreferenceUtil.getInstance().gaplessPlayback()) { + mNextMediaPlayer = new MediaPlayer(); + mNextMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK); + mNextMediaPlayer.setAudioSessionId(getAudioSessionId()); + if (setDataSourceImpl(mNextMediaPlayer, path)) { + try { + mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer); + } catch (@NonNull IllegalArgumentException | IllegalStateException e) { + Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e); + if (mNextMediaPlayer != null) { + mNextMediaPlayer.release(); + mNextMediaPlayer = null; + } + } + } else { + if (mNextMediaPlayer != null) { + mNextMediaPlayer.release(); + mNextMediaPlayer = null; + } + } + } + } + + /** + * Sets the callbacks + * + * @param callbacks The callbacks to use + */ + @Override + public void setCallbacks(@Nullable final Playback.PlaybackCallbacks callbacks) { + this.callbacks = callbacks; + } + + /** + * @return True if the player is ready to go, false otherwise + */ + @Override + public boolean isInitialized() { + return mIsInitialized; + } + + /** + * Starts or resumes playback. + */ + @Override + public boolean start() { + try { + mCurrentMediaPlayer.start(); + return true; + } catch (IllegalStateException e) { + return false; + } + } + + /** + * Resets the MediaPlayer to its uninitialized state. + */ + @Override + public void stop() { + mCurrentMediaPlayer.reset(); + mIsInitialized = false; + } + + /** + * Releases resources associated with this MediaPlayer object. + */ + @Override + public void release() { + stop(); + mCurrentMediaPlayer.release(); + if (mNextMediaPlayer != null) { + mNextMediaPlayer.release(); + } + } + + /** + * Pauses playback. Call start() to resume. + */ + @Override + public boolean pause() { + try { + mCurrentMediaPlayer.pause(); + return true; + } catch (IllegalStateException e) { + return false; + } + } + + /** + * Checks whether the MultiPlayer is playing. + */ + @Override + public boolean isPlaying() { + return mIsInitialized && mCurrentMediaPlayer.isPlaying(); + } + + /** + * Gets the duration of the file. + * + * @return The duration in milliseconds + */ + @Override + public int duration() { + if (!mIsInitialized) { + return -1; + } + try { + return mCurrentMediaPlayer.getDuration(); + } catch (IllegalStateException e) { + return -1; + } + } + + /** + * Gets the current playback position. + * + * @return The current position in milliseconds + */ + @Override + public int position() { + if (!mIsInitialized) { + return -1; + } + try { + return mCurrentMediaPlayer.getCurrentPosition(); + } catch (IllegalStateException e) { + return -1; + } + } + + /** + * Gets the current playback position. + * + * @param whereto The offset in milliseconds from the start to seek to + * @return The offset in milliseconds from the start to seek to + */ + @Override + public int seek(final int whereto) { + try { + mCurrentMediaPlayer.seekTo(whereto); + return whereto; + } catch (IllegalStateException e) { + return -1; + } + } + + @Override + public boolean setVolume(final float vol) { + try { + mCurrentMediaPlayer.setVolume(vol, vol); + return true; + } catch (IllegalStateException e) { + return false; + } + } + + /** + * Sets the audio session ID. + * + * @param sessionId The audio session ID + */ + @Override + public boolean setAudioSessionId(final int sessionId) { + try { + mCurrentMediaPlayer.setAudioSessionId(sessionId); + return true; + } catch (@NonNull IllegalArgumentException | IllegalStateException e) { + return false; + } + } + + /** + * Returns the audio session ID. + * + * @return The current audio session ID. + */ + @Override + public int getAudioSessionId() { + return mCurrentMediaPlayer.getAudioSessionId(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean onError(final MediaPlayer mp, final int what, final int extra) { + mIsInitialized = false; + mCurrentMediaPlayer.release(); + mCurrentMediaPlayer = new MediaPlayer(); + mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK); + if (context != null) { + Toast.makeText(context, context.getResources().getString(R.string.unplayable_file), Toast.LENGTH_SHORT).show(); + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public void onCompletion(final MediaPlayer mp) { + if (mp == mCurrentMediaPlayer && mNextMediaPlayer != null) { + mIsInitialized = false; + mCurrentMediaPlayer.release(); + mCurrentMediaPlayer = mNextMediaPlayer; + mIsInitialized = true; + mNextMediaPlayer = null; + if (callbacks != null) + callbacks.onTrackWentToNext(); + } else { + if (callbacks != null) + callbacks.onTrackEnded(); + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.kt b/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.kt deleted file mode 100644 index ba24b958..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.kt +++ /dev/null @@ -1,333 +0,0 @@ -package code.name.monkey.retromusic.service - -import android.content.Context -import android.content.Intent -import android.media.AudioManager -import android.media.MediaPlayer -import android.media.audiofx.AudioEffect -import android.net.Uri -import android.os.PowerManager -import android.util.Log -import android.widget.Toast - -import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.service.playback.Playback -import code.name.monkey.retromusic.util.PreferenceUtil - -/** - * @author Andrew Neal, Karim Abou Zeid (kabouzeid) - */ -class MultiPlayer -/** - * Constructor of `MultiPlayer` - */ -internal constructor(private val context: Context?) : Playback, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener { - - private var mCurrentMediaPlayer = MediaPlayer() - private var mNextMediaPlayer: MediaPlayer? = null - private var callbacks: Playback.PlaybackCallbacks? = null - - private var mIsInitialized = false - - init { - mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK) - } - - /** - * @param path The path of the file, or the http/rtsp URL of the stream - * you want to play - * @return True if the `player` has been prepared and is - * ready to play, false otherwise - */ - override fun setDataSource(path: String): Boolean { - mIsInitialized = false - mIsInitialized = setDataSourceImpl(mCurrentMediaPlayer, path) - if (mIsInitialized) { - setNextDataSource(null) - } - return mIsInitialized - } - - /** - * @param player The [MediaPlayer] to use - * @param path The path of the file, or the http/rtsp URL of the stream - * you want to play - * @return True if the `player` has been prepared and is - * ready to play, false otherwise - */ - private fun setDataSourceImpl(player: MediaPlayer, path: String): Boolean { - if (context == null) { - return false - } - try { - player.reset() - player.setOnPreparedListener(null) - if (path.startsWith("content://")) { - player.setDataSource(context, Uri.parse(path)) - } else { - player.setDataSource(path) - } - player.setAudioStreamType(AudioManager.STREAM_MUSIC) - player.prepare() - } catch (e: Exception) { - return false - } - - player.setOnCompletionListener(this) - player.setOnErrorListener(this) - val intent = Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION) - intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, audioSessionId) - intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName) - intent.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC) - context.sendBroadcast(intent) - return true - } - - /** - * Set the MediaPlayer to start when this MediaPlayer finishes playback. - * - * @param path The path of the file, or the http/rtsp URL of the stream - * you want to play - */ - override fun setNextDataSource(path: String?) { - if (context == null) { - return - } - try { - mCurrentMediaPlayer.setNextMediaPlayer(null) - } catch (e: IllegalArgumentException) { - Log.i(TAG, "Next media player is current one, continuing") - } catch (e: IllegalStateException) { - Log.e(TAG, "Media player not initialized!") - return - } - - if (mNextMediaPlayer != null) { - mNextMediaPlayer!!.release() - mNextMediaPlayer = null - } - if (path == null) { - return - } - if (PreferenceUtil.getInstance().gaplessPlayback()) { - mNextMediaPlayer = MediaPlayer() - mNextMediaPlayer!!.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK) - mNextMediaPlayer!!.audioSessionId = audioSessionId - if (setDataSourceImpl(mNextMediaPlayer!!, path)) { - try { - mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer) - } catch (e: IllegalArgumentException) { - Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e) - if (mNextMediaPlayer != null) { - mNextMediaPlayer!!.release() - mNextMediaPlayer = null - } - } catch (e: IllegalStateException) { - Log.e(TAG, "setNextDataSource: setNextMediaPlayer()", e) - if (mNextMediaPlayer != null) { - mNextMediaPlayer!!.release() - mNextMediaPlayer = null - } - } - - } else { - if (mNextMediaPlayer != null) { - mNextMediaPlayer!!.release() - mNextMediaPlayer = null - } - } - } - } - - /** - * Sets the callbacks - * - * @param callbacks The callbacks to use - */ - override fun setCallbacks(callbacks: Playback.PlaybackCallbacks?) { - this.callbacks = callbacks - } - - /** - * @return True if the player is ready to go, false otherwise - */ - override fun isInitialized(): Boolean { - return mIsInitialized - } - - /** - * Starts or resumes playback. - */ - override fun start(): Boolean { - try { - mCurrentMediaPlayer.start() - return true - } catch (e: IllegalStateException) { - return false - } - - } - - /** - * Resets the MediaPlayer to its uninitialized state. - */ - override fun stop() { - mCurrentMediaPlayer.reset() - mIsInitialized = false - } - - /** - * Releases resources associated with this MediaPlayer object. - */ - override fun release() { - stop() - mCurrentMediaPlayer.release() - if (mNextMediaPlayer != null) { - mNextMediaPlayer!!.release() - } - } - - /** - * Pauses playback. Call start() to resume. - */ - override fun pause(): Boolean { - try { - mCurrentMediaPlayer.pause() - return true - } catch (e: IllegalStateException) { - return false - } - - } - - /** - * Checks whether the MultiPlayer is playing. - */ - override fun isPlaying(): Boolean { - return mIsInitialized && mCurrentMediaPlayer.isPlaying - } - - /** - * Gets the duration of the file. - * - * @return The duration in milliseconds - */ - override fun duration(): Int { - if (!mIsInitialized) { - return -1 - } - try { - return mCurrentMediaPlayer.duration - } catch (e: IllegalStateException) { - return -1 - } - - } - - /** - * Gets the current playback position. - * - * @return The current position in milliseconds - */ - override fun position(): Int { - if (!mIsInitialized) { - return -1 - } - try { - return mCurrentMediaPlayer.currentPosition - } catch (e: IllegalStateException) { - return -1 - } - - } - - /** - * Gets the current playback position. - * - * @param whereto The offset in milliseconds from the start to seek to - * @return The offset in milliseconds from the start to seek to - */ - override fun seek(whereto: Int): Int { - try { - mCurrentMediaPlayer.seekTo(whereto) - return whereto - } catch (e: IllegalStateException) { - return -1 - } - - } - - override fun setVolume(vol: Float): Boolean { - try { - mCurrentMediaPlayer.setVolume(vol, vol) - return true - } catch (e: IllegalStateException) { - return false - } - - } - - /** - * Sets the audio session ID. - * - * @param sessionId The audio session ID - */ - override fun setAudioSessionId(sessionId: Int): Boolean { - try { - mCurrentMediaPlayer.audioSessionId = sessionId - return true - } catch (e: IllegalArgumentException) { - return false - } catch (e: IllegalStateException) { - return false - } - - } - - /** - * Returns the audio session ID. - * - * @return The current audio session ID. - */ - override fun getAudioSessionId(): Int { - return mCurrentMediaPlayer.audioSessionId - } - - /** - * {@inheritDoc} - */ - override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean { - mIsInitialized = false - mCurrentMediaPlayer.release() - mCurrentMediaPlayer = MediaPlayer() - mCurrentMediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK) - if (context != null) { - Toast.makeText(context, context.resources.getString(R.string.unplayable_file), Toast.LENGTH_SHORT).show() - } - return false - } - - /** - * {@inheritDoc} - */ - override fun onCompletion(mp: MediaPlayer) { - if (mp === mCurrentMediaPlayer && mNextMediaPlayer != null) { - mIsInitialized = false - mCurrentMediaPlayer.release() - mCurrentMediaPlayer = mNextMediaPlayer as MediaPlayer - mIsInitialized = true - mNextMediaPlayer = null - if (callbacks != null) - callbacks!!.onTrackWentToNext() - } else { - if (callbacks != null) - callbacks!!.onTrackEnded() - } - } - - companion object { - val TAG: String = MultiPlayer::class.java.simpleName - } - - -} \ 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 new file mode 100644 index 00000000..39d4e0f0 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java @@ -0,0 +1,1420 @@ +package code.name.monkey.retromusic.service; + +import android.app.PendingIntent; +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.database.ContentObserver; +import android.graphics.Bitmap; +import android.graphics.Point; +import android.graphics.drawable.Drawable; +import android.media.AudioManager; +import android.media.audiofx.AudioEffect; +import android.media.session.MediaSession; +import android.os.Binder; +import android.os.Build; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.PowerManager; +import android.os.Process; +import android.preference.PreferenceManager; +import android.provider.MediaStore; +import android.support.v4.media.MediaMetadataCompat; +import android.support.v4.media.session.MediaSessionCompat; +import android.support.v4.media.session.PlaybackStateCompat; +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyManager; +import android.util.Log; +import android.widget.Toast; + +import com.bumptech.glide.BitmapRequestBuilder; +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.SimpleTarget; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import code.name.monkey.retromusic.R; +import code.name.monkey.retromusic.glide.BlurTransformation; +import code.name.monkey.retromusic.glide.SongGlideRequest; +import code.name.monkey.retromusic.helper.ShuffleHelper; +import code.name.monkey.retromusic.helper.StopWatch; +import code.name.monkey.retromusic.loaders.PlaylistSongsLoader; +import code.name.monkey.retromusic.model.AbsCustomPlaylist; +import code.name.monkey.retromusic.model.Playlist; +import code.name.monkey.retromusic.model.Song; +import code.name.monkey.retromusic.providers.HistoryStore; +import code.name.monkey.retromusic.providers.MusicPlaybackQueueStore; +import code.name.monkey.retromusic.providers.SongPlayCountStore; +import code.name.monkey.retromusic.service.notification.PlayingNotification; +import code.name.monkey.retromusic.service.notification.PlayingNotificationImpl24; +import code.name.monkey.retromusic.service.notification.PlayingNotificationOreo; +import code.name.monkey.retromusic.service.playback.Playback; +import code.name.monkey.retromusic.util.MusicUtil; +import code.name.monkey.retromusic.util.PreferenceUtil; +import code.name.monkey.retromusic.util.RetroUtil; + +import static code.name.monkey.retromusic.Constants.ACTION_PAUSE; +import static code.name.monkey.retromusic.Constants.ACTION_PLAY; +import static code.name.monkey.retromusic.Constants.ACTION_PLAY_PLAYLIST; +import static code.name.monkey.retromusic.Constants.ACTION_QUIT; +import static code.name.monkey.retromusic.Constants.ACTION_REWIND; +import static code.name.monkey.retromusic.Constants.ACTION_SKIP; +import static code.name.monkey.retromusic.Constants.ACTION_STOP; +import static code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE; +import static code.name.monkey.retromusic.Constants.APP_WIDGET_UPDATE; +import static code.name.monkey.retromusic.Constants.EXTRA_APP_WIDGET_NAME; +import static code.name.monkey.retromusic.Constants.INTENT_EXTRA_PLAYLIST; +import static code.name.monkey.retromusic.Constants.INTENT_EXTRA_SHUFFLE_MODE; +import static code.name.monkey.retromusic.Constants.MEDIA_STORE_CHANGED; +import static code.name.monkey.retromusic.Constants.META_CHANGED; +import static code.name.monkey.retromusic.Constants.MUSIC_PACKAGE_NAME; +import static code.name.monkey.retromusic.Constants.PLAY_STATE_CHANGED; +import static code.name.monkey.retromusic.Constants.QUEUE_CHANGED; +import static code.name.monkey.retromusic.Constants.REPEAT_MODE_CHANGED; +import static code.name.monkey.retromusic.Constants.RETRO_MUSIC_PACKAGE_NAME; +import static code.name.monkey.retromusic.Constants.SHUFFLE_MODE_CHANGED; + +/** + * @author Karim Abou Zeid (kabouzeid), Andrew Neal + */ +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; + public static final int PLAY_SONG = 3; + public static final int PREPARE_NEXT = 4; + public static final int SET_POSITION = 5; + public static final int RESTORE_QUEUES = 9; + public static final int SHUFFLE_MODE_NONE = 0; + public static final int SHUFFLE_MODE_SHUFFLE = 1; + public static final int REPEAT_MODE_NONE = 0; + public static final int REPEAT_MODE_ALL = 1; + public static final int REPEAT_MODE_THIS = 2; + public static final int SAVE_QUEUES = 0; + private static final int FOCUS_CHANGE = 6; + private static final int DUCK = 7; + private static final int UNDUCK = 8; + private static final long MEDIA_SESSION_ACTIONS = PlaybackStateCompat.ACTION_PLAY + | PlaybackStateCompat.ACTION_PAUSE + | PlaybackStateCompat.ACTION_PLAY_PAUSE + | PlaybackStateCompat.ACTION_SKIP_TO_NEXT + | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS + | PlaybackStateCompat.ACTION_STOP + | PlaybackStateCompat.ACTION_SEEK_TO; + private final IBinder musicBind = new MusicBinder(); + 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); + + } + }; + private Playback playback; + private ArrayList playingQueue = new ArrayList<>(); + private ArrayList originalPlayingQueue = new ArrayList<>(); + private int position = -1; + private int nextPosition = -1; + private int shuffleMode; + private int repeatMode; + private boolean queuesRestored; + private boolean pausedByTransientLossOfFocus; + private final BroadcastReceiver becomingNoisyReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, @NonNull Intent intent) { + if (intent.getAction() != null && intent.getAction().equals(AudioManager.ACTION_AUDIO_BECOMING_NOISY)) { + pause(); + } + } + }; + private PlayingNotification playingNotification; + private AudioManager audioManager; + @SuppressWarnings("deprecation") + private MediaSessionCompat mediaSession; + private PowerManager.WakeLock wakeLock; + private PlaybackHandler playerHandler; + private final AudioManager.OnAudioFocusChangeListener audioFocusListener = new AudioManager.OnAudioFocusChangeListener() { + @Override + public void onAudioFocusChange(final int focusChange) { + playerHandler.obtainMessage(FOCUS_CHANGE, focusChange, 0).sendToTarget(); + } + }; + private QueueSaveHandler queueSaveHandler; + private HandlerThread musicPlayerHandlerThread; + private HandlerThread queueSaveHandlerThread; + private SongPlayCountHelper songPlayCountHelper = new SongPlayCountHelper(); + private ThrottledSeekHandler throttledSeekHandler; + private boolean becomingNoisyReceiverRegistered; + private IntentFilter becomingNoisyReceiverIntentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY); + private ContentObserver mediaStoreObserver; + private boolean notHandledMetaChangedForCurrentTrack; + private PhoneStateListener phoneStateListener = new PhoneStateListener() { + @Override + public void onCallStateChanged(int state, String incomingNumber) { + switch (state) { + case TelephonyManager.CALL_STATE_IDLE: + //Not in call: Play music + play(); + break; + case TelephonyManager.CALL_STATE_RINGING: + case TelephonyManager.CALL_STATE_OFFHOOK: + //A call is dialing, active or on hold + pause(); + break; + default: + } + super.onCallStateChanged(state, incomingNumber); + } + }; + private boolean isServiceBound; + private Handler uiThreadHandler; + private IntentFilter headsetReceiverIntentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG); + private boolean headsetReceiverRegistered = false; + private BroadcastReceiver headsetReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action != null) { + switch (action) { + case Intent.ACTION_HEADSET_PLUG: + int state = intent.getIntExtra("state", -1); + switch (state) { + case 0: + Log.d(TAG, "Headset unplugged"); + pause(); + break; + case 1: + Log.d(TAG, "Headset plugged"); + play(); + break; + } + break; + } + } + } + }; + + private static String getTrackUri(@NonNull Song song) { + return MusicUtil.getSongFileUri(song.getId()).toString(); + } + + private static Bitmap copy(Bitmap bitmap) { + Bitmap.Config config = bitmap.getConfig(); + if (config == null) { + config = Bitmap.Config.RGB_565; + } + try { + return bitmap.copy(config, false); + } catch (OutOfMemoryError e) { + e.printStackTrace(); + return null; + } + } + + + @Override + public void onCreate() { + super.onCreate(); + + final TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); + if (telephonyManager != null) { + telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE); + } + + final PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); + if (powerManager != null) { + wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName()); + } + wakeLock.setReferenceCounted(false); + + musicPlayerHandlerThread = new HandlerThread("PlaybackHandler"); + musicPlayerHandlerThread.start(); + playerHandler = new PlaybackHandler(this, musicPlayerHandlerThread.getLooper()); + + playback = new MultiPlayer(this); + playback.setCallbacks(this); + + setupMediaSession(); + + // queue saving needs to run on a separate thread so that it doesn't block the playback handler events + queueSaveHandlerThread = new HandlerThread("QueueSaveHandler", Process.THREAD_PRIORITY_BACKGROUND); + queueSaveHandlerThread.start(); + queueSaveHandler = new QueueSaveHandler(this, queueSaveHandlerThread.getLooper()); + + uiThreadHandler = new Handler(); + + registerReceiver(widgetIntentReceiver, new IntentFilter(APP_WIDGET_UPDATE)); + + initNotification(); + + mediaStoreObserver = new MediaStoreObserver(playerHandler); + throttledSeekHandler = new ThrottledSeekHandler(playerHandler); + getContentResolver().registerContentObserver( + MediaStore.Audio.Media.INTERNAL_CONTENT_URI, true, mediaStoreObserver); + getContentResolver().registerContentObserver( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, true, mediaStoreObserver); + + PreferenceUtil.getInstance().registerOnSharedPreferenceChangedListener(this); + + restoreState(); + + mediaSession.setActive(true); + + sendBroadcast(new Intent("code.name.monkey.retromusic.RETRO_MUSIC_SERVICE_CREATED")); + + registerHeadsetEvents(); + + + } + + private AudioManager getAudioManager() { + if (audioManager == null) { + audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); + } + return audioManager; + } + + private void setupMediaSession() { + ComponentName mediaButtonReceiverComponentName = new ComponentName(getApplicationContext(), MediaButtonIntentReceiver.class); + + Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); + mediaButtonIntent.setComponent(mediaButtonReceiverComponentName); + + + PendingIntent mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0); + + mediaSession = new MediaSessionCompat(this, "RetroMusicPlayer", mediaButtonReceiverComponentName, mediaButtonReceiverPendingIntent); + mediaSession.setCallback(new MediaSessionCompat.Callback() { + @Override + public void onPlay() { + play(); + } + + @Override + public void onPause() { + pause(); + } + + @Override + public void onSkipToNext() { + playNextSong(true); + } + + @Override + public void onSkipToPrevious() { + back(true); + } + + @Override + public void onStop() { + quit(); + } + + @Override + public void onSeekTo(long pos) { + seek((int) pos); + } + + @Override + public boolean onMediaButtonEvent(Intent mediaButtonEvent) { + return MediaButtonIntentReceiver.Companion.handleIntent(MusicService.this, mediaButtonEvent); + } + }); + + mediaSession.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS + | MediaSession.FLAG_HANDLES_MEDIA_BUTTONS); + + mediaSession.setMediaButtonReceiver(mediaButtonReceiverPendingIntent); + } + + @Override + public int onStartCommand(@Nullable Intent intent, int flags, int startId) { + if (intent != null) { + if (intent.getAction() != null) { + restoreQueuesAndPositionIfNecessary(); + String action = intent.getAction(); + switch (action) { + case ACTION_TOGGLE_PAUSE: + if (isPlaying()) { + pause(); + } else { + play(); + } + break; + case ACTION_PAUSE: + pause(); + break; + case ACTION_PLAY: + play(); + break; + case ACTION_PLAY_PLAYLIST: + Playlist playlist = intent.getParcelableExtra(INTENT_EXTRA_PLAYLIST); + int shuffleMode = intent.getIntExtra(INTENT_EXTRA_SHUFFLE_MODE, getShuffleMode()); + if (playlist != null) { + ArrayList playlistSongs; + if (playlist instanceof AbsCustomPlaylist) { + playlistSongs = ((AbsCustomPlaylist) playlist).getSongs(getApplicationContext()).blockingFirst(); + } else { + //noinspection unchecked + playlistSongs = PlaylistSongsLoader.INSTANCE.getPlaylistSongList(getApplicationContext(), playlist.id).blockingFirst(); + } + if (!playlistSongs.isEmpty()) { + if (shuffleMode == SHUFFLE_MODE_SHUFFLE) { + int startPosition; + startPosition = new Random().nextInt(playlistSongs.size()); + openQueue(playlistSongs, startPosition, true); + setShuffleMode(shuffleMode); + } else { + openQueue(playlistSongs, 0, true); + } + } else { + Toast.makeText(getApplicationContext(), R.string.playlist_is_empty, Toast.LENGTH_LONG).show(); + } + } else { + Toast.makeText(getApplicationContext(), R.string.playlist_is_empty, Toast.LENGTH_LONG).show(); + } + break; + case ACTION_REWIND: + back(true); + break; + case ACTION_SKIP: + playNextSong(true); + break; + case ACTION_STOP: + case ACTION_QUIT: + return quit(); + } + } + } + + return START_STICKY; + } + + + @Override + public void onDestroy() { + unregisterReceiver(widgetIntentReceiver); + if (becomingNoisyReceiverRegistered) { + unregisterReceiver(becomingNoisyReceiver); + becomingNoisyReceiverRegistered = false; + } + if (headsetReceiverRegistered) { + unregisterReceiver(headsetReceiver); + headsetReceiverRegistered = false; + } + mediaSession.setActive(false); + quit(); + releaseResources(); + getContentResolver().unregisterContentObserver(mediaStoreObserver); + PreferenceUtil.getInstance().unregisterOnSharedPreferenceChangedListener(this); + wakeLock.release(); + + sendBroadcast(new Intent("code.name.monkey.retromusic.RETRO_MUSIC_MUSIC_SERVICE_DESTROYED")); + } + + @Override + public IBinder onBind(Intent intent) { + isServiceBound = true; + return musicBind; + } + + @Override + public void onRebind(Intent intent) { + isServiceBound = true; + } + + @Override + public boolean onUnbind(Intent intent) { + isServiceBound = false; + if (!isPlaying()) { + stopSelf(); + } + return true; + } + + private void saveQueuesImpl() { + MusicPlaybackQueueStore.getInstance(this).saveQueues(playingQueue, originalPlayingQueue); + } + + private void savePosition() { + PreferenceManager.getDefaultSharedPreferences(this).edit().putInt(SAVED_POSITION, getPosition()).apply(); + } + + private void savePositionInTrack() { + PreferenceManager.getDefaultSharedPreferences(this).edit().putInt(SAVED_POSITION_IN_TRACK, getSongProgressMillis()).apply(); + } + + public void saveState() { + saveQueues(); + savePosition(); + savePositionInTrack(); + } + + private void saveQueues() { + queueSaveHandler.removeMessages(SAVE_QUEUES); + queueSaveHandler.sendEmptyMessage(SAVE_QUEUES); + } + + private void restoreState() { + shuffleMode = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_SHUFFLE_MODE, 0); + repeatMode = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_REPEAT_MODE, 0); + handleAndSendChangeInternal(SHUFFLE_MODE_CHANGED); + handleAndSendChangeInternal(REPEAT_MODE_CHANGED); + + playerHandler.removeMessages(RESTORE_QUEUES); + playerHandler.sendEmptyMessage(RESTORE_QUEUES); + } + + private synchronized void restoreQueuesAndPositionIfNecessary() { + if (!queuesRestored && playingQueue.isEmpty()) { + ArrayList restoredQueue = MusicPlaybackQueueStore.getInstance(this).getSavedPlayingQueue() + .blockingFirst(); + + ArrayList restoredOriginalQueue = MusicPlaybackQueueStore.getInstance(this).getSavedOriginalPlayingQueue() + .blockingFirst(); + + int restoredPosition = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_POSITION, -1); + int restoredPositionInTrack = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_POSITION_IN_TRACK, -1); + + if (restoredQueue.size() > 0 && restoredQueue.size() == restoredOriginalQueue.size() && restoredPosition != -1) { + this.originalPlayingQueue = restoredOriginalQueue; + this.playingQueue = restoredQueue; + + position = restoredPosition; + openCurrent(); + prepareNext(); + + if (restoredPositionInTrack > 0) seek(restoredPositionInTrack); + + notHandledMetaChangedForCurrentTrack = true; + sendChangeInternal(META_CHANGED); + sendChangeInternal(QUEUE_CHANGED); + } + } + queuesRestored = true; + } + + private int quit() { + pause(); + playingNotification.stop(); + + if (isServiceBound) { + return START_STICKY; + } else { + closeAudioEffectSession(); + getAudioManager().abandonAudioFocus(audioFocusListener); + stopSelf(); + return START_NOT_STICKY; + } + } + + private void releaseResources() { + playerHandler.removeCallbacksAndMessages(null); + musicPlayerHandlerThread.quitSafely(); + queueSaveHandler.removeCallbacksAndMessages(null); + queueSaveHandlerThread.quitSafely(); + playback.release(); + playback = null; + mediaSession.release(); + } + + public boolean isPlaying() { + return playback != null && playback.isPlaying(); + } + + public int getPosition() { + return position; + } + + public void setPosition(final int position) { + // handle this on the handlers thread to avoid blocking the ui thread + playerHandler.removeMessages(SET_POSITION); + playerHandler.obtainMessage(SET_POSITION, position, 0).sendToTarget(); + } + + public void playNextSong(boolean force) { + playSongAt(getNextPosition(force)); + } + + private boolean openTrackAndPrepareNextAt(int position) { + synchronized (this) { + this.position = position; + boolean prepared = openCurrent(); + if (prepared) prepareNextImpl(); + notifyChange(META_CHANGED); + notHandledMetaChangedForCurrentTrack = false; + return prepared; + } + } + + private boolean openCurrent() { + synchronized (this) { + try { + return playback.setDataSource(getTrackUri(getCurrentSong())); + } catch (Exception e) { + return false; + } + } + } + + private void prepareNext() { + playerHandler.removeMessages(PREPARE_NEXT); + playerHandler.obtainMessage(PREPARE_NEXT).sendToTarget(); + } + + private boolean prepareNextImpl() { + synchronized (this) { + try { + int nextPosition = getNextPosition(false); + playback.setNextDataSource(getTrackUri(getSongAt(nextPosition))); + this.nextPosition = nextPosition; + return true; + } catch (Exception e) { + return false; + } + } + } + + private void closeAudioEffectSession() { + final Intent audioEffectsIntent = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION); + audioEffectsIntent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, playback.getAudioSessionId()); + audioEffectsIntent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName()); + sendBroadcast(audioEffectsIntent); + } + + private boolean requestFocus() { + return (getAudioManager().requestAudioFocus(audioFocusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED); + } + + public void initNotification() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && !PreferenceUtil.getInstance().classicNotification()) { + playingNotification = new PlayingNotificationImpl24(); + } else { + playingNotification = new PlayingNotificationOreo(); + } + playingNotification.init(this); + } + + public void updateNotification() { + if (playingNotification != null && getCurrentSong().getId() != -1) { + playingNotification.update(); + } + } + + private void updateMediaSessionPlaybackState() { + mediaSession.setPlaybackState( + new PlaybackStateCompat.Builder() + .setActions(MEDIA_SESSION_ACTIONS) + .setState(isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED, + getPosition(), 1) + .build()); + } + + private void updateMediaSessionMetaData() { + final Song song = getCurrentSong(); + + if (song.getId() == -1) { + mediaSession.setMetadata(null); + return; + } + + final MediaMetadataCompat.Builder metaData = new MediaMetadataCompat.Builder() + .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, song.getArtistName()) + .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, song.getArtistName()) + .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, song.getAlbumName()) + .putString(MediaMetadataCompat.METADATA_KEY_TITLE, song.getTitle()) + .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, song.getDuration()) + .putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, getPosition() + 1) + .putLong(MediaMetadataCompat.METADATA_KEY_YEAR, song.getYear()) + .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, null); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + metaData.putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, getPlayingQueue().size()); + } + + if (PreferenceUtil.getInstance().albumArtOnLockscreen()) { + final Point screenSize = RetroUtil.getScreenSize(MusicService.this); + final BitmapRequestBuilder request = SongGlideRequest.Builder.from(Glide.with(MusicService.this), song) + .checkIgnoreMediaStore(MusicService.this) + .asBitmap().build(); + if (PreferenceUtil.getInstance().blurredAlbumArt()) { + request.transform(new BlurTransformation.Builder(MusicService.this).build()); + } + runOnUiThread(new Runnable() { + @Override + public void run() { + request.into(new SimpleTarget(screenSize.x, screenSize.y) { + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + super.onLoadFailed(e, errorDrawable); + mediaSession.setMetadata(metaData.build()); + } + + @Override + public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) { + metaData.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, copy(resource)); + mediaSession.setMetadata(metaData.build()); + } + }); + } + }); + } else { + mediaSession.setMetadata(metaData.build()); + } + } + + public void runOnUiThread(Runnable runnable) { + uiThreadHandler.post(runnable); + } + + public Song getCurrentSong() { + return getSongAt(getPosition()); + } + + public Song getSongAt(int position) { + if (position >= 0 && position < getPlayingQueue().size()) { + return getPlayingQueue().get(position); + } else { + return Song.Companion.getEmptySong(); + } + } + + public int getNextPosition(boolean force) { + int position = getPosition() + 1; + switch (getRepeatMode()) { + case REPEAT_MODE_ALL: + if (isLastTrack()) { + position = 0; + } + break; + case REPEAT_MODE_THIS: + if (force) { + if (isLastTrack()) { + position = 0; + } + } else { + position -= 1; + } + break; + default: + case REPEAT_MODE_NONE: + if (isLastTrack()) { + position -= 1; + } + break; + } + return position; + } + + private boolean isLastTrack() { + return getPosition() == getPlayingQueue().size() - 1; + } + + public ArrayList getPlayingQueue() { + return playingQueue; + } + + public int getRepeatMode() { + return repeatMode; + } + + public void setRepeatMode(final int repeatMode) { + switch (repeatMode) { + case REPEAT_MODE_NONE: + case REPEAT_MODE_ALL: + case REPEAT_MODE_THIS: + this.repeatMode = repeatMode; + PreferenceManager.getDefaultSharedPreferences(this).edit() + .putInt(SAVED_REPEAT_MODE, repeatMode) + .apply(); + prepareNext(); + handleAndSendChangeInternal(REPEAT_MODE_CHANGED); + break; + } + } + + public void openQueue(@Nullable final ArrayList playingQueue, final int startPosition, final boolean startPlaying) { + if (playingQueue != null && !playingQueue.isEmpty() && startPosition >= 0 && startPosition < playingQueue.size()) { + // it is important to copy the playing queue here first as we might add/remove songs later + originalPlayingQueue = new ArrayList<>(playingQueue); + this.playingQueue = new ArrayList<>(originalPlayingQueue); + + int position = startPosition; + if (shuffleMode == SHUFFLE_MODE_SHUFFLE) { + ShuffleHelper.INSTANCE.makeShuffleList(this.playingQueue, startPosition); + position = 0; + } + if (startPlaying) { + playSongAt(position); + } else { + setPosition(position); + } + notifyChange(QUEUE_CHANGED); + } + } + + public void addSong(int position, Song song) { + playingQueue.add(position, song); + originalPlayingQueue.add(position, song); + notifyChange(QUEUE_CHANGED); + } + + public void addSong(Song song) { + playingQueue.add(song); + originalPlayingQueue.add(song); + notifyChange(QUEUE_CHANGED); + } + + public void addSongs(int position, List songs) { + playingQueue.addAll(position, songs); + originalPlayingQueue.addAll(position, songs); + notifyChange(QUEUE_CHANGED); + } + + public void addSongs(List songs) { + playingQueue.addAll(songs); + originalPlayingQueue.addAll(songs); + notifyChange(QUEUE_CHANGED); + } + + public void removeSong(int position) { + if (getShuffleMode() == SHUFFLE_MODE_NONE) { + playingQueue.remove(position); + originalPlayingQueue.remove(position); + } else { + originalPlayingQueue.remove(playingQueue.remove(position)); + } + + rePosition(position); + + notifyChange(QUEUE_CHANGED); + } + + public void removeSong(@NonNull Song song) { + for (int i = 0; i < playingQueue.size(); i++) { + if (playingQueue.get(i).getId() == song.getId()) { + playingQueue.remove(i); + rePosition(i); + } + } + for (int i = 0; i < originalPlayingQueue.size(); i++) { + if (originalPlayingQueue.get(i).getId() == song.getId()) { + originalPlayingQueue.remove(i); + } + } + notifyChange(QUEUE_CHANGED); + } + + private void rePosition(int deletedPosition) { + int currentPosition = getPosition(); + if (deletedPosition < currentPosition) { + position = currentPosition - 1; + } else if (deletedPosition == currentPosition) { + if (playingQueue.size() > deletedPosition) { + setPosition(position); + } else { + setPosition(position - 1); + } + } + } + + public void moveSong(int from, int to) { + if (from == to) return; + final int currentPosition = getPosition(); + Song songToMove = playingQueue.remove(from); + playingQueue.add(to, songToMove); + if (getShuffleMode() == SHUFFLE_MODE_NONE) { + Song tmpSong = originalPlayingQueue.remove(from); + originalPlayingQueue.add(to, tmpSong); + } + if (from > currentPosition && to <= currentPosition) { + position = currentPosition + 1; + } else if (from < currentPosition && to >= currentPosition) { + position = currentPosition - 1; + } else if (from == currentPosition) { + position = to; + } + notifyChange(QUEUE_CHANGED); + } + + public void clearQueue() { + playingQueue.clear(); + originalPlayingQueue.clear(); + + setPosition(-1); + notifyChange(QUEUE_CHANGED); + } + + public void playSongAt(final int position) { + // handle this on the handlers thread to avoid blocking the ui thread + playerHandler.removeMessages(PLAY_SONG); + playerHandler.obtainMessage(PLAY_SONG, position, 0).sendToTarget(); + } + + private void playSongAtImpl(int position) { + if (openTrackAndPrepareNextAt(position)) { + play(); + } else { + Toast.makeText(this, getResources().getString(R.string.unplayable_file), Toast.LENGTH_SHORT).show(); + } + } + + public void pause() { + pausedByTransientLossOfFocus = false; + if (playback.isPlaying()) { + playback.pause(); + notifyChange(PLAY_STATE_CHANGED); + } + } + + public void play() { + synchronized (this) { + if (requestFocus()) { + if (!playback.isPlaying()) { + if (!playback.isInitialized()) { + playSongAt(getPosition()); + } else { + playback.start(); + if (!becomingNoisyReceiverRegistered) { + registerReceiver(becomingNoisyReceiver, becomingNoisyReceiverIntentFilter); + becomingNoisyReceiverRegistered = true; + } + if (notHandledMetaChangedForCurrentTrack) { + handleChangeInternal(META_CHANGED); + notHandledMetaChangedForCurrentTrack = false; + } + notifyChange(PLAY_STATE_CHANGED); + + // fixes a bug where the volume would stay ducked because the AudioManager.AUDIOFOCUS_GAIN event is not sent + playerHandler.removeMessages(DUCK); + playerHandler.sendEmptyMessage(UNDUCK); + } + } + } else { + Toast.makeText(this, getResources().getString(R.string.audio_focus_denied), Toast.LENGTH_SHORT).show(); + } + } + } + + public void playSongs(ArrayList songs, int shuffleMode) { + if (songs != null && !songs.isEmpty()) { + if (shuffleMode == SHUFFLE_MODE_SHUFFLE) { + int startPosition = 0; + if (!songs.isEmpty()) { + startPosition = new Random().nextInt(songs.size()); + } + openQueue(songs, startPosition, false); + setShuffleMode(shuffleMode); + } else { + openQueue(songs, 0, false); + } + play(); + } else { + Toast.makeText(getApplicationContext(), R.string.playlist_is_empty, Toast.LENGTH_LONG).show(); + } + } + + public void playPreviousSong(boolean force) { + playSongAt(getPreviousPosition(force)); + } + + public void back(boolean force) { + if (getSongProgressMillis() > 2000) { + seek(0); + } else { + playPreviousSong(force); + } + } + + public int getPreviousPosition(boolean force) { + int newPosition = getPosition() - 1; + switch (repeatMode) { + case REPEAT_MODE_ALL: + if (newPosition < 0) { + newPosition = getPlayingQueue().size() - 1; + } + break; + case REPEAT_MODE_THIS: + if (force) { + if (newPosition < 0) { + newPosition = getPlayingQueue().size() - 1; + } + } else { + newPosition = getPosition(); + } + break; + default: + case REPEAT_MODE_NONE: + if (newPosition < 0) { + newPosition = 0; + } + break; + } + return newPosition; + } + + public int getSongProgressMillis() { + return playback.position(); + } + + public int getSongDurationMillis() { + return playback.duration(); + } + + public long getQueueDurationMillis(int position) { + long duration = 0; + for (int i = position + 1; i < playingQueue.size(); i++) + duration += playingQueue.get(i).getDuration(); + return duration; + } + + public int seek(int millis) { + synchronized (this) { + try { + int newPosition = playback.seek(millis); + throttledSeekHandler.notifySeek(); + return newPosition; + } catch (Exception e) { + return -1; + } + } + } + + public void cycleRepeatMode() { + switch (getRepeatMode()) { + case REPEAT_MODE_NONE: + setRepeatMode(REPEAT_MODE_ALL); + break; + case REPEAT_MODE_ALL: + setRepeatMode(REPEAT_MODE_THIS); + break; + default: + setRepeatMode(REPEAT_MODE_NONE); + break; + } + } + + public void toggleShuffle() { + if (getShuffleMode() == SHUFFLE_MODE_NONE) { + setShuffleMode(SHUFFLE_MODE_SHUFFLE); + } else { + setShuffleMode(SHUFFLE_MODE_NONE); + } + } + + public int getShuffleMode() { + return shuffleMode; + } + + public void setShuffleMode(final int shuffleMode) { + PreferenceManager.getDefaultSharedPreferences(this).edit() + .putInt(SAVED_SHUFFLE_MODE, shuffleMode) + .apply(); + switch (shuffleMode) { + case SHUFFLE_MODE_SHUFFLE: + this.shuffleMode = shuffleMode; + ShuffleHelper.INSTANCE.makeShuffleList(this.getPlayingQueue(), getPosition()); + position = 0; + break; + case SHUFFLE_MODE_NONE: + this.shuffleMode = shuffleMode; + int currentSongId = getCurrentSong().getId(); + playingQueue = new ArrayList<>(originalPlayingQueue); + int newPosition = 0; + for (Song song : getPlayingQueue()) { + if (song.getId() == currentSongId) { + newPosition = getPlayingQueue().indexOf(song); + } + } + position = newPosition; + break; + } + handleAndSendChangeInternal(SHUFFLE_MODE_CHANGED); + notifyChange(QUEUE_CHANGED); + } + + private void notifyChange(@NonNull final String what) { + handleAndSendChangeInternal(what); + sendPublicIntent(what); + } + + private void handleAndSendChangeInternal(@NonNull final String what) { + handleChangeInternal(what); + sendChangeInternal(what); + } + + // to let other apps know whats playing. i.E. last.fm (scrobbling) or musixmatch + private void sendPublicIntent(@NonNull final String what) { + final Intent intent = new Intent(what.replace(RETRO_MUSIC_PACKAGE_NAME, MUSIC_PACKAGE_NAME)); + + final Song song = getCurrentSong(); + + intent.putExtra("id", song.getId()); + intent.putExtra("artist", song.getArtistName()); + intent.putExtra("album", song.getAlbumName()); + intent.putExtra("track", song.getTitle()); + intent.putExtra("duration", song.getDuration()); + intent.putExtra("position", (long) getSongProgressMillis()); + intent.putExtra("playing", isPlaying()); + intent.putExtra("scrobbling_source", RETRO_MUSIC_PACKAGE_NAME); + + sendStickyBroadcast(intent); + + } + + private void sendChangeInternal(final String what) { + sendBroadcast(new Intent(what)); + + } + + private void handleChangeInternal(@NonNull final String what) { + switch (what) { + case PLAY_STATE_CHANGED: + updateNotification(); + updateMediaSessionPlaybackState(); + final boolean isPlaying = isPlaying(); + if (!isPlaying && getSongProgressMillis() > 0) { + savePositionInTrack(); + } + songPlayCountHelper.notifyPlayStateChanged(isPlaying); + break; + case META_CHANGED: + updateNotification(); + updateMediaSessionMetaData(); + savePosition(); + savePositionInTrack(); + final Song currentSong = getCurrentSong(); + HistoryStore.getInstance(this).addSongId(currentSong.getId()); + if (songPlayCountHelper.shouldBumpPlayCount()) { + SongPlayCountStore.getInstance(this).bumpPlayCount(songPlayCountHelper.getSong().getId()); + } + songPlayCountHelper.notifySongChanged(currentSong); + break; + case QUEUE_CHANGED: + updateMediaSessionMetaData(); // because playing queue size might have changed + saveState(); + if (playingQueue.size() > 0) { + prepareNext(); + } else { + playingNotification.stop(); + } + break; + } + } + + public int getAudioSessionId() { + return playback.getAudioSessionId(); + } + + public MediaSessionCompat getMediaSession() { + return mediaSession; + } + + public void releaseWakeLock() { + if (wakeLock.isHeld()) { + wakeLock.release(); + } + } + + public void acquireWakeLock(long milli) { + wakeLock.acquire(milli); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + switch (key) { + case PreferenceUtil.GAPLESS_PLAYBACK: + if (sharedPreferences.getBoolean(key, false)) { + prepareNext(); + } else { + playback.setNextDataSource(null); + } + break; + case PreferenceUtil.ALBUM_ART_ON_LOCKSCREEN: + case PreferenceUtil.BLURRED_ALBUM_ART: + updateMediaSessionMetaData(); + break; + case PreferenceUtil.COLORED_NOTIFICATION: + case PreferenceUtil.DOMINANT_COLOR: + updateNotification(); + break; + case PreferenceUtil.CLASSIC_NOTIFICATION: + initNotification(); + updateNotification(); + break; + case PreferenceUtil.TOGGLE_HEADSET: + registerHeadsetEvents(); + break; + } + } + + private void registerHeadsetEvents() { + if (!headsetReceiverRegistered && PreferenceUtil.getInstance().getHeadsetPlugged()) { + registerReceiver(headsetReceiver, headsetReceiverIntentFilter); + headsetReceiverRegistered = true; + } + } + + @Override + public void onTrackWentToNext() { + playerHandler.sendEmptyMessage(TRACK_WENT_TO_NEXT); + } + + @Override + public void onTrackEnded() { + acquireWakeLock(30000); + playerHandler.sendEmptyMessage(TRACK_ENDED); + } + + + private static final class QueueSaveHandler extends Handler { + @NonNull + private final WeakReference mService; + + QueueSaveHandler(final MusicService service, @NonNull final Looper looper) { + super(looper); + mService = new WeakReference<>(service); + } + + @Override + public void handleMessage(@NonNull Message msg) { + final MusicService service = mService.get(); + switch (msg.what) { + case SAVE_QUEUES: + service.saveQueuesImpl(); + break; + } + } + } + + private static final class PlaybackHandler extends Handler { + @NonNull + private final WeakReference mService; + private float currentDuckVolume = 1.0f; + + PlaybackHandler(final MusicService service, @NonNull final Looper looper) { + super(looper); + mService = new WeakReference<>(service); + } + + @Override + public void handleMessage(@NonNull final Message msg) { + final MusicService service = mService.get(); + if (service == null) { + return; + } + + switch (msg.what) { + case DUCK: + if (PreferenceUtil.getInstance().audioDucking()) { + currentDuckVolume -= .05f; + if (currentDuckVolume > .2f) { + sendEmptyMessageDelayed(DUCK, 10); + } else { + currentDuckVolume = .2f; + } + } else { + currentDuckVolume = 1f; + } + service.playback.setVolume(currentDuckVolume); + break; + + case UNDUCK: + if (PreferenceUtil.getInstance().audioDucking()) { + currentDuckVolume += .03f; + if (currentDuckVolume < 1f) { + sendEmptyMessageDelayed(UNDUCK, 10); + } else { + currentDuckVolume = 1f; + } + } else { + currentDuckVolume = 1f; + } + service.playback.setVolume(currentDuckVolume); + break; + + case TRACK_WENT_TO_NEXT: + if (service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) { + service.pause(); + service.seek(0); + } else { + service.position = service.nextPosition; + service.prepareNextImpl(); + service.notifyChange(META_CHANGED); + } + break; + + case TRACK_ENDED: + if (service.getRepeatMode() == REPEAT_MODE_NONE && service.isLastTrack()) { + service.notifyChange(PLAY_STATE_CHANGED); + service.seek(0); + } else { + service.playNextSong(false); + } + sendEmptyMessage(RELEASE_WAKELOCK); + break; + + case RELEASE_WAKELOCK: + service.releaseWakeLock(); + break; + + case PLAY_SONG: + service.playSongAtImpl(msg.arg1); + break; + + case SET_POSITION: + service.openTrackAndPrepareNextAt(msg.arg1); + service.notifyChange(PLAY_STATE_CHANGED); + break; + + case PREPARE_NEXT: + service.prepareNextImpl(); + break; + + case RESTORE_QUEUES: + service.restoreQueuesAndPositionIfNecessary(); + break; + + case FOCUS_CHANGE: + switch (msg.arg1) { + case AudioManager.AUDIOFOCUS_GAIN: + if (!service.isPlaying() && service.pausedByTransientLossOfFocus) { + service.play(); + service.pausedByTransientLossOfFocus = false; + } + removeMessages(DUCK); + sendEmptyMessage(UNDUCK); + break; + + case AudioManager.AUDIOFOCUS_LOSS: + // Lost focus for an unbounded amount of time: stop playback and release media playback + service.pause(); + break; + + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: + // Lost focus for a short time, but we have to stop + // playback. We don't release the media playback because playback + // is likely to resume + boolean wasPlaying = service.isPlaying(); + service.pause(); + service.pausedByTransientLossOfFocus = wasPlaying; + break; + + case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: + // Lost focus for a short time, but it's ok to keep playing + // at an attenuated level + removeMessages(UNDUCK); + sendEmptyMessage(DUCK); + break; + } + break; + } + } + } + + private static class SongPlayCountHelper { + public static final String TAG = SongPlayCountHelper.class.getSimpleName(); + + private StopWatch stopWatch = new StopWatch(); + private Song song = Song.Companion.getEmptySong(); + + public Song getSong() { + return song; + } + + boolean shouldBumpPlayCount() { + return song.getDuration() * 0.5d < stopWatch.getElapsedTime(); + } + + void notifySongChanged(Song song) { + synchronized (this) { + stopWatch.reset(); + this.song = song; + } + } + + void notifyPlayStateChanged(boolean isPlaying) { + synchronized (this) { + if (isPlaying) { + stopWatch.start(); + } else { + stopWatch.pause(); + } + } + } + } + + public class MusicBinder extends Binder { + @NonNull + public MusicService getService() { + return MusicService.this; + } + } + + private class MediaStoreObserver extends ContentObserver implements Runnable { + // milliseconds to delay before calling refresh to aggregate events + private static final long REFRESH_DELAY = 500; + private Handler mHandler; + + MediaStoreObserver(Handler handler) { + super(handler); + mHandler = handler; + } + + @Override + public void onChange(boolean selfChange) { + // if a change is detected, remove any scheduled callback + // then post a new one. This is intended to prevent closely + // spaced events from generating multiple refresh calls + mHandler.removeCallbacks(this); + mHandler.postDelayed(this, REFRESH_DELAY); + } + + @Override + public void run() { + // actually call refresh when the delayed callback fires + // do not send a sticky broadcast here + handleAndSendChangeInternal(MEDIA_STORE_CHANGED); + } + } + + private class ThrottledSeekHandler implements Runnable { + // milliseconds to throttle before calling run() to aggregate events + private static final long THROTTLE = 500; + private Handler mHandler; + + ThrottledSeekHandler(Handler handler) { + mHandler = handler; + } + + void notifySeek() { + mHandler.removeCallbacks(this); + mHandler.postDelayed(this, THROTTLE); + } + + @Override + public void run() { + savePositionInTrack(); + sendPublicIntent(PLAY_STATE_CHANGED); // for musixmatch synced lyrics + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt deleted file mode 100644 index 813385cf..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt +++ /dev/null @@ -1,1247 +0,0 @@ -package code.name.monkey.retromusic.service - -import android.annotation.SuppressLint -import android.app.PendingIntent -import android.app.Service -import android.content.* -import android.database.ContentObserver -import android.graphics.Bitmap -import android.graphics.drawable.Drawable -import android.media.AudioManager -import android.media.audiofx.AudioEffect -import android.media.session.MediaSession -import android.os.* -import android.preference.PreferenceManager -import android.provider.MediaStore -import android.support.v4.media.MediaMetadataCompat -import android.support.v4.media.session.MediaSessionCompat -import android.support.v4.media.session.PlaybackStateCompat -import android.telephony.PhoneStateListener -import android.telephony.TelephonyManager -import android.util.Log -import android.widget.Toast -import code.name.monkey.retromusic.Constants.ACTION_PAUSE -import code.name.monkey.retromusic.Constants.ACTION_PLAY -import code.name.monkey.retromusic.Constants.ACTION_PLAY_PLAYLIST -import code.name.monkey.retromusic.Constants.ACTION_QUIT -import code.name.monkey.retromusic.Constants.ACTION_SKIP -import code.name.monkey.retromusic.Constants.ACTION_STOP -import code.name.monkey.retromusic.Constants.ACTION_TOGGLE_PAUSE -import code.name.monkey.retromusic.Constants.APP_WIDGET_UPDATE -import code.name.monkey.retromusic.Constants.EXTRA_APP_WIDGET_NAME -import code.name.monkey.retromusic.Constants.INTENT_EXTRA_PLAYLIST -import code.name.monkey.retromusic.Constants.INTENT_EXTRA_SHUFFLE_MODE -import code.name.monkey.retromusic.Constants.MEDIA_STORE_CHANGED -import code.name.monkey.retromusic.Constants.META_CHANGED -import code.name.monkey.retromusic.Constants.MUSIC_PACKAGE_NAME -import code.name.monkey.retromusic.Constants.PLAY_STATE_CHANGED -import code.name.monkey.retromusic.Constants.QUEUE_CHANGED -import code.name.monkey.retromusic.Constants.REPEAT_MODE_CHANGED -import code.name.monkey.retromusic.Constants.RETRO_MUSIC_PACKAGE_NAME -import code.name.monkey.retromusic.Constants.SHUFFLE_MODE_CHANGED -import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.glide.BlurTransformation -import code.name.monkey.retromusic.glide.SongGlideRequest -import code.name.monkey.retromusic.helper.MusicPlayerRemote.setShuffleMode -import code.name.monkey.retromusic.helper.ShuffleHelper -import code.name.monkey.retromusic.helper.StopWatch -import code.name.monkey.retromusic.loaders.PlaylistSongsLoader -import code.name.monkey.retromusic.model.AbsCustomPlaylist -import code.name.monkey.retromusic.model.Playlist -import code.name.monkey.retromusic.model.Song -import code.name.monkey.retromusic.providers.HistoryStore -import code.name.monkey.retromusic.providers.MusicPlaybackQueueStore -import code.name.monkey.retromusic.providers.SongPlayCountStore -import code.name.monkey.retromusic.service.notification.PlayingNotification -import code.name.monkey.retromusic.service.notification.PlayingNotificationImpl24 -import code.name.monkey.retromusic.service.notification.PlayingNotificationOreo -import code.name.monkey.retromusic.service.playback.Playback -import code.name.monkey.retromusic.util.MusicUtil -import code.name.monkey.retromusic.util.PreferenceUtil -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.google.android.gms.cast.framework.media.MediaIntentReceiver.ACTION_REWIND -import java.lang.ref.WeakReference -import java.util.* - -/** - * @author Karim Abou Zeid (kabouzeid), Andrew Neal - */ -class MusicService : Service(), SharedPreferences.OnSharedPreferenceChangeListener, Playback.PlaybackCallbacks { - private val musicBind = MusicBinder() - private var playback: Playback? = null - var playingQueue = ArrayList() - private set - private var originalPlayingQueue = ArrayList() - var position = -1 - set(value) { - playerHandler!!.removeMessages(SET_POSITION) - playerHandler!!.obtainMessage(SET_POSITION, value, 0).sendToTarget() - } - private var nextPosition = -1 - var shuffleMode: Int = 0 - set(value) { - PreferenceManager.getDefaultSharedPreferences(this).edit() - .putInt(SAVED_SHUFFLE_MODE, value) - .apply() - when (value) { - SHUFFLE_MODE_SHUFFLE -> { - field = value - ShuffleHelper.makeShuffleList(this.playingQueue, position) - position = 0 - } - SHUFFLE_MODE_NONE -> { - field = value - val currentSongId = currentSong.id - playingQueue = ArrayList(originalPlayingQueue) - var newPosition = 0 - for (song in playingQueue) { - if (song.id == currentSongId) { - newPosition = playingQueue.indexOf(song) - } - } - position = newPosition - } - } - handleAndSendChangeInternal(SHUFFLE_MODE_CHANGED) - notifyChange(QUEUE_CHANGED) - } - var repeatMode: Int = 0 - set(value) { - when (value) { - REPEAT_MODE_NONE, REPEAT_MODE_ALL, REPEAT_MODE_THIS -> { - field = value - PreferenceManager.getDefaultSharedPreferences(this).edit() - .putInt(SAVED_REPEAT_MODE, repeatMode) - .apply() - prepareNext() - handleAndSendChangeInternal(REPEAT_MODE_CHANGED) - } - } - } - private var queuesRestored: Boolean = false - private var pausedByTransientLossOfFocus: Boolean = false - private val becomingNoisyReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - if (intent.action != null && intent.action == AudioManager.ACTION_AUDIO_BECOMING_NOISY) { - pause() - } - } - } - private var playingNotification: PlayingNotification? = null - private var audioManager: AudioManager? = null - var mediaSession: MediaSessionCompat? = null - private set - private var wakeLock: PowerManager.WakeLock? = null - private var playerHandler: PlaybackHandler? = null - private val audioFocusListener = AudioManager.OnAudioFocusChangeListener { focusChange -> playerHandler!!.obtainMessage(FOCUS_CHANGE, focusChange, 0).sendToTarget() } - private var queueSaveHandler: QueueSaveHandler? = null - private var musicPlayerHandlerThread: HandlerThread? = null - private var queueSaveHandlerThread: HandlerThread? = null - private val songPlayCountHelper = SongPlayCountHelper() - private var throttledSeekHandler: ThrottledSeekHandler? = null - private var becomingNoisyReceiverRegistered: Boolean = false - private val becomingNoisyReceiverIntentFilter = IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY) - private var mediaStoreObserver: ContentObserver? = null - private var notHandledMetaChangedForCurrentTrack: Boolean = false - private val phoneStateListener = object : PhoneStateListener() { - override fun onCallStateChanged(state: Int, incomingNumber: String) { - when (state) { - TelephonyManager.CALL_STATE_IDLE -> - //Not in call: Play music - play() - TelephonyManager.CALL_STATE_RINGING, TelephonyManager.CALL_STATE_OFFHOOK -> - //A call is dialing, active or on hold - pause() - } - super.onCallStateChanged(state, incomingNumber) - } - } - private var isServiceBound: Boolean = false - private var uiThreadHandler: Handler? = null - private val widgetIntentReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - val command = intent.getStringExtra(EXTRA_APP_WIDGET_NAME) - } - } - private val headsetReceiverIntentFilter = IntentFilter(Intent.ACTION_HEADSET_PLUG) - private var headsetReceiverRegistered = false - private val headsetReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - val action = intent.action - if (action != null) { - when (action) { - Intent.ACTION_HEADSET_PLUG -> { - val state = intent.getIntExtra("state", -1) - when (state) { - 0 -> { - Log.d(TAG, "Headset unplugged") - pause() - } - 1 -> { - Log.d(TAG, "Headset plugged") - play() - } - } - } - } - } - } - } - - val isPlaying: Boolean - get() = playback != null && playback!!.isPlaying - - val currentSong: Song - get() = getSongAt(position) - - private val isLastTrack: Boolean - get() = position == playingQueue.size - 1 - - val songProgressMillis: Int - get() = playback!!.position() - - val songDurationMillis: Int - get() = playback!!.duration() - - val audioSessionId: Int - get() = playback!!.audioSessionId - - - override fun onCreate() { - super.onCreate() - - val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager - telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE) - - val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager - wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, javaClass.name) - wakeLock!!.setReferenceCounted(false) - - musicPlayerHandlerThread = HandlerThread("PlaybackHandler") - musicPlayerHandlerThread!!.start() - playerHandler = PlaybackHandler(this, musicPlayerHandlerThread!!.looper) - - playback = MultiPlayer(this) - playback!!.setCallbacks(this) - - setupMediaSession() - - // queue saving needs to run on a separate thread so that it doesn't block the playback handler events - queueSaveHandlerThread = HandlerThread("QueueSaveHandler", Process.THREAD_PRIORITY_BACKGROUND) - queueSaveHandlerThread!!.start() - queueSaveHandler = QueueSaveHandler(this, queueSaveHandlerThread!!.looper) - - uiThreadHandler = Handler() - - registerReceiver(widgetIntentReceiver, IntentFilter(APP_WIDGET_UPDATE)) - - initNotification() - - mediaStoreObserver = MediaStoreObserver(playerHandler!!) - throttledSeekHandler = ThrottledSeekHandler(playerHandler!!) - contentResolver.registerContentObserver( - MediaStore.Audio.Media.INTERNAL_CONTENT_URI, true, mediaStoreObserver!!) - contentResolver.registerContentObserver( - MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, true, mediaStoreObserver!!) - - PreferenceUtil.getInstance().registerOnSharedPreferenceChangedListener(this) - - restoreState() - - mediaSession!!.isActive = true - - sendBroadcast(Intent("code.name.monkey.retromusic.RETRO_MUSIC_SERVICE_CREATED")) - - registerHeadsetEvents() - - - } - - private fun getAudioManager(): AudioManager? { - if (audioManager == null) { - audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager - } - return audioManager - } - - @SuppressLint("WrongConstant") - private fun setupMediaSession() { - val mediaButtonReceiverComponentName = ComponentName(applicationContext, MediaButtonIntentReceiver::class.java) - - val mediaButtonIntent = Intent(Intent.ACTION_MEDIA_BUTTON) - mediaButtonIntent.component = mediaButtonReceiverComponentName - - - val mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(applicationContext, 0, mediaButtonIntent, 0) - - mediaSession = MediaSessionCompat(this, "RetroMusicPlayer", mediaButtonReceiverComponentName, mediaButtonReceiverPendingIntent) - mediaSession!!.setCallback(object : MediaSessionCompat.Callback() { - override fun onPlay() { - play() - } - - override fun onPause() { - pause() - } - - override fun onSkipToNext() { - playNextSong(true) - } - - override fun onSkipToPrevious() { - back(true) - } - - override fun onStop() { - quit() - } - - override fun onSeekTo(pos: Long) { - seek(pos.toInt()) - } - - override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean { - return MediaButtonIntentReceiver.handleIntent(this@MusicService, mediaButtonEvent) - } - }) - - mediaSession!!.setFlags(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS or MediaSession.FLAG_HANDLES_MEDIA_BUTTONS) - - mediaSession!!.setMediaButtonReceiver(mediaButtonReceiverPendingIntent) - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - if (intent != null) { - if (intent.action != null) { - restoreQueuesAndPositionIfNecessary() - val action = intent.action - when (action) { - ACTION_TOGGLE_PAUSE -> if (isPlaying) { - pause() - } else { - play() - } - ACTION_PAUSE -> pause() - ACTION_PLAY -> play() - ACTION_PLAY_PLAYLIST -> { - val playlist = intent.getParcelableExtra(INTENT_EXTRA_PLAYLIST) - val shuffleMode = intent.getIntExtra(INTENT_EXTRA_SHUFFLE_MODE, shuffleMode) - if (playlist != null) { - val playlistSongs: ArrayList - if (playlist is AbsCustomPlaylist) { - playlistSongs = playlist.getSongs(applicationContext).blockingFirst() - } else { - - playlistSongs = PlaylistSongsLoader.getPlaylistSongList(applicationContext, playlist.id).blockingFirst() - } - if (!playlistSongs.isEmpty()) { - if (shuffleMode == SHUFFLE_MODE_SHUFFLE) { - val startPosition: Int = Random().nextInt(playlistSongs.size) - openQueue(playlistSongs, startPosition, true) - setShuffleMode(shuffleMode) - } else { - openQueue(playlistSongs, 0, true) - } - } else { - Toast.makeText(applicationContext, R.string.playlist_is_empty, Toast.LENGTH_LONG).show() - } - } else { - Toast.makeText(applicationContext, R.string.playlist_is_empty, Toast.LENGTH_LONG).show() - } - } - ACTION_REWIND -> back(true) - ACTION_SKIP -> playNextSong(true) - ACTION_STOP, ACTION_QUIT -> return quit() - } - } - } - - return Service.START_STICKY - } - - - override fun onDestroy() { - unregisterReceiver(widgetIntentReceiver) - if (becomingNoisyReceiverRegistered) { - unregisterReceiver(becomingNoisyReceiver) - becomingNoisyReceiverRegistered = false - } - if (headsetReceiverRegistered) { - unregisterReceiver(headsetReceiver) - headsetReceiverRegistered = false - } - mediaSession!!.isActive = false - quit() - releaseResources() - contentResolver.unregisterContentObserver(mediaStoreObserver!!) - PreferenceUtil.getInstance().unregisterOnSharedPreferenceChangedListener(this) - wakeLock!!.release() - - sendBroadcast(Intent("code.name.monkey.retromusic.RETRO_MUSIC_MUSIC_SERVICE_DESTROYED")) - } - - override fun onBind(intent: Intent): IBinder? { - isServiceBound = true - return musicBind - } - - override fun onRebind(intent: Intent) { - isServiceBound = true - } - - override fun onUnbind(intent: Intent): Boolean { - isServiceBound = false - if (!isPlaying) { - stopSelf() - } - return true - } - - private fun saveQueuesImpl() { - MusicPlaybackQueueStore.getInstance(this).saveQueues(playingQueue, originalPlayingQueue) - } - - private fun savePosition() { - PreferenceManager.getDefaultSharedPreferences(this).edit().putInt(SAVED_POSITION, position).apply() - } - - private fun savePositionInTrack() { - PreferenceManager.getDefaultSharedPreferences(this).edit().putInt(SAVED_POSITION_IN_TRACK, songProgressMillis).apply() - } - - private fun saveState() { - saveQueues() - savePosition() - savePositionInTrack() - } - - private fun saveQueues() { - queueSaveHandler!!.removeMessages(SAVE_QUEUES) - queueSaveHandler!!.sendEmptyMessage(SAVE_QUEUES) - } - - private fun restoreState() { - shuffleMode = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_SHUFFLE_MODE, 0) - repeatMode = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_REPEAT_MODE, 0) - handleAndSendChangeInternal(SHUFFLE_MODE_CHANGED) - handleAndSendChangeInternal(REPEAT_MODE_CHANGED) - - playerHandler!!.removeMessages(RESTORE_QUEUES) - playerHandler!!.sendEmptyMessage(RESTORE_QUEUES) - } - - @Synchronized - private fun restoreQueuesAndPositionIfNecessary() { - if (!queuesRestored && playingQueue.isEmpty()) { - val restoredQueue = MusicPlaybackQueueStore.getInstance(this).savedPlayingQueue - .blockingFirst() - - val restoredOriginalQueue = MusicPlaybackQueueStore.getInstance(this).savedOriginalPlayingQueue - .blockingFirst() - - val restoredPosition = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_POSITION, -1) - val restoredPositionInTrack = PreferenceManager.getDefaultSharedPreferences(this).getInt(SAVED_POSITION_IN_TRACK, -1) - - if (restoredQueue.size > 0 && restoredQueue.size == restoredOriginalQueue.size && restoredPosition != -1) { - this.originalPlayingQueue = restoredOriginalQueue - this.playingQueue = restoredQueue - - position = restoredPosition - openCurrent() - prepareNext() - - if (restoredPositionInTrack > 0) seek(restoredPositionInTrack) - - notHandledMetaChangedForCurrentTrack = true - sendChangeInternal(META_CHANGED) - sendChangeInternal(QUEUE_CHANGED) - } - } - queuesRestored = true - } - - @SuppressLint("WrongConstant") - private fun quit(): Int { - pause() - playingNotification!!.stop() - - if (isServiceBound) { - return Service.START_STICKY - } else { - closeAudioEffectSession() - getAudioManager()!!.abandonAudioFocus(audioFocusListener) - stopSelf() - return Service.START_NOT_STICKY - } - } - - private fun releaseResources() { - playerHandler!!.removeCallbacksAndMessages(null) - musicPlayerHandlerThread!!.quitSafely() - queueSaveHandler!!.removeCallbacksAndMessages(null) - queueSaveHandlerThread!!.quitSafely() - playback!!.release() - playback = null - mediaSession!!.release() - } - - fun playNextSong(force: Boolean) { - playSongAt(getNextPosition(force)) - } - - private fun openTrackAndPrepareNextAt(position: Int): Boolean { - synchronized(this) { - this.position = position - val prepared = openCurrent() - if (prepared) prepareNextImpl() - notifyChange(META_CHANGED) - notHandledMetaChangedForCurrentTrack = false - return prepared - } - } - - private fun openCurrent(): Boolean { - synchronized(this) { - try { - return playback!!.setDataSource(getTrackUri(currentSong)) - } catch (e: Exception) { - return false - } - - } - } - - private fun prepareNext() { - playerHandler!!.removeMessages(PREPARE_NEXT) - playerHandler!!.obtainMessage(PREPARE_NEXT).sendToTarget() - } - - private fun prepareNextImpl(): Boolean { - synchronized(this) { - return try { - val nextPosition = getNextPosition(false) - playback!!.setNextDataSource(getTrackUri(getSongAt(nextPosition))) - this.nextPosition = nextPosition - true - } catch (e: Exception) { - false - } - - } - } - - private fun closeAudioEffectSession() { - val audioEffectsIntent = Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION) - audioEffectsIntent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, playback!!.audioSessionId) - audioEffectsIntent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, packageName) - sendBroadcast(audioEffectsIntent) - } - - private fun requestFocus(): Boolean { - return getAudioManager()!!.requestAudioFocus(audioFocusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED - } - - fun initNotification() { - playingNotification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && !PreferenceUtil.getInstance().classicNotification()) { - PlayingNotificationImpl24() - } else { - PlayingNotificationOreo() - } - playingNotification!!.init(this) - } - - fun updateNotification() { - if (playingNotification != null && currentSong.id != -1) { - playingNotification!!.update() - } - } - - private fun updateMediaSessionPlaybackState() { - mediaSession!!.setPlaybackState( - PlaybackStateCompat.Builder() - .setActions(MEDIA_SESSION_ACTIONS) - .setState(if (isPlaying) PlaybackStateCompat.STATE_PLAYING else PlaybackStateCompat.STATE_PAUSED, - position.toLong(), 1f) - .build()) - } - - private fun updateMediaSessionMetaData() { - val song = currentSong - - if (song.id == -1) { - mediaSession!!.setMetadata(null) - return - } - - val metaData = MediaMetadataCompat.Builder() - .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, song.artistName) - .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, song.artistName) - .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, song.albumName) - .putString(MediaMetadataCompat.METADATA_KEY_TITLE, song.title) - .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, song.duration) - .putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, (position + 1).toLong()) - .putLong(MediaMetadataCompat.METADATA_KEY_YEAR, song.year.toLong()) - .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, null) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - metaData.putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, playingQueue.size.toLong()) - } - - if (PreferenceUtil.getInstance().albumArtOnLockscreen()) { - val screenSize = RetroUtil.getScreenSize(this@MusicService) - val request = SongGlideRequest.Builder.from(Glide.with(this@MusicService), song) - .checkIgnoreMediaStore(this@MusicService) - .asBitmap().build() - if (PreferenceUtil.getInstance().blurredAlbumArt()) { - request.transform(BlurTransformation.Builder(this@MusicService).build()) - } - runOnUiThread(Runnable { - request.into(object : SimpleTarget(screenSize.x, screenSize.y) { - override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) { - super.onLoadFailed(e, errorDrawable) - mediaSession!!.setMetadata(metaData.build()) - } - - override fun onResourceReady(resource: Bitmap, glideAnimation: GlideAnimation) { - metaData.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, copy(resource)) - mediaSession!!.setMetadata(metaData.build()) - } - }) - }) - } else { - mediaSession!!.setMetadata(metaData.build()) - } - } - - fun runOnUiThread(runnable: Runnable) { - uiThreadHandler!!.post(runnable) - } - - private fun getSongAt(position: Int): Song { - return if (position >= 0 && position < playingQueue.size) { - playingQueue[position] - } else { - Song.EMPTY_SONG - } - } - - private fun getNextPosition(force: Boolean): Int { - var position = position + 1 - when (repeatMode) { - REPEAT_MODE_ALL -> if (isLastTrack) { - position = 0 - } - REPEAT_MODE_THIS -> if (force) { - if (isLastTrack) { - position = 0 - } - } else { - position -= 1 - } - REPEAT_MODE_NONE -> if (isLastTrack) { - position -= 1 - } - else -> if (isLastTrack) { - position -= 1 - } - } - return position - } - - - fun openQueue(playingQueue: ArrayList?, startPosition: Int, startPlaying: Boolean) { - if (playingQueue != null && !playingQueue.isEmpty() && startPosition >= 0 && startPosition < playingQueue.size) { - // it is important to copy the playing queue here first as we might add/remove songs later - originalPlayingQueue = ArrayList(playingQueue) - this.playingQueue = ArrayList(originalPlayingQueue) - - var position = startPosition - if (shuffleMode == SHUFFLE_MODE_SHUFFLE) { - ShuffleHelper.makeShuffleList(this.playingQueue, startPosition) - position = 0 - } - if (startPlaying) { - playSongAt(position) - } else { - this.position = position - } - notifyChange(QUEUE_CHANGED) - } - } - - fun addSong(position: Int, song: Song) { - playingQueue.add(position, song) - originalPlayingQueue.add(position, song) - notifyChange(QUEUE_CHANGED) - } - - fun addSong(song: Song) { - playingQueue.add(song) - originalPlayingQueue.add(song) - notifyChange(QUEUE_CHANGED) - } - - fun addSongs(position: Int, songs: List) { - playingQueue.addAll(position, songs) - originalPlayingQueue.addAll(position, songs) - notifyChange(QUEUE_CHANGED) - } - - fun addSongs(songs: List) { - playingQueue.addAll(songs) - originalPlayingQueue.addAll(songs) - notifyChange(QUEUE_CHANGED) - } - - fun removeSong(position: Int) { - if (shuffleMode == SHUFFLE_MODE_NONE) { - playingQueue.removeAt(position) - originalPlayingQueue.removeAt(position) - } else { - originalPlayingQueue.remove(playingQueue.removeAt(position)) - } - - rePosition(position) - - notifyChange(QUEUE_CHANGED) - } - - fun removeSong(song: Song) { - for (i in playingQueue.indices) { - if (playingQueue[i].id == song.id) { - playingQueue.removeAt(i) - rePosition(i) - } - } - for (i in originalPlayingQueue.indices) { - if (originalPlayingQueue[i].id == song.id) { - originalPlayingQueue.removeAt(i) - } - } - notifyChange(QUEUE_CHANGED) - } - - private fun rePosition(deletedPosition: Int) { - val currentPosition = position - if (deletedPosition < currentPosition) { - position = currentPosition - 1 - } else if (deletedPosition == currentPosition) { - if (playingQueue.size > deletedPosition) { - this.position = position - } else { - this.position = position - 1 - } - } - } - - fun moveSong(from: Int, to: Int) { - if (from == to) return - val currentPosition = position - val songToMove = playingQueue.removeAt(from) - playingQueue.add(to, songToMove) - if (shuffleMode == SHUFFLE_MODE_NONE) { - val tmpSong = originalPlayingQueue.removeAt(from) - originalPlayingQueue.add(to, tmpSong) - } - if (currentPosition in to..(from - 1)) { - position = currentPosition + 1 - } else if (currentPosition in (from + 1)..to) { - position = currentPosition - 1 - } else if (from == currentPosition) { - position = to - } - notifyChange(QUEUE_CHANGED) - } - - fun clearQueue() { - playingQueue.clear() - originalPlayingQueue.clear() - - position = -1 - notifyChange(QUEUE_CHANGED) - } - - fun playSongAt(position: Int) { - // handle this on the handlers thread to avoid blocking the ui thread - playerHandler!!.removeMessages(PLAY_SONG) - playerHandler!!.obtainMessage(PLAY_SONG, position, 0).sendToTarget() - } - - private fun playSongAtImpl(position: Int) { - if (openTrackAndPrepareNextAt(position)) { - play() - } else { - Toast.makeText(this, resources.getString(R.string.unplayable_file), Toast.LENGTH_SHORT).show() - } - } - - fun pause() { - pausedByTransientLossOfFocus = false - if (playback!!.isPlaying) { - playback!!.pause() - notifyChange(PLAY_STATE_CHANGED) - } - } - - fun play() { - synchronized(this) { - if (requestFocus()) { - if (!playback!!.isPlaying) { - if (!playback!!.isInitialized) { - playSongAt(position) - } else { - playback!!.start() - if (!becomingNoisyReceiverRegistered) { - registerReceiver(becomingNoisyReceiver, becomingNoisyReceiverIntentFilter) - becomingNoisyReceiverRegistered = true - } - if (notHandledMetaChangedForCurrentTrack) { - handleChangeInternal(META_CHANGED) - notHandledMetaChangedForCurrentTrack = false - } - notifyChange(PLAY_STATE_CHANGED) - - // fixes a bug where the volume would stay ducked because the AudioManager.AUDIOFOCUS_GAIN event is not sent - playerHandler!!.removeMessages(DUCK) - playerHandler!!.sendEmptyMessage(UN_DUCK) - } - } - } else { - Toast.makeText(this, resources.getString(R.string.audio_focus_denied), Toast.LENGTH_SHORT).show() - } - } - } - - fun playSongs(songs: ArrayList?, shuffleMode: Int) { - if (songs != null && !songs.isEmpty()) { - if (shuffleMode == SHUFFLE_MODE_SHUFFLE) { - var startPosition = 0 - if (!songs.isEmpty()) { - startPosition = Random().nextInt(songs.size) - } - openQueue(songs, startPosition, false) - setShuffleMode(shuffleMode) - } else { - openQueue(songs, 0, false) - } - play() - } else { - Toast.makeText(applicationContext, R.string.playlist_is_empty, Toast.LENGTH_LONG).show() - } - } - - fun playPreviousSong(force: Boolean) { - playSongAt(getPreviousPosition(force)) - } - - fun back(force: Boolean) { - if (songProgressMillis > 2000) { - seek(0) - } else { - playPreviousSong(force) - } - } - - private fun getPreviousPosition(force: Boolean): Int { - var newPosition = position - 1 - when (repeatMode) { - REPEAT_MODE_ALL -> if (newPosition < 0) { - newPosition = playingQueue.size - 1 - } - REPEAT_MODE_THIS -> if (force) { - if (newPosition < 0) { - newPosition = playingQueue.size - 1 - } - } else { - newPosition = position - } - REPEAT_MODE_NONE -> if (newPosition < 0) { - newPosition = 0 - } - else -> if (newPosition < 0) { - newPosition = 0 - } - } - return newPosition - } - - fun getQueueDurationMillis(position: Int): Long { - var duration: Long = 0 - for (i in position + 1 until playingQueue.size) - duration += playingQueue[i].duration - return duration - } - - fun seek(millis: Int): Int { - synchronized(this) { - try { - val newPosition = playback!!.seek(millis) - throttledSeekHandler!!.notifySeek() - return newPosition - } catch (e: Exception) { - return -1 - } - - } - } - - fun cycleRepeatMode() { - repeatMode = when (repeatMode) { - REPEAT_MODE_NONE -> REPEAT_MODE_ALL - REPEAT_MODE_ALL -> REPEAT_MODE_THIS - else -> REPEAT_MODE_NONE - } - } - - fun toggleShuffle() { - if (shuffleMode == SHUFFLE_MODE_NONE) { - setShuffleMode(SHUFFLE_MODE_SHUFFLE) - } else { - setShuffleMode(SHUFFLE_MODE_NONE) - } - } - - - private fun notifyChange(what: String) { - handleAndSendChangeInternal(what) - sendPublicIntent(what) - } - - private fun handleAndSendChangeInternal(what: String) { - handleChangeInternal(what) - sendChangeInternal(what) - } - - // to let other apps know whats playing. i.E. last.fm (scrobbling) or musixmatch - @SuppressLint("WrongConstant") - private fun sendPublicIntent(what: String) { - val intent = Intent(what.replace(RETRO_MUSIC_PACKAGE_NAME, MUSIC_PACKAGE_NAME)) - - val song = currentSong - - intent.putExtra("id", song.id) - intent.putExtra("artist", song.artistName) - intent.putExtra("album", song.albumName) - intent.putExtra("track", song.title) - intent.putExtra("duration", song.duration) - intent.putExtra("position", songProgressMillis.toLong()) - intent.putExtra("playing", isPlaying) - intent.putExtra("scrobbling_source", RETRO_MUSIC_PACKAGE_NAME) - - sendStickyBroadcast(intent) - - } - - private fun sendChangeInternal(what: String) { - sendBroadcast(Intent(what)) - } - - private fun handleChangeInternal(what: String) { - when (what) { - PLAY_STATE_CHANGED -> { - updateNotification() - updateMediaSessionPlaybackState() - val isPlaying = isPlaying - if (!isPlaying && songProgressMillis > 0) { - savePositionInTrack() - } - songPlayCountHelper.notifyPlayStateChanged(isPlaying) - } - META_CHANGED -> { - updateNotification() - updateMediaSessionMetaData() - savePosition() - savePositionInTrack() - val currentSong = currentSong - HistoryStore.getInstance(this).addSongId(currentSong.id.toLong()) - if (songPlayCountHelper.shouldBumpPlayCount()) { - SongPlayCountStore.getInstance(this).bumpPlayCount(songPlayCountHelper.song.id.toLong()) - } - songPlayCountHelper.notifySongChanged(currentSong) - } - QUEUE_CHANGED -> { - updateMediaSessionMetaData() // because playing queue size might have changed - saveState() - if (playingQueue.size > 0) { - prepareNext() - } else { - playingNotification!!.stop() - } - } - } - } - - fun releaseWakeLock() { - if (wakeLock!!.isHeld) { - wakeLock!!.release() - } - } - - private fun acquireWakeLock(milli: Long) { - wakeLock!!.acquire(milli) - } - - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { - when (key) { - PreferenceUtil.GAPLESS_PLAYBACK -> if (sharedPreferences.getBoolean(key, false)) { - prepareNext() - } else { - playback!!.setNextDataSource(null) - } - PreferenceUtil.ALBUM_ART_ON_LOCKSCREEN, PreferenceUtil.BLURRED_ALBUM_ART -> updateMediaSessionMetaData() - PreferenceUtil.COLORED_NOTIFICATION, PreferenceUtil.DOMINANT_COLOR -> updateNotification() - PreferenceUtil.CLASSIC_NOTIFICATION -> { - initNotification() - updateNotification() - } - PreferenceUtil.TOGGLE_HEADSET -> registerHeadsetEvents() - } - } - - private fun registerHeadsetEvents() { - if (!headsetReceiverRegistered && PreferenceUtil.getInstance().headsetPlugged) { - registerReceiver(headsetReceiver, headsetReceiverIntentFilter) - headsetReceiverRegistered = true - } - } - - override fun onTrackWentToNext() { - playerHandler!!.sendEmptyMessage(TRACK_WENT_TO_NEXT) - } - - override fun onTrackEnded() { - acquireWakeLock(30000) - playerHandler!!.sendEmptyMessage(TRACK_ENDED) - } - - - inner class QueueSaveHandler internal constructor(service: MusicService, looper: Looper) : Handler(looper) { - val mService: WeakReference = WeakReference(service) - - override fun handleMessage(msg: Message) { - val service = mService.get() - when (msg.what) { - SAVE_QUEUES -> service!!.saveQueuesImpl() - } - } - } - - inner class PlaybackHandler internal constructor(service: MusicService, looper: Looper) : Handler(looper) { - val mService: WeakReference = WeakReference(service) - var currentDuckVolume = 1.0f - - override fun handleMessage(msg: Message) { - val service = mService.get() ?: return - - when (msg.what) { - DUCK -> { - if (PreferenceUtil.getInstance().audioDucking()) { - currentDuckVolume -= .05f - if (currentDuckVolume > .2f) { - sendEmptyMessageDelayed(DUCK, 10) - } else { - currentDuckVolume = .2f - } - } else { - currentDuckVolume = 1f - } - service.playback!!.setVolume(currentDuckVolume) - } - - UN_DUCK -> { - if (PreferenceUtil.getInstance().audioDucking()) { - currentDuckVolume += .03f - if (currentDuckVolume < 1f) { - sendEmptyMessageDelayed(UN_DUCK, 10) - } else { - currentDuckVolume = 1f - } - } else { - currentDuckVolume = 1f - } - service.playback!!.setVolume(currentDuckVolume) - } - - TRACK_WENT_TO_NEXT -> if (service.repeatMode == REPEAT_MODE_NONE && service.isLastTrack) { - service.pause() - service.seek(0) - } else { - service.position = service.nextPosition - service.prepareNextImpl() - service.notifyChange(META_CHANGED) - } - - TRACK_ENDED -> { - if (service.repeatMode == REPEAT_MODE_NONE && service.isLastTrack) { - service.notifyChange(PLAY_STATE_CHANGED) - service.seek(0) - } else { - service.playNextSong(false) - } - sendEmptyMessage(RELEASE_WAKELOCK) - } - - RELEASE_WAKELOCK -> service.releaseWakeLock() - - PLAY_SONG -> service.playSongAtImpl(msg.arg1) - - SET_POSITION -> { - service.openTrackAndPrepareNextAt(msg.arg1) - service.notifyChange(PLAY_STATE_CHANGED) - } - - PREPARE_NEXT -> service.prepareNextImpl() - - RESTORE_QUEUES -> service.restoreQueuesAndPositionIfNecessary() - - FOCUS_CHANGE -> when (msg.arg1) { - AudioManager.AUDIOFOCUS_GAIN -> { - if (!service.isPlaying && service.pausedByTransientLossOfFocus) { - service.play() - service.pausedByTransientLossOfFocus = false - } - removeMessages(DUCK) - sendEmptyMessage(UN_DUCK) - } - - AudioManager.AUDIOFOCUS_LOSS -> - // Lost focus for an unbounded amount of time: stop playback and release media playback - service.pause() - - AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { - // Lost focus for a short time, but we have to stop - // playback. We don't release the media playback because playback - // is likely to resume - val wasPlaying = service.isPlaying - service.pause() - service.pausedByTransientLossOfFocus = wasPlaying - } - - AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { - // Lost focus for a short time, but it's ok to keep playing - // at an attenuated level - removeMessages(UN_DUCK) - sendEmptyMessage(DUCK) - } - } - } - } - } - - inner class SongPlayCountHelper { - - private val stopWatch = StopWatch() - var song = Song.EMPTY_SONG - private set - - internal fun shouldBumpPlayCount(): Boolean { - return song.duration * 0.5 < stopWatch.elapsedTime - } - - internal fun notifySongChanged(song: Song) { - synchronized(this) { - stopWatch.reset() - this.song = song - } - } - - internal fun notifyPlayStateChanged(isPlaying: Boolean) { - synchronized(this) { - if (isPlaying) { - stopWatch.start() - } else { - stopWatch.pause() - } - } - } - } - - inner class MusicBinder : Binder() { - val service: MusicService - get() = this@MusicService - } - - inner class MediaStoreObserver internal constructor(private val mHandler: Handler) : ContentObserver(mHandler), Runnable { - - override fun onChange(selfChange: Boolean) { - // if a change is detected, remove any scheduled callback - // then post a new one. This is intended to prevent closely - // spaced events from generating multiple refresh calls - mHandler.removeCallbacks(this) - mHandler.postDelayed(this, 500) - } - - override fun run() { - // actually call refresh when the delayed callback fires - // do not send a sticky broadcast here - handleAndSendChangeInternal(MEDIA_STORE_CHANGED) - } - } - - inner class ThrottledSeekHandler internal constructor(private val mHandler: Handler) : Runnable { - - internal fun notifySeek() { - mHandler.removeCallbacks(this) - mHandler.postDelayed(this, 500) - } - - override fun run() { - savePositionInTrack() - sendPublicIntent(PLAY_STATE_CHANGED) // for musixmatch synced lyrics - } - } - - companion object { - val TAG: String = MusicService::class.java.simpleName - - const val SAVED_POSITION = "POSITION" - const val SAVED_POSITION_IN_TRACK = "POSITION_IN_TRACK" - const val SAVED_SHUFFLE_MODE = "SHUFFLE_MODE" - const val SAVED_REPEAT_MODE = "REPEAT_MODE" - - const val RELEASE_WAKELOCK = 0 - const val TRACK_ENDED = 1 - const val TRACK_WENT_TO_NEXT = 2 - const val PLAY_SONG = 3 - const val PREPARE_NEXT = 4 - const val SET_POSITION = 5 - const val RESTORE_QUEUES = 9 - const val SHUFFLE_MODE_NONE = 0 - const val SHUFFLE_MODE_SHUFFLE = 1 - const val REPEAT_MODE_NONE = 0 - const val REPEAT_MODE_ALL = 1 - const val REPEAT_MODE_THIS = 2 - const val SAVE_QUEUES = 0 - const val FOCUS_CHANGE = 6 - const val DUCK = 7 - const val UN_DUCK = 8 - const val MEDIA_SESSION_ACTIONS = (PlaybackStateCompat.ACTION_PLAY - or PlaybackStateCompat.ACTION_PAUSE - or PlaybackStateCompat.ACTION_PLAY_PAUSE - or PlaybackStateCompat.ACTION_SKIP_TO_NEXT - or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS - or PlaybackStateCompat.ACTION_STOP - or PlaybackStateCompat.ACTION_SEEK_TO) - - private fun getTrackUri(song: Song): String { - return MusicUtil.getSongFileUri(song.id).toString() - } - - private fun copy(bitmap: Bitmap): Bitmap? { - var config: Bitmap.Config? = bitmap.config - if (config == null) { - config = Bitmap.Config.RGB_565 - } - try { - return bitmap.copy(config, false) - } catch (e: OutOfMemoryError) { - e.printStackTrace() - return null - } - - } - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/AlbumDetailsActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/AlbumDetailsActivity.kt index af628a2c..1876a809 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/AlbumDetailsActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/AlbumDetailsActivity.kt @@ -13,7 +13,6 @@ import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import butterknife.ButterKnife -import butterknife.OnClick import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.TintHelper @@ -49,9 +48,9 @@ import java.util.* class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsContract.AlbumDetailsView { - private var albumDetailsPresenter: AlbumDetailsPresenter? = null + private lateinit var albumDetailsPresenter: AlbumDetailsPresenter + private lateinit var simpleSongAdapter: SimpleSongAdapter - private var adapter: SimpleSongAdapter? = null var album: Album? = null private set @@ -82,13 +81,12 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsContrac val albumId = intent.getIntExtra(EXTRA_ALBUM_ID, -1) albumDetailsPresenter = AlbumDetailsPresenter(this, albumId) - albumDetailsPresenter!!.subscribe() + albumDetailsPresenter.subscribe() setupRecyclerView() setupToolbarMarginHeight() - - contentContainer.setOnScrollChangeListener { v: NestedScrollView?, scrollX: Int, scrollY: Int, oldScrollX: Int, oldScrollY: Int -> + contentContainer.setOnScrollChangeListener { _: NestedScrollView?, _: Int, scrollY: Int, _: Int, oldScrollY: Int -> run { if (scrollY > oldScrollY) { actionShuffleAll!!.setShowTitle(false) @@ -98,31 +96,40 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsContrac } } } + + actionShuffleAll.setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(album!!.songs!!, true) } + artistImage.setOnClickListener { + val artistPairs = arrayOf>(Pair.create(image, resources.getString(R.string.transition_artist_image))) + NavigationUtil.goToArtist(this, album!!.artistId, *artistPairs) + } } private fun setupRecyclerView() { - adapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song) + simpleSongAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song) recyclerView.apply { layoutManager = LinearLayoutManager(this@AlbumDetailsActivity) itemAnimator = DefaultItemAnimator() isNestedScrollingEnabled = false - adapter = adapter + adapter = simpleSongAdapter } } private fun setupToolbarMarginHeight() { - val primaryColor = ThemeStore.primaryColor(this) - TintHelper.setTintAuto(contentContainer!!, primaryColor, true) - if (collapsingToolbarLayout != null) { - collapsingToolbarLayout!!.setContentScrimColor(primaryColor) - collapsingToolbarLayout!!.setStatusBarScrimColor(ColorUtil.darkenColor(primaryColor)) - } - - toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp) setSupportActionBar(toolbar) - supportActionBar!!.title = null + val primaryColor = ThemeStore.primaryColor(this) + TintHelper.setTintAuto(contentContainer!!, primaryColor, true) + + if (collapsingToolbarLayout != null) { + collapsingToolbarLayout!!.apply { + setContentScrimColor(primaryColor) + setStatusBarScrimColor(ColorUtil.darkenColor(primaryColor)) + } + } + + + toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp) if (toolbar != null && !PreferenceUtil.getInstance().fullScreenMode) { val params = toolbar!!.layoutParams as ViewGroup.MarginLayoutParams @@ -131,45 +138,29 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsContrac } if (appBarLayout != null) { - appBarLayout!!.addOnOffsetChangedListener(object : AppBarStateChangeListener() { - override fun onStateChanged(appBarLayout: AppBarLayout, state: AppBarStateChangeListener.State) { - val color: Int - when (state) { - AppBarStateChangeListener.State.COLLAPSED -> { - setLightStatusbar(ColorUtil.isColorLight(ThemeStore.primaryColor(this@AlbumDetailsActivity))) - color = ThemeStore.primaryColor(this@AlbumDetailsActivity) - } - AppBarStateChangeListener.State.EXPANDED, AppBarStateChangeListener.State.IDLE -> { - setLightStatusbar(false) - color = Color.TRANSPARENT - } - else -> { - setLightStatusbar(false) - color = Color.TRANSPARENT + appBarLayout!!.apply { + addOnOffsetChangedListener(object : AppBarStateChangeListener() { + override fun onStateChanged(appBarLayout: AppBarLayout, state: AppBarStateChangeListener.State) { + val color: Int = when (state) { + AppBarStateChangeListener.State.COLLAPSED -> { + setLightStatusbar(ColorUtil.isColorLight(ThemeStore.primaryColor(this@AlbumDetailsActivity))) + ThemeStore.primaryColor(this@AlbumDetailsActivity) + } + AppBarStateChangeListener.State.EXPANDED, AppBarStateChangeListener.State.IDLE -> { + setLightStatusbar(false) + Color.TRANSPARENT + } } + ToolbarContentTintHelper.setToolbarContentColorBasedOnToolbarColor(this@AlbumDetailsActivity, toolbar, color) } - ToolbarContentTintHelper.setToolbarContentColorBasedOnToolbarColor(this@AlbumDetailsActivity, toolbar, color) - } - }) - } - } - - @OnClick(R.id.action_shuffle_all, R.id.artist_image) - fun onViewClicked(view: View) { - when (view.id) { - R.id.artist_image -> { - val artistPairs = arrayOf>(Pair.create(image, resources.getString(R.string.transition_artist_image))) - NavigationUtil.goToArtist(this, album!!.artistId, *artistPairs) - } - R.id.action_shuffle_all -> if (album!!.songs != null) { - MusicPlayerRemote.openAndShuffleQueue(album!!.songs!!, true) + }) } } } override fun onPause() { super.onPause() - albumDetailsPresenter!!.unsubscribe() + albumDetailsPresenter.unsubscribe() } override fun loading() { @@ -196,7 +187,8 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsContrac loadAlbumCover() loadMoreFrom(album) - adapter!!.swapDataSet(album.songs) + + simpleSongAdapter.swapDataSet(album.songs) } private fun loadMoreFrom(album: Album) { @@ -213,20 +205,19 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsContrac }) } - val albums = ArtistLoader.getArtist(this, album.artistId) - .blockingFirst().albums + val albums = ArtistLoader.getArtist(this, album.artistId).blockingFirst().albums albums!!.remove(album) if (!albums.isEmpty()) { moreTitle.visibility = View.VISIBLE - moreRecyclerView!!.visibility = View.VISIBLE + moreRecyclerView.visibility = View.VISIBLE } else { return } moreTitle.text = String.format("More from %s", album.artistName) val albumAdapter = HorizontalAlbumAdapter(this, albums, false, null) - moreRecyclerView!!.layoutManager = GridLayoutManager(this, 1, GridLayoutManager.HORIZONTAL, false) - moreRecyclerView!!.adapter = albumAdapter + moreRecyclerView.layoutManager = GridLayoutManager(this, 1, GridLayoutManager.HORIZONTAL, false) + moreRecyclerView.adapter = albumAdapter } private fun loadAlbumCover() { @@ -262,7 +253,7 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsContrac private fun handleSortOrderMenuItem(item: MenuItem): Boolean { var sortOrder: String? = null - val songs = adapter!!.dataSet + val songs = simpleSongAdapter.dataSet when (item.itemId) { R.id.action_play_next -> { MusicPlayerRemote.playNext(songs) @@ -327,7 +318,7 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsContrac } private fun reload() { - albumDetailsPresenter!!.subscribe() + albumDetailsPresenter.subscribe() } companion object { diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/ArtistDetailActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/ArtistDetailActivity.java deleted file mode 100755 index 6bf6346e..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/ArtistDetailActivity.java +++ /dev/null @@ -1,458 +0,0 @@ -package code.name.monkey.retromusic.ui.activities; - -import android.content.Intent; -import android.content.res.ColorStateList; -import android.graphics.Color; -import android.os.Bundle; -import android.text.Html; -import android.text.Spanned; -import android.transition.Slide; -import android.view.Gravity; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; -import android.view.animation.AnimationUtils; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; - -import com.bumptech.glide.Glide; -import com.google.android.material.appbar.AppBarLayout; -import com.google.android.material.appbar.CollapsingToolbarLayout; - -import java.util.ArrayList; -import java.util.Locale; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.widget.AppCompatTextView; -import androidx.appcompat.widget.Toolbar; -import androidx.core.app.ActivityCompat; -import androidx.core.widget.NestedScrollView; -import androidx.recyclerview.widget.DefaultItemAnimator; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import code.name.monkey.appthemehelper.ThemeStore; -import code.name.monkey.appthemehelper.util.ColorUtil; -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.AddToPlaylistDialog; -import code.name.monkey.retromusic.glide.ArtistGlideRequest; -import code.name.monkey.retromusic.glide.RetroMusicColoredTarget; -import code.name.monkey.retromusic.helper.MusicPlayerRemote; -import code.name.monkey.retromusic.misc.AppBarStateChangeListener; -import code.name.monkey.retromusic.model.Artist; -import code.name.monkey.retromusic.model.Song; -import code.name.monkey.retromusic.mvp.contract.ArtistDetailContract; -import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsPresenter; -import code.name.monkey.retromusic.rest.LastFMRestClient; -import code.name.monkey.retromusic.rest.model.LastFmArtist; -import code.name.monkey.retromusic.ui.activities.base.AbsSlidingMusicPanelActivity; -import code.name.monkey.retromusic.ui.adapter.album.AlbumAdapter; -import code.name.monkey.retromusic.ui.adapter.album.HorizontalAlbumAdapter; -import code.name.monkey.retromusic.ui.adapter.song.SimpleSongAdapter; -import code.name.monkey.retromusic.util.CustomArtistImageUtil; -import code.name.monkey.retromusic.util.DensityUtil; -import code.name.monkey.retromusic.util.MusicUtil; -import code.name.monkey.retromusic.util.PreferenceUtil; -import code.name.monkey.retromusic.util.RetroUtil; -import code.name.monkey.retromusic.views.CollapsingFAB; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implements - ArtistDetailContract.ArtistsDetailsView { - - public static final String EXTRA_ARTIST_ID = "extra_artist_id"; - private static final int REQUEST_CODE_SELECT_IMAGE = 9003; - @BindView(R.id.app_bar) - @Nullable - AppBarLayout appBarLayout; - - @BindView(R.id.collapsing_toolbar) - @Nullable - CollapsingToolbarLayout collapsingToolbarLayout; - - @BindView(R.id.image) - ImageView image; - - @BindView(R.id.biography) - TextView biographyTextView; - - @BindView(R.id.recycler_view) - RecyclerView recyclerView; - - @BindView(R.id.album_recycler_view) - RecyclerView albumRecyclerView; - - @BindView(R.id.album_title) - AppCompatTextView albumTitle; - - @BindView(R.id.song_title) - AppCompatTextView songTitle; - - @BindView(R.id.biography_title) - AppCompatTextView biographyTitle; - - @BindView(R.id.title) - TextView title; - - @BindView(R.id.text) - TextView text; - - @BindView(R.id.action_shuffle_all) - CollapsingFAB shuffleButton; - - @BindView(R.id.gradient_background) - @Nullable - View background; - - @BindView(R.id.image_container) - @Nullable - View imageContainer; - - @BindView(R.id.content) - NestedScrollView contentContainer; - - @BindView(R.id.toolbar) - Toolbar toolbar; - - @Nullable - private Spanned biography; - private Artist artist; - private LastFMRestClient lastFMRestClient; - private ArtistDetailsPresenter artistDetailsPresenter; - private SimpleSongAdapter songAdapter; - private AlbumAdapter albumAdapter; - private boolean forceDownload; - - void setupWindowTransistion() { - Slide slide = new Slide(Gravity.BOTTOM); - slide.setInterpolator( - AnimationUtils.loadInterpolator(this, android.R.interpolator.linear_out_slow_in)); - getWindow().setEnterTransition(slide); - - } - - - @Override - protected View createContentView() { - return wrapSlidingMusicPanel(R.layout.activity_artist_details); - } - - @Override - protected void onCreate(Bundle bundle) { - setDrawUnderStatusBar(); - setupWindowTransistion(); - super.onCreate(bundle); - ButterKnife.bind(this); - - toggleBottomNavigationView(true); - setNavigationbarColorAuto(); - setLightNavigationBar(true); - - ActivityCompat.postponeEnterTransition(this); - - lastFMRestClient = new LastFMRestClient(this); - - setUpViews(); - - artistDetailsPresenter = new ArtistDetailsPresenter(this, getIntent().getExtras()); - artistDetailsPresenter.subscribe(); - - contentContainer.setOnScrollChangeListener((NestedScrollView.OnScrollChangeListener) (v, scrollX, scrollY, oldScrollX, oldScrollY) -> { - if (scrollY > oldScrollY) { - shuffleButton.setShowTitle(false); - } - if (scrollY < oldScrollY) { - shuffleButton.setShowTitle(true); - } - }); - } - - private void setUpViews() { - setupRecyclerView(); - setupToolbarMarginHeight(); - setupContainerHeight(); - } - - private void setupContainerHeight() { - if (imageContainer != null) { - LayoutParams params = imageContainer.getLayoutParams(); - params.width = DensityUtil.getScreenHeight(this) / 2; - imageContainer.setLayoutParams(params); - } - } - - private void setupToolbarMarginHeight() { - int primaryColor = ThemeStore.primaryColor(this); - TintHelper.setTintAuto(contentContainer, primaryColor, true); - if (collapsingToolbarLayout != null) { - collapsingToolbarLayout.setContentScrimColor(primaryColor); - collapsingToolbarLayout.setStatusBarScrimColor(ColorUtil.darkenColor(primaryColor)); - } - - toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp); - setSupportActionBar(toolbar); - //noinspection ConstantConditions - getSupportActionBar().setTitle(null); - - - if (toolbar != null && !PreferenceUtil.getInstance().getFullScreenMode()) { - ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams(); - params.topMargin = RetroUtil.getStatusBarHeight( ); - toolbar.setLayoutParams(params); - } - - if (appBarLayout != null) { - appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() { - @Override - public void onStateChanged(AppBarLayout appBarLayout, State state) { - int color; - switch (state) { - case COLLAPSED: - setLightStatusbar(ColorUtil.isColorLight(ThemeStore.primaryColor(appBarLayout.getContext()))); - color = ThemeStore.primaryColor(appBarLayout.getContext()); - break; - default: - case EXPANDED: - case IDLE: - setLightStatusbar(false); - color = Color.TRANSPARENT; - break; - } - ToolbarContentTintHelper.setToolbarContentColorBasedOnToolbarColor(appBarLayout.getContext(), toolbar, color); - } - }); - } - } - - private void setupRecyclerView() { - albumAdapter = new HorizontalAlbumAdapter(this, new ArrayList<>(), false, null); - albumRecyclerView.setItemAnimator(new DefaultItemAnimator()); - albumRecyclerView.setLayoutManager(new GridLayoutManager(this, 1, GridLayoutManager.HORIZONTAL, false)); - albumRecyclerView.setAdapter(albumAdapter); - - songAdapter = new SimpleSongAdapter(this, new ArrayList<>(), R.layout.item_song); - recyclerView.setItemAnimator(new DefaultItemAnimator()); - recyclerView.setLayoutManager(new LinearLayoutManager(this)); - recyclerView.setAdapter(songAdapter); - } - - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - switch (requestCode) { - case REQUEST_CODE_SELECT_IMAGE: - if (resultCode == RESULT_OK) { - CustomArtistImageUtil.getInstance(this).setCustomArtistImage(artist, data.getData()); - } - break; - default: - if (resultCode == RESULT_OK) { - reload(); - } - break; - } - } - - @Override - protected void onPause() { - super.onPause(); - artistDetailsPresenter.unsubscribe(); - } - - @Override - public void loading() { - } - - @Override - public void showEmptyView() { - - } - - @Override - public void completed() { - ActivityCompat.startPostponedEnterTransition(this); - } - - @Override - public void showData(Artist artist) { - setArtist(artist); - } - - private Artist getArtist() { - if (artist == null) { - artist = new Artist(); - } - return artist; - } - - private void setArtist(Artist artist) { - if (artist.getSongCount() <= 0) { - finish(); - } - this.artist = artist; - loadArtistImage(); - - if (RetroUtil.isAllowedToDownloadMetadata(this)) { - loadBiography(); - } - title.setText(artist.getName()); - text.setText(String.format("%s • %s", MusicUtil.getArtistInfoString(this, artist), MusicUtil - .getReadableDurationString(MusicUtil.getTotalDuration(this, artist.getSongs())))); - - songAdapter.swapDataSet(artist.getSongs()); - albumAdapter.swapDataSet(artist.getAlbums()); - } - - private void loadBiography() { - loadBiography(Locale.getDefault().getLanguage()); - } - - private void loadBiography(@Nullable final String lang) { - biography = null; - - lastFMRestClient.getApiService() - .getArtistInfo(getArtist().getName(), lang, null) - .enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, - @NonNull Response response) { - final LastFmArtist lastFmArtist = response.body(); - if (lastFmArtist != null && lastFmArtist.getArtist() != null) { - final String bioContent = lastFmArtist.getArtist().getBio().getContent(); - if (bioContent != null && !bioContent.trim().isEmpty()) { - //TransitionManager.beginDelayedTransition(titleContainer); - biographyTextView.setVisibility(View.VISIBLE); - biographyTitle.setVisibility(View.VISIBLE); - biography = Html.fromHtml(bioContent); - biographyTextView.setText(biography); - } - } - - // If the "lang" parameter is set and no biography is given, retry with default language - if (biography == null && lang != null) { - loadBiography(null); - } - } - - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - t.printStackTrace(); - biography = null; - } - }); - } - - @OnClick(R.id.biography) - void toggleArtistBiography() { - if (biographyTextView.getMaxLines() == 4) { - biographyTextView.setMaxLines(Integer.MAX_VALUE); - } else { - biographyTextView.setMaxLines(4); - } - } - - private void loadArtistImage() { - ArtistGlideRequest.Builder.from(Glide.with(this), artist) - .forceDownload(forceDownload) - .generatePalette(this).build() - .dontAnimate() - .into(new RetroMusicColoredTarget(image) { - @Override - public void onColorReady(int color) { - setColors(color); - } - }); - forceDownload = false; - } - - private void setColors(int color) { - - int textColor = PreferenceUtil.getInstance().getAdaptiveColor() ? color : ThemeStore.accentColor(this); - - albumTitle.setTextColor(textColor); - songTitle.setTextColor(textColor); - biographyTitle.setTextColor(textColor); - - shuffleButton.setColor(textColor); - - if (background != null) { - background.setBackgroundTintList(ColorStateList.valueOf(color)); - } - findViewById(R.id.root).setBackgroundColor(ThemeStore.primaryColor(this)); - } - - @OnClick({R.id.action_shuffle_all}) - public void onViewClicked(View view) { - switch (view.getId()) { - case R.id.action_shuffle_all: - MusicPlayerRemote.INSTANCE.openAndShuffleQueue(getArtist().getSongs(), true); - break; - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - return handleSortOrderMenuItem(item); - } - - private boolean handleSortOrderMenuItem(@NonNull MenuItem item) { - final ArrayList songs = getArtist().getSongs(); - switch (item.getItemId()) { - case android.R.id.home: - super.onBackPressed(); - return true; - case R.id.action_play_next: - MusicPlayerRemote.INSTANCE.playNext(songs); - return true; - case R.id.action_add_to_current_playing: - MusicPlayerRemote.INSTANCE.enqueue(songs); - return true; - case R.id.action_add_to_playlist: - AddToPlaylistDialog.create(songs).show(getSupportFragmentManager(), "ADD_PLAYLIST"); - return true; - case R.id.action_set_artist_image: - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.setType("image/*"); - startActivityForResult( - Intent.createChooser(intent, getString(R.string.pick_from_local_storage)), - REQUEST_CODE_SELECT_IMAGE); - return true; - case R.id.action_reset_artist_image: - Toast.makeText(ArtistDetailActivity.this, getResources().getString(R.string.updating), - Toast.LENGTH_SHORT).show(); - CustomArtistImageUtil.getInstance(ArtistDetailActivity.this).resetCustomArtistImage(artist); - forceDownload = true; - return true; - } - return true; - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_artist_detail, menu); - return super.onCreateOptionsMenu(menu); - } - - @Override - public void onMediaStoreChanged() { - super.onMediaStoreChanged(); - reload(); - } - - private void reload() { - artistDetailsPresenter.unsubscribe(); - artistDetailsPresenter.subscribe(); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/ArtistDetailActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/ArtistDetailActivity.kt new file mode 100755 index 00000000..c47a6074 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/ArtistDetailActivity.kt @@ -0,0 +1,363 @@ +package code.name.monkey.retromusic.ui.activities + +import android.app.Activity +import android.content.Intent +import android.graphics.Color +import android.os.Build +import android.os.Bundle +import android.text.Html +import android.text.Spanned +import android.transition.Slide +import android.view.* +import android.view.animation.AnimationUtils +import android.widget.Toast +import androidx.core.app.ActivityCompat +import androidx.core.widget.NestedScrollView +import androidx.recyclerview.widget.DefaultItemAnimator +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import butterknife.ButterKnife +import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.appthemehelper.util.ColorUtil +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.AddToPlaylistDialog +import code.name.monkey.retromusic.glide.ArtistGlideRequest +import code.name.monkey.retromusic.glide.RetroMusicColoredTarget +import code.name.monkey.retromusic.helper.MusicPlayerRemote +import code.name.monkey.retromusic.misc.AppBarStateChangeListener +import code.name.monkey.retromusic.model.Artist +import code.name.monkey.retromusic.mvp.contract.ArtistDetailContract +import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsPresenter +import code.name.monkey.retromusic.rest.LastFMRestClient +import code.name.monkey.retromusic.rest.model.LastFmArtist +import code.name.monkey.retromusic.ui.activities.base.AbsSlidingMusicPanelActivity +import code.name.monkey.retromusic.ui.adapter.album.AlbumAdapter +import code.name.monkey.retromusic.ui.adapter.album.HorizontalAlbumAdapter +import code.name.monkey.retromusic.ui.adapter.song.SimpleSongAdapter +import code.name.monkey.retromusic.util.* +import com.bumptech.glide.Glide +import com.google.android.material.appbar.AppBarLayout +import kotlinx.android.synthetic.main.activity_artist_content.* +import kotlinx.android.synthetic.main.activity_artist_details.* +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response +import java.util.* + +class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailContract.ArtistsDetailsView { + + private var biography: Spanned? = null + private var artist: Artist? = null + private var lastFMRestClient: LastFMRestClient? = null + private var artistDetailsPresenter: ArtistDetailsPresenter? = null + private var songAdapter: SimpleSongAdapter? = null + private var albumAdapter: AlbumAdapter? = null + private var forceDownload: Boolean = false + + private fun setupWindowTransistion() { + val slide = Slide(Gravity.BOTTOM) + slide.interpolator = AnimationUtils.loadInterpolator(this, android.R.interpolator.linear_out_slow_in) + window.enterTransition = slide + } + + + override fun createContentView(): View { + return wrapSlidingMusicPanel(R.layout.activity_artist_details) + } + + override fun onCreate(savedInstanceState: Bundle?) { + setDrawUnderStatusBar() + setupWindowTransistion() + super.onCreate(savedInstanceState) + ButterKnife.bind(this) + + toggleBottomNavigationView(true) + setNavigationbarColorAuto() + setLightNavigationBar(true) + + ActivityCompat.postponeEnterTransition(this) + + lastFMRestClient = LastFMRestClient(this) + + setUpViews() + + artistDetailsPresenter = ArtistDetailsPresenter(this, intent.extras) + artistDetailsPresenter!!.subscribe() + + contentContainer.setOnScrollChangeListener { _: NestedScrollView?, _: Int, scrollY: Int, _: Int, oldScrollY: Int -> + run { + if (scrollY > oldScrollY) { + actionShuffleAll!!.setShowTitle(false) + } + if (scrollY < oldScrollY) { + actionShuffleAll!!.setShowTitle(true) + } + } + } + + biographyText.setOnClickListener { + if (biographyText.maxLines == 4) { + biographyText.maxLines = Integer.MAX_VALUE + } else { + biographyText.maxLines = 4 + } + } + actionShuffleAll.setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(getArtist().songs, true) } + } + + private fun setUpViews() { + setupRecyclerView() + setupToolbarMarginHeight() + setupContainerHeight() + } + + private fun setupContainerHeight() { + if (imageContainer != null) { + val params = imageContainer!!.layoutParams + params.width = DensityUtil.getScreenHeight(this) / 2 + imageContainer!!.layoutParams = params + } + } + + private fun setupToolbarMarginHeight() { + val primaryColor = ThemeStore.primaryColor(this) + TintHelper.setTintAuto(contentContainer!!, primaryColor, true) + if (collapsingToolbar != null) { + collapsingToolbar!!.setContentScrimColor(primaryColor) + collapsingToolbar!!.setStatusBarScrimColor(ColorUtil.darkenColor(primaryColor)) + } + + toolbar!!.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp) + setSupportActionBar(toolbar) + + supportActionBar!!.title = null + + + if (toolbar != null && !PreferenceUtil.getInstance().fullScreenMode) { + val params = toolbar!!.layoutParams as ViewGroup.MarginLayoutParams + params.topMargin = RetroUtil.getStatusBarHeight() + toolbar!!.layoutParams = params + } + + if (appBarLayout != null) { + appBarLayout!!.addOnOffsetChangedListener(object : AppBarStateChangeListener() { + override fun onStateChanged(appBarLayout: AppBarLayout, state: AppBarStateChangeListener.State) { + val color: Int + when (state) { + AppBarStateChangeListener.State.COLLAPSED -> { + setLightStatusbar(ColorUtil.isColorLight(ThemeStore.primaryColor(appBarLayout.context))) + color = ThemeStore.primaryColor(appBarLayout.context) + } + AppBarStateChangeListener.State.EXPANDED, AppBarStateChangeListener.State.IDLE -> { + setLightStatusbar(false) + color = Color.TRANSPARENT + } + + } + ToolbarContentTintHelper.setToolbarContentColorBasedOnToolbarColor(appBarLayout.context, toolbar, color) + } + }) + } + } + + private fun setupRecyclerView() { + albumAdapter = HorizontalAlbumAdapter(this, ArrayList(), false, null) + albumRecyclerView.apply { + itemAnimator = DefaultItemAnimator() + layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false) + adapter = albumAdapter + } + songAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song) + recyclerView.apply { + itemAnimator = DefaultItemAnimator() + layoutManager = LinearLayoutManager(this.context) + adapter = songAdapter + } + } + + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when (requestCode) { + REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) { + CustomArtistImageUtil.getInstance(this).setCustomArtistImage(artist, data!!.data) + } + else -> if (resultCode == Activity.RESULT_OK) { + reload() + } + } + } + + override fun onPause() { + super.onPause() + artistDetailsPresenter!!.unsubscribe() + } + + override fun loading() {} + + override fun showEmptyView() { + + } + + override fun completed() { + ActivityCompat.startPostponedEnterTransition(this) + } + + override fun showData(artist: Artist) { + setArtist(artist) + } + + private fun getArtist(): Artist { + if (artist == null) { + artist = Artist() + } + return this.artist!! + } + + private fun setArtist(artist: Artist) { + if (artist.songCount <= 0) { + finish() + } + this.artist = artist + loadArtistImage() + + if (RetroUtil.isAllowedToDownloadMetadata(this)) { + loadBiography() + } + artistTitle.text = artist.name + text.text = String.format("%s • %s", MusicUtil.getArtistInfoString(this, artist), MusicUtil + .getReadableDurationString(MusicUtil.getTotalDuration(this, artist.songs))) + + songAdapter!!.swapDataSet(artist.songs) + albumAdapter!!.swapDataSet(artist.albums!!) + } + + private fun loadBiography(lang: String? = Locale.getDefault().language) { + biography = null + + lastFMRestClient!!.apiService + .getArtistInfo(getArtist().name, lang, null) + .enqueue(object : Callback { + override fun onResponse(call: Call, + response: Response) { + val lastFmArtist = response.body() + if (lastFmArtist != null && lastFmArtist.artist != null) { + val bioContent = lastFmArtist.artist.bio.content + if (bioContent != null && !bioContent.trim { it <= ' ' }.isEmpty()) { + //TransitionManager.beginDelayedTransition(titleContainer); + biographyText.visibility = View.VISIBLE + biographyTitle.visibility = View.VISIBLE + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + biography = Html.fromHtml(bioContent, Html.FROM_HTML_MODE_LEGACY) + } else { + biography = Html.fromHtml(bioContent) + } + biographyText!!.text = biography + } + } + + // If the "lang" parameter is set and no biography is given, retry with default language + if (biography == null && lang != null) { + loadBiography(null) + } + } + + override fun onFailure(call: Call, t: Throwable) { + t.printStackTrace() + biography = null + } + }) + } + + + private fun loadArtistImage() { + ArtistGlideRequest.Builder.from(Glide.with(this), artist) + .forceDownload(forceDownload) + .generatePalette(this).build() + .dontAnimate() + .into(object : RetroMusicColoredTarget(artistImage) { + override fun onColorReady(color: Int) { + setColors(color) + } + }) + forceDownload = false + } + + private fun setColors(color: Int) { + + val textColor = if (PreferenceUtil.getInstance().adaptiveColor) color else ThemeStore.accentColor(this) + + albumTitle.setTextColor(textColor) + songTitle.setTextColor(textColor) + biographyTitle.setTextColor(textColor) + + actionShuffleAll.setColor(textColor) + + + findViewById(R.id.root).setBackgroundColor(ThemeStore.primaryColor(this)) + } + + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return handleSortOrderMenuItem(item) + } + + private fun handleSortOrderMenuItem(item: MenuItem): Boolean { + val songs = getArtist().songs + when (item.itemId) { + android.R.id.home -> { + super.onBackPressed() + return true + } + R.id.action_play_next -> { + MusicPlayerRemote.playNext(songs) + return true + } + R.id.action_add_to_current_playing -> { + MusicPlayerRemote.enqueue(songs) + return true + } + R.id.action_add_to_playlist -> { + AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST") + return true + } + R.id.action_set_artist_image -> { + val intent = Intent(Intent.ACTION_GET_CONTENT) + intent.type = "image/*" + startActivityForResult(Intent.createChooser(intent, getString(R.string.pick_from_local_storage)), REQUEST_CODE_SELECT_IMAGE) + return true + } + R.id.action_reset_artist_image -> { + Toast.makeText(this@ArtistDetailActivity, resources.getString(R.string.updating), + Toast.LENGTH_SHORT).show() + CustomArtistImageUtil.getInstance(this@ArtistDetailActivity).resetCustomArtistImage(artist) + forceDownload = true + return true + } + } + return true + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.menu_artist_detail, menu) + return super.onCreateOptionsMenu(menu) + } + + override fun onMediaStoreChanged() { + super.onMediaStoreChanged() + reload() + } + + private fun reload() { + artistDetailsPresenter!!.unsubscribe() + artistDetailsPresenter!!.subscribe() + } + + companion object { + + const val EXTRA_ARTIST_ID = "extra_artist_id" + const val REQUEST_CODE_SELECT_IMAGE = 9003 + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/ErrorHandlerActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/ErrorHandlerActivity.java index 5a0ecd4c..10253ff9 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/ErrorHandlerActivity.java +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/ErrorHandlerActivity.java @@ -1 +1 @@ -package code.name.monkey.retromusic.ui.activities; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import android.view.View; import butterknife.OnClick; import code.name.monkey.retromusic.R; import code.name.monkey.retromusic.RetroApplication; public class ErrorHandlerActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_error_handler); } @OnClick(R.id.clear_app_data) void clearAppDate(View view) { RetroApplication.Companion.deleteAppData(); } } \ No newline at end of file +package code.name.monkey.retromusic.ui.activities; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import android.view.View; import butterknife.OnClick; import code.name.monkey.retromusic.R; import code.name.monkey.retromusic.App; public class ErrorHandlerActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_error_handler); } @OnClick(R.id.clear_app_data) void clearAppDate(View view) { App.Companion.deleteAppData(); } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/GenreDetailsActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/GenreDetailsActivity.java deleted file mode 100644 index f7130704..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/GenreDetailsActivity.java +++ /dev/null @@ -1,226 +0,0 @@ -package code.name.monkey.retromusic.ui.activities; - -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.ProgressBar; -import android.widget.TextView; - -import com.afollestad.materialcab.MaterialCab; -import com.google.android.material.appbar.AppBarLayout; -import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView; - -import java.util.ArrayList; - -import androidx.annotation.NonNull; -import androidx.appcompat.widget.Toolbar; -import androidx.recyclerview.widget.DefaultItemAnimator; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import code.name.monkey.appthemehelper.ThemeStore; -import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; -import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.helper.MusicPlayerRemote; -import code.name.monkey.retromusic.helper.menu.GenreMenuHelper; -import code.name.monkey.retromusic.interfaces.CabHolder; -import code.name.monkey.retromusic.model.Genre; -import code.name.monkey.retromusic.model.Song; -import code.name.monkey.retromusic.mvp.contract.GenreDetailsContract; -import code.name.monkey.retromusic.mvp.presenter.GenreDetailsPresenter; -import code.name.monkey.retromusic.ui.activities.base.AbsSlidingMusicPanelActivity; -import code.name.monkey.retromusic.ui.adapter.song.SongAdapter; -import code.name.monkey.retromusic.util.RetroColorUtil; -import code.name.monkey.retromusic.util.ViewUtil; -import code.name.monkey.retromusic.views.CollapsingFAB; - -/** - * @author Hemanth S (h4h13). - */ - -public class GenreDetailsActivity extends AbsSlidingMusicPanelActivity implements GenreDetailsContract.GenreDetailsView, CabHolder { - public static final String EXTRA_GENRE_ID = "extra_genre_id"; - - @BindView(R.id.recycler_view) - RecyclerView recyclerView; - - @BindView(R.id.toolbar) - Toolbar toolbar; - - @BindView(android.R.id.empty) - TextView empty; - - @BindView(R.id.action_shuffle) - CollapsingFAB shuffleButton; - - @BindView(R.id.progress_bar) - ProgressBar progressBar; - - @BindView(R.id.app_bar) - AppBarLayout appBarLayout; - - @BindView(R.id.title) - TextView title; - - private Genre genre; - private GenreDetailsPresenter presenter; - private SongAdapter songAdapter; - private MaterialCab cab; - - private void checkIsEmpty() { - empty.setVisibility( - songAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE - ); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - setDrawUnderStatusBar(); - super.onCreate(savedInstanceState); - ButterKnife.bind(this); - - setNavigationbarColorAuto(); - setTaskDescriptionColorAuto(); - toggleBottomNavigationView(true); - setLightNavigationBar(true); - - - genre = getIntent().getParcelableExtra(EXTRA_GENRE_ID); - presenter = new GenreDetailsPresenter(this, genre.getId()); - - setUpToolBar(); - setupRecyclerView(); - } - - @OnClick({R.id.action_shuffle}) - public void onViewClicked(View view) { - switch (view.getId()) { - case R.id.action_shuffle: - MusicPlayerRemote.INSTANCE.openAndShuffleQueue(songAdapter.getDataSet(), true); - break; - } - } - - private void setUpToolBar() { - title.setText(genre.getName()); - title.setTextColor(ThemeStore.textColorPrimary(this)); - - int primaryColor = ThemeStore.primaryColor(this); - toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp); - toolbar.setBackgroundColor(primaryColor); - appBarLayout.setBackgroundColor(primaryColor); - ToolbarContentTintHelper.colorBackButton(toolbar, ThemeStore.accentColor(this)); - setTitle(null); - setSupportActionBar(toolbar); - shuffleButton.setColor(ThemeStore.accentColor(this)); - } - - @Override - protected void onResume() { - super.onResume(); - presenter.subscribe(); - } - - @Override - protected void onPause() { - super.onPause(); - presenter.unsubscribe(); - } - - @Override - protected View createContentView() { - return wrapSlidingMusicPanel(R.layout.activity_playlist_detail); - } - - - @Override - public void loading() { - - } - - @Override - public void showEmptyView() { - - } - - @Override - public void completed() { - - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_genre_detail, menu); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - onBackPressed(); - } - return GenreMenuHelper.INSTANCE.handleMenuClick(this, genre, item); - } - - private void setupRecyclerView() { - ViewUtil.setUpFastScrollRecyclerViewColor(this, - ((FastScrollRecyclerView) recyclerView), ThemeStore.accentColor(this)); - songAdapter = new SongAdapter(this, new ArrayList<>(), R.layout.item_list, false, this); - recyclerView.setItemAnimator(new DefaultItemAnimator()); - recyclerView.setLayoutManager(new LinearLayoutManager(this)); - recyclerView.setAdapter(songAdapter); - recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - super.onScrolled(recyclerView, dx, dy); - if (dy > 0) { - shuffleButton.setShowTitle(false); - } else if (dy < 0) { - shuffleButton.setShowTitle(true); - } - } - }); - songAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { - @Override - public void onChanged() { - super.onChanged(); - checkIsEmpty(); - } - }); - } - - @Override - public void showData(ArrayList songs) { - songAdapter.swapDataSet(songs); - } - - @NonNull - @Override - public MaterialCab openCab(final int menu, final MaterialCab.Callback callback) { - if (cab != null && cab.isActive()) cab.finish(); - cab = new MaterialCab(this, R.id.cab_stub) - .setMenu(menu) - .setCloseDrawableRes(R.drawable.ic_close_white_24dp) - .setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor(this))) - .start(callback); - return cab; - } - - @Override - public void onBackPressed() { - if (cab != null && cab.isActive()) cab.finish(); - else { - recyclerView.stopScroll(); - super.onBackPressed(); - } - } - - @Override - public void onMediaStoreChanged() { - super.onMediaStoreChanged(); - presenter.subscribe(); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/GenreDetailsActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/GenreDetailsActivity.kt new file mode 100644 index 00000000..b1178cc1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/GenreDetailsActivity.kt @@ -0,0 +1,174 @@ +package code.name.monkey.retromusic.ui.activities + +import android.os.Bundle +import android.view.Menu +import android.view.MenuItem +import android.view.View +import androidx.recyclerview.widget.DefaultItemAnimator +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import butterknife.ButterKnife +import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.helper.MusicPlayerRemote +import code.name.monkey.retromusic.helper.menu.GenreMenuHelper +import code.name.monkey.retromusic.interfaces.CabHolder +import code.name.monkey.retromusic.model.Genre +import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.mvp.contract.GenreDetailsContract +import code.name.monkey.retromusic.mvp.presenter.GenreDetailsPresenter +import code.name.monkey.retromusic.ui.activities.base.AbsSlidingMusicPanelActivity +import code.name.monkey.retromusic.ui.adapter.song.SongAdapter +import code.name.monkey.retromusic.util.RetroColorUtil +import code.name.monkey.retromusic.util.ViewUtil +import com.afollestad.materialcab.MaterialCab +import kotlinx.android.synthetic.main.activity_playlist_detail.* +import java.util.* + +/** + * @author Hemanth S (h4h13). + */ + +class GenreDetailsActivity : AbsSlidingMusicPanelActivity(), GenreDetailsContract.GenreDetailsView, CabHolder { + + private var genre: Genre? = null + private var presenter: GenreDetailsPresenter? = null + private var songAdapter: SongAdapter? = null + private var cab: MaterialCab? = null + + private fun checkIsEmpty() { + empty!!.visibility = if (songAdapter!!.itemCount == 0) View.VISIBLE else View.GONE + } + + override fun onCreate(savedInstanceState: Bundle?) { + setDrawUnderStatusBar() + super.onCreate(savedInstanceState) + ButterKnife.bind(this) + + setStatusbarColorAuto() + setNavigationbarColorAuto() + setTaskDescriptionColorAuto() + + toggleBottomNavigationView(true) + setLightNavigationBar(true) + + + genre = intent.extras!!.getParcelable(EXTRA_GENRE_ID) + presenter = GenreDetailsPresenter(this, genre!!.id) + + setUpToolBar() + setupRecyclerView() + actionShuffle.setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(songAdapter!!.dataSet, true) } + } + + private fun setUpToolBar() { + bannerTitle!!.text = genre!!.name + bannerTitle!!.setTextColor(ThemeStore.textColorPrimary(this)) + + val primaryColor = ThemeStore.primaryColor(this) + toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp) + toolbar.setBackgroundColor(primaryColor) + appBarLayout.setBackgroundColor(primaryColor) + ToolbarContentTintHelper.colorBackButton(toolbar!!, ThemeStore.accentColor(this)) + title = null + setSupportActionBar(toolbar) + actionShuffle.setColor(ThemeStore.accentColor(this)) + } + + override fun onResume() { + super.onResume() + presenter!!.subscribe() + } + + override fun onPause() { + super.onPause() + presenter!!.unsubscribe() + } + + override fun createContentView(): View { + return wrapSlidingMusicPanel(R.layout.activity_playlist_detail) + } + + + override fun loading() { + + } + + override fun showEmptyView() { + + } + + override fun completed() { + + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.menu_genre_detail, menu) + return super.onCreateOptionsMenu(menu) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + if (item.itemId == android.R.id.home) { + onBackPressed() + } + return GenreMenuHelper.handleMenuClick(this, genre!!, item) + } + + private fun setupRecyclerView() { + ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView, ThemeStore.accentColor(this)) + songAdapter = SongAdapter(this, ArrayList(), R.layout.item_list, false, this) + recyclerView.apply { + itemAnimator = DefaultItemAnimator() + layoutManager = LinearLayoutManager(this@GenreDetailsActivity) + adapter = songAdapter + }.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + super.onScrolled(recyclerView, dx, dy) + if (dy > 0) { + actionShuffle.setShowTitle(false) + } else if (dy < 0) { + actionShuffle.setShowTitle(true) + } + } + }) + songAdapter!!.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { + override fun onChanged() { + super.onChanged() + checkIsEmpty() + } + }) + } + + override fun showData(songs: ArrayList) { + songAdapter!!.swapDataSet(songs) + } + + override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab { + if (cab != null && cab!!.isActive) cab!!.finish() + cab = MaterialCab(this, R.id.cab_stub) + .setMenu(menuRes) + .setCloseDrawableRes(R.drawable.ic_close_white_24dp) + .setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor(this))) + .start(callback) + return cab!! + } + + override fun onBackPressed() { + if (cab != null && cab!!.isActive) + cab!!.finish() + else { + recyclerView!!.stopScroll() + super.onBackPressed() + } + } + + override fun onMediaStoreChanged() { + super.onMediaStoreChanged() + presenter!!.subscribe() + } + + companion object { + const val EXTRA_GENRE_ID = "extra_genre_id" + } +} 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 e875ca79..81f934b6 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 @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.content.* import android.content.pm.PackageManager import android.os.Bundle +import android.os.Handler import android.preference.PreferenceManager import android.provider.MediaStore import android.util.Log @@ -12,8 +13,11 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import butterknife.ButterKnife +import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.appthemehelper.util.ATHUtil +import code.name.monkey.appthemehelper.util.NavigationViewUtil +import code.name.monkey.retromusic.App import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.RetroApplication import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.SearchQueryHelper import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks @@ -23,16 +27,18 @@ import code.name.monkey.retromusic.loaders.PlaylistSongsLoader import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.ui.activities.base.AbsSlidingMusicPanelActivity import code.name.monkey.retromusic.ui.fragments.mainactivity.LibraryFragment +import code.name.monkey.retromusic.ui.fragments.mainactivity.folders.FoldersFragment import code.name.monkey.retromusic.ui.fragments.mainactivity.home.BannerHomeFragment import code.name.monkey.retromusic.util.PreferenceUtil import com.afollestad.materialdialogs.MaterialDialog -import com.google.android.material.bottomnavigation.BottomNavigationView import io.reactivex.disposables.CompositeDisposable +import kotlinx.android.synthetic.main.activity_main_drawer_layout.* import java.util.* -class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedPreferenceChangeListener, BottomNavigationView.OnNavigationItemSelectedListener { - lateinit var currentFragment: MainActivityFragmentCallbacks +class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedPreferenceChangeListener { + + private lateinit var currentFragment: MainActivityFragmentCallbacks private var blockRequestPermissions: Boolean = false private val disposable = CompositeDisposable() @@ -63,16 +69,23 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP super.onCreate(savedInstanceState) ButterKnife.bind(this) - getBottomNavigationView()!!.setOnNavigationItemSelectedListener(this) + getBottomNavigationView()!!.setOnNavigationItemSelectedListener { + PreferenceUtil.getInstance().lastPage = it.itemId + selectedFragment(it.itemId) + true + } + + setUpDrawerLayout() if (savedInstanceState == null) { - selectedFragment(PreferenceUtil.getInstance().lastPage) + setMusicChooser(PreferenceUtil.getInstance().lastMusicChooser) } else { - restoreCurrentFragment() + restoreCurrentFragment(); } + checkShowChangelog() - if (!RetroApplication.isProVersion && !PreferenceManager.getDefaultSharedPreferences(this).getBoolean("shown", false)) { + if (!App.isProVersion && !PreferenceManager.getDefaultSharedPreferences(this).getBoolean("shown", false)) { showPromotionalOffer() } } @@ -104,7 +117,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP intent.putExtra("expand", false) } } - } override fun onDestroy() { @@ -114,16 +126,12 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP PreferenceUtil.getInstance().unregisterOnSharedPreferenceChangedListener(this) } - fun setCurrentFragment(fragment: Fragment, isStackAdd: Boolean, tag: String) { - val fragmentTransaction = supportFragmentManager.beginTransaction() - fragmentTransaction.replace(R.id.fragment_container, fragment, tag) - if (isStackAdd) { - fragmentTransaction.addToBackStack(tag) - } - fragmentTransaction.commit() + private fun setCurrentFragment(fragment: Fragment) { + supportFragmentManager.beginTransaction().replace(R.id.fragment_container, fragment, null).commit() currentFragment = fragment as MainActivityFragmentCallbacks } + private fun restoreCurrentFragment() { currentFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as MainActivityFragmentCallbacks } @@ -139,7 +147,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP if (intent.action != null && intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH) { val songs = SearchQueryHelper.getSongs(this, intent.extras!!) - if (MusicPlayerRemote.shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) { MusicPlayerRemote.openAndShuffleQueue(songs, true) } else { @@ -148,15 +155,14 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP handled = true } - if (uri != null && uri.toString().length > 0) { + if (uri != null && uri.toString().isNotEmpty()) { MusicPlayerRemote.playFromUri(uri) handled = true } else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) { val id = parseIdFromIntent(intent, "playlistId", "playlist").toInt() if (id >= 0) { val position = intent.getIntExtra("position", 0) - val songs = ArrayList( - PlaylistSongsLoader.getPlaylistSongList(this, id).blockingFirst()) + val songs = ArrayList(PlaylistSongsLoader.getPlaylistSongList(this, id).blockingFirst()) MusicPlayerRemote.openQueue(songs, position, true) handled = true } @@ -164,16 +170,14 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP val id = parseIdFromIntent(intent, "albumId", "album").toInt() if (id >= 0) { val position = intent.getIntExtra("position", 0) - MusicPlayerRemote - .openQueue(AlbumLoader.getAlbum(this, id).blockingFirst().songs!!, position, true) + MusicPlayerRemote.openQueue(AlbumLoader.getAlbum(this, id).blockingFirst().songs!!, position, true) handled = true } } else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) { val id = parseIdFromIntent(intent, "artistId", "artist").toInt() if (id >= 0) { val position = intent.getIntExtra("position", 0) - MusicPlayerRemote - .openQueue(ArtistLoader.getArtist(this, id).blockingFirst().songs, position, true) + MusicPlayerRemote.openQueue(ArtistLoader.getArtist(this, id).blockingFirst().songs, position, true) handled = true } } @@ -192,7 +196,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP } catch (e: NumberFormatException) { Log.e(TAG, e.message) } - } } return id @@ -213,6 +216,10 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP } override fun handleBackPress(): Boolean { + if (drawerLayout.isDrawerOpen(navigationView)) { + drawerLayout.closeDrawers() + return true + } return super.handleBackPress() || currentFragment.handleBackPress() } @@ -257,10 +264,10 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP private fun showPromotionalOffer() { MaterialDialog.Builder(this) .positiveText("Buy") - .onPositive { dialog, which -> startActivity(Intent(this@MainActivity, ProVersionActivity::class.java)) } + .onPositive { _, _ -> startActivity(Intent(this@MainActivity, ProVersionActivity::class.java)) } .negativeText(android.R.string.cancel) .customView(R.layout.dialog_promotional_offer, false) - .dismissListener { dialog -> + .dismissListener { PreferenceManager.getDefaultSharedPreferences(this@MainActivity) .edit() .putBoolean("shown", true) @@ -269,19 +276,82 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP .show() } - override fun onNavigationItemSelected(menuItem: MenuItem): Boolean { - PreferenceUtil.getInstance().lastPage = menuItem.itemId - selectedFragment(menuItem.itemId) - return true - } - private fun selectedFragment(itemId: Int) { when (itemId) { - R.id.action_album, R.id.action_artist, R.id.action_playlist, R.id.action_song -> setCurrentFragment(LibraryFragment.newInstance(itemId), false, LibraryFragment.TAG) - R.id.action_home -> setCurrentFragment(BannerHomeFragment.newInstance(), false, BannerHomeFragment.TAG) + R.id.action_album, + R.id.action_artist, + R.id.action_playlist, + R.id.action_song -> setCurrentFragment(LibraryFragment.newInstance(itemId)) } } + private fun setUpNavigationView() { + val accentColor = ThemeStore.accentColor(this) + NavigationViewUtil.setItemIconColors(navigationView, ATHUtil.resolveColor(this, R.attr.iconColor, ThemeStore.textColorSecondary(this)), accentColor) + NavigationViewUtil.setItemTextColors(navigationView, ThemeStore.textColorPrimary(this), accentColor) + + checkSetUpPro() + navigationView.setNavigationItemSelectedListener { menuItem -> + drawerLayout.closeDrawers() + when (menuItem.itemId) { + R.id.nav_library -> Handler().postDelayed({ setMusicChooser(LIBRARY) }, 200) + R.id.nav_home -> Handler().postDelayed({ setMusicChooser(HOME) }, 200) + R.id.nav_folders -> Handler().postDelayed({ setMusicChooser(FOLDERS) }, 200) + R.id.buy_pro -> Handler().postDelayed({ startActivityForResult(Intent(this@MainActivity, ProVersionActivity::class.java), PURCHASE_REQUEST) }, 200) + } + true + } + } + + private fun setMusicChooser(key: Int) { + PreferenceUtil.getInstance().lastMusicChooser = key + when (key) { + LIBRARY -> { + navigationView.setCheckedItem(R.id.nav_library) + setCurrentFragment(LibraryFragment.newInstance()) + } + FOLDERS -> { + navigationView.setCheckedItem(R.id.nav_folders) + setCurrentFragment(FoldersFragment.newInstance(this)) + } + HOME -> { + navigationView.setCheckedItem(R.id.nav_home) + setCurrentFragment(BannerHomeFragment()) + } + } + } + + + private fun checkSetUpPro() { + if (App.isProVersion) { + setUpPro() + } + } + + private fun setUpPro() { + navigationView.menu.removeGroup(R.id.navigation_drawer_menu_category_buy_pro) + } + + private fun setUpDrawerLayout() { + setUpNavigationView() + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + if (item.itemId == android.R.id.home) { + if (drawerLayout.isDrawerOpen(navigationView)) { + drawerLayout.closeDrawer(navigationView) + } else { + drawerLayout.openDrawer(navigationView) + } + return true + } + return super.onOptionsItemSelected(item) + } + + private fun updateNavigationDrawerHeader() { + + } + companion object { const val APP_INTRO_REQUEST = 2323 const val LIBRARY = 1 @@ -290,5 +360,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP private const val TAG = "MainActivity" private const val APP_USER_INFO_REQUEST = 9003 private const val REQUEST_CODE_THEME = 9002 + private const val PURCHASE_REQUEST = 101 } } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlaylistDetailActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlaylistDetailActivity.java deleted file mode 100644 index 724b3e51..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlaylistDetailActivity.java +++ /dev/null @@ -1,309 +0,0 @@ -package code.name.monkey.retromusic.ui.activities; - -import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.TextView; - -import com.afollestad.materialcab.MaterialCab; -import com.google.android.material.appbar.AppBarLayout; -import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator; -import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator; -import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager; -import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils; -import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView; - -import java.util.ArrayList; - -import androidx.annotation.NonNull; -import androidx.appcompat.widget.Toolbar; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import code.name.monkey.appthemehelper.ThemeStore; -import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; -import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.helper.MusicPlayerRemote; -import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper; -import code.name.monkey.retromusic.interfaces.CabHolder; -import code.name.monkey.retromusic.loaders.PlaylistLoader; -import code.name.monkey.retromusic.model.AbsCustomPlaylist; -import code.name.monkey.retromusic.model.Playlist; -import code.name.monkey.retromusic.model.Song; -import code.name.monkey.retromusic.mvp.contract.PlaylistSongsContract; -import code.name.monkey.retromusic.mvp.presenter.PlaylistSongsPresenter; -import code.name.monkey.retromusic.ui.activities.base.AbsSlidingMusicPanelActivity; -import code.name.monkey.retromusic.ui.adapter.song.OrderablePlaylistSongAdapter; -import code.name.monkey.retromusic.ui.adapter.song.PlaylistSongAdapter; -import code.name.monkey.retromusic.ui.adapter.song.SongAdapter; -import code.name.monkey.retromusic.util.PlaylistsUtil; -import code.name.monkey.retromusic.util.RetroColorUtil; -import code.name.monkey.retromusic.util.ViewUtil; -import code.name.monkey.retromusic.views.CollapsingFAB; - -public class PlaylistDetailActivity extends AbsSlidingMusicPanelActivity implements CabHolder, - PlaylistSongsContract.PlaylistSongsView { - - @NonNull - public static String EXTRA_PLAYLIST = "extra_playlist"; - - @BindView(R.id.recycler_view) - RecyclerView recyclerView; - - @BindView(R.id.toolbar) - Toolbar toolbar; - - @BindView(android.R.id.empty) - TextView empty; - - @BindView(R.id.action_shuffle) - CollapsingFAB shuffleButton; - - @BindView(R.id.app_bar) - AppBarLayout appBarLayout; - - @BindView(R.id.title) - TextView title; - - private Playlist playlist; - private MaterialCab cab; - private SongAdapter adapter; - private RecyclerView.Adapter wrappedAdapter; - private RecyclerViewDragDropManager recyclerViewDragDropManager; - private PlaylistSongsPresenter songsPresenter; - - @Override - protected void onCreate(Bundle savedInstanceState) { - setDrawUnderStatusBar(); - super.onCreate(savedInstanceState); - ButterKnife.bind(this); - - setStatusbarColorAuto(); - setNavigationbarColorAuto(); - setTaskDescriptionColorAuto(); - setLightNavigationBar(true); - toggleBottomNavigationView(true); - - playlist = getIntent().getExtras().getParcelable(EXTRA_PLAYLIST); - - if (playlist != null) { - songsPresenter = new PlaylistSongsPresenter(this, playlist); - } - - setUpToolBar(); - setUpRecyclerView(); - } - - @Override - protected View createContentView() { - return wrapSlidingMusicPanel(R.layout.activity_playlist_detail); - } - - private void setUpRecyclerView() { - ViewUtil.setUpFastScrollRecyclerViewColor(this, ((FastScrollRecyclerView) recyclerView), - ThemeStore.accentColor(this)); - recyclerView.setLayoutManager(new LinearLayoutManager(this)); - if (playlist instanceof AbsCustomPlaylist) { - adapter = new PlaylistSongAdapter(this, new ArrayList(), R.layout.item_list, false, - this); - recyclerView.setAdapter(adapter); - } else { - recyclerViewDragDropManager = new RecyclerViewDragDropManager(); - final GeneralItemAnimator animator = new RefactoredDefaultItemAnimator(); - adapter = new OrderablePlaylistSongAdapter(this, new ArrayList<>(), - R.layout.item_list, false, this, (fromPosition, toPosition) -> { - if (PlaylistsUtil.moveItem(PlaylistDetailActivity.this, playlist.id, fromPosition, toPosition)) { - Song song = adapter.getDataSet().remove(fromPosition); - adapter.getDataSet().add(toPosition, song); - adapter.notifyItemMoved(fromPosition, toPosition); - } - }); - wrappedAdapter = recyclerViewDragDropManager.createWrappedAdapter(adapter); - - recyclerView.setAdapter(wrappedAdapter); - recyclerView.setItemAnimator(animator); - - recyclerViewDragDropManager.attachRecyclerView(recyclerView); - } - adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { - @Override - public void onChanged() { - super.onChanged(); - checkIsEmpty(); - } - }); - recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - super.onScrolled(recyclerView, dx, dy); - if (dy > 0) { - shuffleButton.setShowTitle(false); - } else if (dy < 0) { - shuffleButton.setShowTitle(true); - } - } - }); - } - - @Override - protected void onResume() { - super.onResume(); - songsPresenter.subscribe(); - } - - private void setUpToolBar() { - title.setText(playlist.name); - title.setTextColor(ThemeStore.textColorPrimary(this)); - shuffleButton.setColor(ThemeStore.accentColor(this)); - - int primaryColor = ThemeStore.primaryColor(this); - toolbar.setBackgroundColor(primaryColor); - appBarLayout.setBackgroundColor(primaryColor); - - setTitle(null); - setSupportActionBar(toolbar); - toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp); - - ToolbarContentTintHelper.colorBackButton(toolbar, ThemeStore.accentColor(this)); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(playlist instanceof AbsCustomPlaylist ? R.menu.menu_smart_playlist_detail : R.menu.menu_playlist_detail, menu); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - int id = item.getItemId(); - switch (id) { - case android.R.id.home: - onBackPressed(); - return true; - } - return PlaylistMenuHelper.INSTANCE.handleMenuClick(this, playlist, item); - } - - @NonNull - @Override - public MaterialCab openCab(final int menu, final MaterialCab.Callback callback) { - if (cab != null && cab.isActive()) { - cab.finish(); - } - cab = new MaterialCab(this, R.id.cab_stub) - .setMenu(menu) - .setCloseDrawableRes(R.drawable.ic_close_white_24dp) - .setBackgroundColor( - RetroColorUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor(this))) - .start(callback); - return cab; - } - - @Override - public void onBackPressed() { - if (cab != null && cab.isActive()) { - cab.finish(); - } else { - recyclerView.stopScroll(); - super.onBackPressed(); - } - } - - @Override - public void onMediaStoreChanged() { - super.onMediaStoreChanged(); - - if (!(playlist instanceof AbsCustomPlaylist)) { - // Playlist deleted - if (!PlaylistsUtil.doesPlaylistExist(this, playlist.id)) { - finish(); - return; - } - - // Playlist renamed - final String playlistName = PlaylistsUtil.getNameForPlaylist(this, playlist.id); - if (!playlistName.equals(playlist.name)) { - playlist = PlaylistLoader.INSTANCE.getPlaylist(this, playlist.id).blockingFirst(); - setToolbarTitle(playlist.name); - } - } - songsPresenter.subscribe(); - } - - private void setToolbarTitle(String title) { - //noinspection ConstantConditions - getSupportActionBar().setTitle(title); - } - - private void checkIsEmpty() { - empty.setVisibility( - adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE - ); - } - - @Override - public void onPause() { - if (recyclerViewDragDropManager != null) { - recyclerViewDragDropManager.cancelDrag(); - } - super.onPause(); - songsPresenter.unsubscribe(); - } - - @Override - public void onDestroy() { - if (recyclerViewDragDropManager != null) { - recyclerViewDragDropManager.release(); - recyclerViewDragDropManager = null; - } - - if (recyclerView != null) { - recyclerView.setItemAnimator(null); - recyclerView.setAdapter(null); - recyclerView = null; - } - - if (wrappedAdapter != null) { - WrapperAdapterUtils.releaseAll(wrappedAdapter); - wrappedAdapter = null; - } - adapter = null; - - super.onDestroy(); - } - - @Override - public void onPlayingMetaChanged() { - super.onPlayingMetaChanged(); - songsPresenter.subscribe(); - } - - @Override - public void loading() { - } - - @Override - public void showEmptyView() { - empty.setVisibility(View.VISIBLE); - } - - @Override - public void completed() { - } - - @Override - public void showData(ArrayList songs) { - adapter.swapDataSet(songs); - } - - @OnClick(R.id.action_shuffle) - public void onViewClicked() { - if (adapter.getDataSet().isEmpty()) { - return; - } - MusicPlayerRemote.INSTANCE.openAndShuffleQueue(adapter.getDataSet(), true); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlaylistDetailActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlaylistDetailActivity.kt new file mode 100644 index 00000000..07ca6e0e --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/PlaylistDetailActivity.kt @@ -0,0 +1,254 @@ +package code.name.monkey.retromusic.ui.activities + +import android.os.Bundle +import android.view.Menu +import android.view.MenuItem +import android.view.View +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import butterknife.ButterKnife +import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.helper.MusicPlayerRemote +import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper +import code.name.monkey.retromusic.interfaces.CabHolder +import code.name.monkey.retromusic.loaders.PlaylistLoader +import code.name.monkey.retromusic.model.AbsCustomPlaylist +import code.name.monkey.retromusic.model.Playlist +import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.mvp.contract.PlaylistSongsContract +import code.name.monkey.retromusic.mvp.presenter.PlaylistSongsPresenter +import code.name.monkey.retromusic.ui.activities.base.AbsSlidingMusicPanelActivity +import code.name.monkey.retromusic.ui.adapter.song.OrderablePlaylistSongAdapter +import code.name.monkey.retromusic.ui.adapter.song.PlaylistSongAdapter +import code.name.monkey.retromusic.ui.adapter.song.SongAdapter +import code.name.monkey.retromusic.util.PlaylistsUtil +import code.name.monkey.retromusic.util.RetroColorUtil +import code.name.monkey.retromusic.util.ViewUtil +import com.afollestad.materialcab.MaterialCab +import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator +import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager +import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils +import kotlinx.android.synthetic.main.activity_playlist_detail.* +import java.util.* + +class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, PlaylistSongsContract.PlaylistSongsView { + + + private var playlist: Playlist? = null + private var cab: MaterialCab? = null + private lateinit var adapter: SongAdapter + private var wrappedAdapter: RecyclerView.Adapter<*>? = null + private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null + private var songsPresenter: PlaylistSongsPresenter? = null + + override fun onCreate(savedInstanceState: Bundle?) { + setDrawUnderStatusBar() + super.onCreate(savedInstanceState) + ButterKnife.bind(this) + + setStatusbarColorAuto() + setNavigationbarColorAuto() + setTaskDescriptionColorAuto() + setLightNavigationBar(true) + toggleBottomNavigationView(true) + + + playlist = intent.extras!!.getParcelable(EXTRA_PLAYLIST) + songsPresenter = PlaylistSongsPresenter(this, playlist!!) + + setUpToolBar() + setUpRecyclerView() + } + + override fun createContentView(): View { + return wrapSlidingMusicPanel(R.layout.activity_playlist_detail) + } + + private fun setUpRecyclerView() { + ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView, ThemeStore.accentColor(this)) + recyclerView.layoutManager = LinearLayoutManager(this) + if (playlist is AbsCustomPlaylist) { + adapter = PlaylistSongAdapter(this, ArrayList(), R.layout.item_list, false, this) + recyclerView!!.adapter = adapter + } else { + recyclerViewDragDropManager = RecyclerViewDragDropManager() + val animator = RefactoredDefaultItemAnimator() + adapter = OrderablePlaylistSongAdapter(this, ArrayList(), R.layout.item_list, false, this, + object : OrderablePlaylistSongAdapter.OnMoveItemListener { + override fun onMoveItem(fromPosition: Int, toPosition: Int) { + if (PlaylistsUtil.moveItem(this@PlaylistDetailActivity, playlist!!.id, fromPosition, toPosition)) { + val song = adapter.dataSet.removeAt(fromPosition) + adapter.dataSet.add(toPosition, song) + adapter.notifyItemMoved(fromPosition, toPosition) + } + } + }) + wrappedAdapter = recyclerViewDragDropManager!!.createWrappedAdapter(adapter) + + recyclerView.adapter = wrappedAdapter + recyclerView.itemAnimator = animator + + recyclerViewDragDropManager!!.attachRecyclerView(recyclerView!!) + } + adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { + override fun onChanged() { + super.onChanged() + checkIsEmpty() + } + }) + recyclerView!!.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + super.onScrolled(recyclerView, dx, dy) + if (dy > 0) { + actionShuffle.setShowTitle(false) + } else if (dy < 0) { + actionShuffle.setShowTitle(true) + } + } + }) + actionShuffle.setOnClickListener { + if (adapter.dataSet.isEmpty()) { + return@setOnClickListener + } + MusicPlayerRemote.openAndShuffleQueue(adapter.dataSet, true) + } + } + + override fun onResume() { + super.onResume() + songsPresenter!!.subscribe() + } + + private fun setUpToolBar() { + bannerTitle.text = playlist!!.name + bannerTitle.setTextColor(ThemeStore.textColorPrimary(this)) + actionShuffle.setColor(ThemeStore.accentColor(this)) + + val primaryColor = ThemeStore.primaryColor(this) + toolbar!!.setBackgroundColor(primaryColor) + appBarLayout!!.setBackgroundColor(primaryColor) + + title = null + setSupportActionBar(toolbar) + toolbar!!.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp) + + ToolbarContentTintHelper.colorBackButton(toolbar!!, ThemeStore.accentColor(this)) + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(if (playlist is AbsCustomPlaylist) R.menu.menu_smart_playlist_detail else R.menu.menu_playlist_detail, menu) + return super.onCreateOptionsMenu(menu) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + val id = item.itemId + when (id) { + android.R.id.home -> { + onBackPressed() + return true + } + } + return PlaylistMenuHelper.handleMenuClick(this, playlist!!, item) + } + + override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab { + if (cab != null && cab!!.isActive) { + cab!!.finish() + } + cab = MaterialCab(this, R.id.cab_stub) + .setMenu(menuRes) + .setCloseDrawableRes(R.drawable.ic_close_white_24dp) + .setBackgroundColor( + RetroColorUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor(this))) + .start(callback) + return cab!! + } + + override fun onBackPressed() { + if (cab != null && cab!!.isActive) { + cab!!.finish() + } else { + recyclerView!!.stopScroll() + super.onBackPressed() + } + } + + override fun onMediaStoreChanged() { + super.onMediaStoreChanged() + + if (playlist !is AbsCustomPlaylist) { + // Playlist deleted + if (!PlaylistsUtil.doesPlaylistExist(this, playlist!!.id)) { + finish() + return + } + + // Playlist renamed + val playlistName = PlaylistsUtil.getNameForPlaylist(this, playlist!!.id.toLong()) + if (playlistName != playlist!!.name) { + playlist = PlaylistLoader.getPlaylist(this, playlist!!.id).blockingFirst() + setToolbarTitle(playlist!!.name) + } + } + songsPresenter!!.subscribe() + } + + private fun setToolbarTitle(title: String) { + + supportActionBar!!.title = title + } + + private fun checkIsEmpty() { + empty.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE + } + + public override fun onPause() { + if (recyclerViewDragDropManager != null) { + recyclerViewDragDropManager!!.cancelDrag() + } + super.onPause() + songsPresenter!!.unsubscribe() + } + + override fun onDestroy() { + if (recyclerViewDragDropManager != null) { + recyclerViewDragDropManager!!.release() + recyclerViewDragDropManager = null + } + + if (recyclerView != null) { + recyclerView!!.itemAnimator = null + recyclerView!!.adapter = null + } + + if (wrappedAdapter != null) { + WrapperAdapterUtils.releaseAll(wrappedAdapter) + wrappedAdapter = null + } + super.onDestroy() + } + + override fun onPlayingMetaChanged() { + super.onPlayingMetaChanged() + songsPresenter!!.subscribe() + } + + override fun loading() {} + + override fun showEmptyView() { + empty!!.visibility = View.VISIBLE + } + + override fun completed() {} + + override fun showData(songs: ArrayList) { + adapter.swapDataSet(songs) + } + + companion object { + + var EXTRA_PLAYLIST = "extra_playlist" + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/ProVersionActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/ProVersionActivity.java index e2a8ea95..cd425bd6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/ProVersionActivity.java +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/ProVersionActivity.java @@ -27,7 +27,7 @@ import code.name.monkey.appthemehelper.util.MaterialUtil; import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; import code.name.monkey.retromusic.BuildConfig; import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.App; import code.name.monkey.retromusic.ui.activities.base.AbsBaseActivity; /** @@ -106,7 +106,7 @@ public class ProVersionActivity extends AbsBaseActivity implements } break; case R.id.purchase_button: - billingProcessor.purchase(ProVersionActivity.this, RetroApplication.PRO_VERSION_PRODUCT_ID); + billingProcessor.purchase(ProVersionActivity.this, App.PRO_VERSION_PRODUCT_ID); break; } } @@ -119,7 +119,7 @@ public class ProVersionActivity extends AbsBaseActivity implements @Override public void onPurchaseHistoryRestored() { - if (RetroApplication.Companion.isProVersion()) { + if (App.Companion.isProVersion()) { Toast.makeText(this, R.string.restored_previous_purchase_please_restart, Toast.LENGTH_LONG) .show(); setResult(RESULT_OK); diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/SettingsActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/SettingsActivity.java deleted file mode 100755 index b0e912ab..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/SettingsActivity.java +++ /dev/null @@ -1,163 +0,0 @@ -package code.name.monkey.retromusic.ui.activities; - -import android.content.SharedPreferences; -import android.os.Bundle; -import android.util.Log; -import android.view.MenuItem; -import android.widget.FrameLayout; -import android.widget.TextView; - -import com.afollestad.materialdialogs.color.ColorChooserDialog; -import com.google.android.material.appbar.AppBarLayout; - -import androidx.annotation.ColorInt; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; -import androidx.appcompat.widget.Toolbar; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentTransaction; -import androidx.transition.TransitionManager; -import butterknife.BindView; -import butterknife.ButterKnife; -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.ui.fragments.settings.MainSettingsFragment; -import code.name.monkey.retromusic.util.PreferenceUtil; - -public class SettingsActivity extends AbsBaseActivity implements ColorChooserDialog.ColorCallback, SharedPreferences.OnSharedPreferenceChangeListener { - - private static final String TAG = "SettingsActivity"; - - @BindView(R.id.toolbar) - Toolbar toolbar; - - @BindView(R.id.app_bar) - AppBarLayout appBarLayout; - - @BindView(R.id.title) - TextView title; - - @BindView(R.id.detail_content_frame) - @Nullable - FrameLayout detailsFrame; - - private FragmentManager fragmentManager = getSupportFragmentManager(); - - @Override - public void onColorSelection(@NonNull ColorChooserDialog dialog, @ColorInt int selectedColor) { - switch (dialog.getTitle()) { - case R.string.primary_color: - int theme = ColorUtil.isColorLight(selectedColor) ? - PreferenceUtil.getThemeResFromPrefValue("light") : - PreferenceUtil.getThemeResFromPrefValue("dark"); - - ThemeStore.editTheme(this).activityTheme(theme).primaryColor(selectedColor).commit(); - break; - case R.string.accent_color: - ThemeStore.editTheme(this).accentColor(selectedColor).commit(); - break; - } - - recreate(); - } - - @Override - public void onColorChooserDismissed(@NonNull ColorChooserDialog dialog) { - - } - - @Override - protected void onCreate(@Nullable Bundle bundle) { - super.onCreate(bundle); - setContentView(R.layout.activity_settings); - ButterKnife.bind(this); - - setStatusbarColorAuto(); - setNavigationbarColorAuto(); - - setLightNavigationBar(true); - - setupToolbar(); - - if (bundle == null) { - fragmentManager.beginTransaction().replace(R.id.content_frame, new MainSettingsFragment()) - .commit(); - } - } - - private void setupToolbar() { - 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)); - } - - public void setupFragment(Fragment fragment, @StringRes int titleName) { - FragmentTransaction fragmentTransaction = fragmentManager - .beginTransaction() - .setCustomAnimations(R.anim.sliding_in_left, R.anim.sliding_out_right, android.R.anim.slide_in_left, android.R.anim.slide_out_right); - - title.setText(titleName); - - if (detailsFrame == null) { - fragmentTransaction.replace(R.id.content_frame, fragment, fragment.getTag()); - fragmentTransaction.addToBackStack(null); - fragmentTransaction.commit(); - } else { - fragmentTransaction.replace(R.id.detail_content_frame, fragment, fragment.getTag()); - fragmentTransaction.commit(); - } - } - - @Override - public void onBackPressed() { - if (fragmentManager.getBackStackEntryCount() == 0) { - super.onBackPressed(); - } else { - title.setText(R.string.action_settings); - fragmentManager.popBackStack(); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - onBackPressed(); - return true; - } - return super.onOptionsItemSelected(item); - } - - public void addAppbarLayoutElevation(float v) { - TransitionManager.beginDelayedTransition(appBarLayout); - appBarLayout.setElevation(v); - } - - @Override - public void onPause() { - super.onPause(); - PreferenceUtil.getInstance().unregisterOnSharedPreferenceChangedListener(this); - } - - @Override - public void onResume() { - super.onResume(); - PreferenceUtil.getInstance().registerOnSharedPreferenceChangedListener(this); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - Log.i(TAG, "onSharedPreferenceChanged: "); - if (key.equals(PreferenceUtil.PROFILE_IMAGE_PATH)) { - recreate(); - } - } -} 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 new file mode 100755 index 00000000..e0fe1e00 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/SettingsActivity.kt @@ -0,0 +1,124 @@ +package code.name.monkey.retromusic.ui.activities + +import android.content.SharedPreferences +import android.os.Bundle +import android.view.MenuItem +import androidx.annotation.ColorInt +import androidx.annotation.StringRes +import androidx.fragment.app.Fragment +import butterknife.ButterKnife +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.ui.fragments.settings.MainSettingsFragment +import code.name.monkey.retromusic.util.PreferenceUtil +import com.afollestad.materialdialogs.color.ColorChooserDialog +import kotlinx.android.synthetic.main.activity_settings.* + +class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback, SharedPreferences.OnSharedPreferenceChangeListener { + + private val fragmentManager = supportFragmentManager + + override fun onColorSelection(dialog: ColorChooserDialog, @ColorInt selectedColor: Int) { + when (dialog.title) { + R.string.primary_color -> { + val theme = if (ColorUtil.isColorLight(selectedColor)) + PreferenceUtil.getThemeResFromPrefValue("light") + else + PreferenceUtil.getThemeResFromPrefValue("dark") + + ThemeStore.editTheme(this).activityTheme(theme).primaryColor(selectedColor).commit() + } + R.string.accent_color -> ThemeStore.editTheme(this).accentColor(selectedColor).commit() + } + recreate() + } + + override fun onColorChooserDismissed(dialog: ColorChooserDialog) { + + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_settings) + ButterKnife.bind(this) + + setStatusbarColorAuto() + setNavigationbarColorAuto() + + setLightNavigationBar(true) + + setupToolbar() + + if (savedInstanceState == null) { + fragmentManager.beginTransaction().replace(R.id.contentFrame, MainSettingsFragment()) + .commit() + } + } + + private fun setupToolbar() { + setSupportActionBar(toolbar) + title = null + toolbar.setBackgroundColor(ThemeStore.primaryColor(this)) + appBarLayout.setBackgroundColor(ThemeStore.primaryColor(this)) + toolbar.setNavigationOnClickListener { onBackPressed() } + settingsTitle.setTextColor(ThemeStore.textColorPrimary(this)) + ToolbarContentTintHelper.colorBackButton(toolbar, ThemeStore.accentColor(this)) + } + + fun setupFragment(fragment: Fragment, @StringRes titleName: Int) { + val fragmentTransaction = fragmentManager + .beginTransaction() + .setCustomAnimations(R.anim.sliding_in_left, R.anim.sliding_out_right, android.R.anim.slide_in_left, android.R.anim.slide_out_right) + + settingsTitle.setText(titleName) + + if (detailContentFrame == null) { + fragmentTransaction.replace(R.id.contentFrame, fragment, fragment.tag) + fragmentTransaction.addToBackStack(null) + fragmentTransaction.commit() + } else { + fragmentTransaction.replace(R.id.detailContentFrame, fragment, fragment.tag) + fragmentTransaction.commit() + } + } + + override fun onBackPressed() { + if (fragmentManager.backStackEntryCount == 0) { + super.onBackPressed() + } else { + settingsTitle.setText(R.string.action_settings) + fragmentManager.popBackStack() + } + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + if (item.itemId == android.R.id.home) { + onBackPressed() + return true + } + return super.onOptionsItemSelected(item) + } + + public override fun onPause() { + super.onPause() + PreferenceUtil.getInstance().unregisterOnSharedPreferenceChangedListener(this) + } + + public override fun onResume() { + super.onResume() + PreferenceUtil.getInstance().registerOnSharedPreferenceChangedListener(this) + } + + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { + if (key == PreferenceUtil.PROFILE_IMAGE_PATH) { + recreate() + } + } + + companion object { + const val TAG: String = "SettingsActivity" + } +} 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 index f70c5e94..d8a6d492 100644 --- 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 @@ -46,7 +46,7 @@ class WhatsNewActivity : AbsBaseActivity() { appBarLayout.setBackgroundColor(ThemeStore.primaryColor(this)) setSupportActionBar(toolbar) title = null - toolbar.setNavigationOnClickListener({ v -> onBackPressed() }) + toolbar.setNavigationOnClickListener { onBackPressed() } whatNewtitle.setTextColor(ThemeStore.textColorPrimary(this)) ToolbarContentTintHelper.colorBackButton(toolbar, ThemeStore.accentColor(this)) diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsBaseActivity.java b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsBaseActivity.java deleted file mode 100644 index 1c679cff..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsBaseActivity.java +++ /dev/null @@ -1,159 +0,0 @@ -package code.name.monkey.retromusic.ui.activities.base; - -import android.Manifest; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.media.AudioManager; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.provider.Settings; -import android.view.KeyEvent; -import android.view.View; -import android.view.ViewGroup; - -import com.google.android.material.snackbar.Snackbar; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.app.ActivityCompat; -import androidx.core.view.ViewCompat; -import code.name.monkey.appthemehelper.ThemeStore; -import code.name.monkey.retromusic.R; -import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; - - -public abstract class AbsBaseActivity extends AbsThemeActivity { - - public static final int PERMISSION_REQUEST = 100; - private boolean hadPermissions; - private String[] permissions; - private String permissionDeniedMessage; - - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setVolumeControlStream(AudioManager.STREAM_MUSIC); - - permissions = getPermissionsToRequest(); - hadPermissions = hasPermissions(); - - setPermissionDeniedMessage(null); - } - - @Override - protected void onPostCreate(@Nullable Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - if (!hasPermissions()) { - requestPermissions(); - } - } - - @Override - protected void onResume() { - super.onResume(); - final boolean hasPermissions = hasPermissions(); - if (hasPermissions != hadPermissions) { - hadPermissions = hasPermissions; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - onHasPermissionsChanged(hasPermissions); - } - } - } - - protected void onHasPermissionsChanged(boolean hasPermissions) { - // implemented by sub classes - } - - @Override - public boolean dispatchKeyEvent(@NonNull KeyEvent event) { - if (event.getKeyCode() == KeyEvent.KEYCODE_MENU && event.getAction() == KeyEvent.ACTION_UP) { - showOverflowMenu(); - return true; - } - return super.dispatchKeyEvent(event); - } - - protected void showOverflowMenu() { - - } - - @Override - protected void attachBaseContext(Context newBase) { - super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); - } - - @Nullable - protected String[] getPermissionsToRequest() { - return null; - } - - protected View getSnackBarContainer() { - return getWindow().getDecorView(); - } - - private String getPermissionDeniedMessage() { - return permissionDeniedMessage == null ? getString(R.string.permissions_denied) - : permissionDeniedMessage; - } - - protected void setPermissionDeniedMessage(String message) { - permissionDeniedMessage = message; - } - - protected void requestPermissions() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && permissions != null) { - requestPermissions(permissions, PERMISSION_REQUEST); - } - } - - protected boolean hasPermissions() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && permissions != null) { - for (String permission : permissions) { - if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { - return false; - } - } - } - return true; - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, - @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - if (requestCode == PERMISSION_REQUEST) { - for (int grantResult : grantResults) { - if (grantResult != PackageManager.PERMISSION_GRANTED) { - if (ActivityCompat.shouldShowRequestPermissionRationale(AbsBaseActivity.this, - Manifest.permission.WRITE_EXTERNAL_STORAGE)) { - //User has deny from permission dialog - Snackbar.make(getSnackBarContainer(), getPermissionDeniedMessage(), - Snackbar.LENGTH_INDEFINITE) - .setAction(R.string.action_grant, view -> requestPermissions()) - .setActionTextColor(ThemeStore.accentColor(this)) - .show(); - } else { - // User has deny permission and checked never show permission dialog so you can redirect to Application settings page - Snackbar.make(getSnackBarContainer(), getPermissionDeniedMessage(), - Snackbar.LENGTH_INDEFINITE) - .setAction(R.string.action_settings, view -> { - Intent intent = new Intent(); - intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - Uri uri = Uri.fromParts("package", AbsBaseActivity.this.getPackageName(), null); - intent.setData(uri); - startActivity(intent); - }) - .setActionTextColor(ThemeStore.accentColor(this)) - .show(); - } - return; - } - } - hadPermissions = true; - onHasPermissionsChanged(true); - } - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsBaseActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsBaseActivity.kt index 25850c50..5bbafb05 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsBaseActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsBaseActivity.kt @@ -1,7 +1,6 @@ package code.name.monkey.retromusic.ui.activities.base import android.Manifest -import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.media.AudioManager @@ -15,17 +14,16 @@ import androidx.core.app.ActivityCompat import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.retromusic.R import com.google.android.material.snackbar.Snackbar -import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper abstract class AbsBaseActivity : AbsThemeActivity() { private var hadPermissions: Boolean = false - private var permissions: Array? = null + private lateinit var permissions: Array private var permissionDeniedMessage: String? = null - open fun getPermissionsToRequest(): Array? { - return null + open fun getPermissionsToRequest(): Array { + return arrayOf() } protected fun setPermissionDeniedMessage(message: String) { @@ -82,20 +80,16 @@ abstract class AbsBaseActivity : AbsThemeActivity() { protected fun showOverflowMenu() { } - - override fun attachBaseContext(newBase: Context) { - super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)) - } - + protected open fun requestPermissions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - requestPermissions(permissions!!, PERMISSION_REQUEST) + requestPermissions(permissions, PERMISSION_REQUEST) } } protected fun hasPermissions(): Boolean { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - for (permission in permissions!!) { + for (permission in permissions) { if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { return false } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsMusicServiceActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsMusicServiceActivity.kt index 086c9786..e22fb801 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsMusicServiceActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsMusicServiceActivity.kt @@ -138,7 +138,7 @@ abstract class AbsMusicServiceActivity : AbsCastActivity(), MusicServiceEventLis } - override fun getPermissionsToRequest(): Array? { + override fun getPermissionsToRequest(): Array { return arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE) } @@ -163,6 +163,6 @@ abstract class AbsMusicServiceActivity : AbsCastActivity(), MusicServiceEventLis } companion object { - val TAG = AbsMusicServiceActivity::class.java.simpleName + val TAG: String = AbsMusicServiceActivity::class.java.simpleName } } 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 d41255e7..6035d437 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 @@ -21,6 +21,10 @@ import code.name.monkey.retromusic.ui.fragments.NowPlayingScreen import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.ui.fragments.player.adaptive.AdaptiveFragment import code.name.monkey.retromusic.ui.fragments.player.blur.BlurPlayerFragment +import code.name.monkey.retromusic.ui.fragments.player.card.CardFragment +import code.name.monkey.retromusic.ui.fragments.player.cardblur.CardBlurFragment +import code.name.monkey.retromusic.ui.fragments.player.fit.FitFragment +import code.name.monkey.retromusic.ui.fragments.player.normal.PlayerFragment import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.views.BottomNavigationBarTinted import com.google.android.material.bottomnavigation.BottomNavigationView @@ -58,7 +62,7 @@ abstract class AbsSlidingMusicPanelActivity protected constructor() : AbsMusicSe slidingUpPanelLayout = findViewById(R.id.sliding_layout); bottomNavigationView = findViewById(R.id.bottom_navigation); - choosFragmentForTheme() + chooseFragmentForTheme() setupSlidingUpPanel() } @@ -207,22 +211,23 @@ abstract class AbsSlidingMusicPanelActivity protected constructor() : AbsMusicSe miniPlayerFragment!!.view!!.visibility = if (alpha == 0f) View.GONE else View.VISIBLE } - private fun choosFragmentForTheme() { + private fun chooseFragmentForTheme() { currentNowPlayingScreen = PreferenceUtil.getInstance().nowPlayingScreen - val fragment: Fragment // must implement AbsPlayerFragment - when (currentNowPlayingScreen) { - NowPlayingScreen.BLUR -> fragment = BlurPlayerFragment() - NowPlayingScreen.ADAPTIVE -> fragment = AdaptiveFragment() - else -> fragment = AdaptiveFragment() - } + val fragment: Fragment = when (currentNowPlayingScreen) { + NowPlayingScreen.BLUR -> BlurPlayerFragment() + NowPlayingScreen.ADAPTIVE -> AdaptiveFragment() + NowPlayingScreen.NORMAL -> PlayerFragment() + NowPlayingScreen.CARD -> CardFragment() + NowPlayingScreen.BLUR_CARD -> CardBlurFragment() + NowPlayingScreen.FIT -> FitFragment() + else -> PlayerFragment() + } // must implement AbsPlayerFragment supportFragmentManager.beginTransaction().replace(R.id.player_fragment_container, fragment).commit() supportFragmentManager.executePendingTransactions() - playerFragment = supportFragmentManager.findFragmentById(R.id.player_fragment_container) as AbsPlayerFragment? - miniPlayerFragment = supportFragmentManager.findFragmentById(R.id.mini_player_fragment) as MiniPlayerFragment? - - + playerFragment = supportFragmentManager.findFragmentById(R.id.player_fragment_container) as AbsPlayerFragment + miniPlayerFragment = supportFragmentManager.findFragmentById(R.id.mini_player_fragment) as MiniPlayerFragment miniPlayerFragment!!.view!!.setOnClickListener { expandPanel() } } @@ -296,6 +301,6 @@ abstract class AbsSlidingMusicPanelActivity protected constructor() : AbsMusicSe companion object { - val TAG = AbsSlidingMusicPanelActivity::class.java.simpleName + val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsThemeActivity.kt b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsThemeActivity.kt index a88a03e6..fb99ef1b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsThemeActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/activities/base/AbsThemeActivity.kt @@ -96,15 +96,16 @@ abstract class AbsThemeActivity : ATHActivity(), Runnable { if (VersionUtils.hasKitKat()) { val statusBar = window.decorView.rootView.findViewById(R.id.status_bar) if (statusBar != null) { - if (VersionUtils.hasMarshmallow()) { - window.statusBarColor = color - } else if (VersionUtils.hasLollipop()) { - statusBar.setBackgroundColor(ColorUtil.darkenColor(color)) - } else { - statusBar.setBackgroundColor(color) + when { + VersionUtils.hasMarshmallow() -> window.statusBarColor = color + VersionUtils.hasLollipop() -> statusBar.setBackgroundColor(ColorUtil.darkenColor(color)) + else -> statusBar.setBackgroundColor(color) } } else if (Build.VERSION.SDK_INT >= 21) { - window.statusBarColor = ColorUtil.darkenColor(color) + when { + VersionUtils.hasMarshmallow() -> window.statusBarColor = color + else -> window.statusBarColor = ColorUtil.darkenColor(color) + } } } setLightStatusbarAuto(color) diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/CollageSongAdapter.java b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/CollageSongAdapter.java index 4e955f2c..166f7f65 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/CollageSongAdapter.java +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/CollageSongAdapter.java @@ -70,8 +70,7 @@ public class CollageSongAdapter extends RecyclerView.Adapter imageViews; @@ -80,14 +79,12 @@ public class CollageSongAdapter extends RecyclerView.Adapter { - MusicPlayerRemote.INSTANCE.openQueue(dataSet, 0, true); - }); - view.setBackgroundColor(color); - view.setTextColor(MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(color))); + //ButterKnife.bind(this, itemView); + //Context context = itemView.getContext(); + //int color = ThemeStore.accentColor(context); + //view.setOnClickListener(v -> MusicPlayerRemote.INSTANCE.openQueue(dataSet, 0, true)); + //view.setBackgroundColor(color); + //view.setTextColor(MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(color))); } void bindSongs() { diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/AbsOffsetSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/AbsOffsetSongAdapter.kt index 4329ea2b..92e25f58 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/AbsOffsetSongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/AbsOffsetSongAdapter.kt @@ -61,7 +61,7 @@ abstract class AbsOffsetSongAdapter : SongAdapter { override// could also return null, just to be safe return empty song val song: Song - get() = if (itemViewType == OFFSET_ITEM) Song.EMPTY_SONG else dataSet[adapterPosition - 1] + get() = if (itemViewType == OFFSET_ITEM) Song.emptySong else dataSet[adapterPosition - 1] override fun onClick(v: View?) { if (isInQuickSelectMode && itemViewType != OFFSET_ITEM) { diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/OrderablePlaylistSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/OrderablePlaylistSongAdapter.kt index a55a548f..8889c516 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/OrderablePlaylistSongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/adapter/song/OrderablePlaylistSongAdapter.kt @@ -36,7 +36,7 @@ class OrderablePlaylistSongAdapter(activity: AppCompatActivity, positionFinal-- var long: Long = 0 - if (position < 0) { + if (positionFinal < 0) { long = -2 } else { if (dataSet[positionFinal] is PlaylistSong) { diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/MiniPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/MiniPlayerFragment.kt index d627fd68..34d90346 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/MiniPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/MiniPlayerFragment.kt @@ -10,7 +10,6 @@ import android.text.SpannableStringBuilder import android.text.style.ForegroundColorSpan import android.view.* import android.view.animation.DecelerateInterpolator -import butterknife.OnClick import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.retromusic.R import code.name.monkey.retromusic.helper.MusicPlayerRemote @@ -76,7 +75,7 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(), MusicProgressViewUpda private fun updateSongTitle() { val builder = SpannableStringBuilder() - val song = MusicPlayerRemote.currentSong ?: return + val song = MusicPlayerRemote.currentSong val title = SpannableString(song.title) title.setSpan(ForegroundColorSpan(ThemeStore.textColorPrimary(context!!)), 0, title.length, 0) diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/NowPlayingScreen.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/NowPlayingScreen.java index 59f4288e..5b74e577 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/NowPlayingScreen.java +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/NowPlayingScreen.java @@ -6,9 +6,19 @@ import code.name.monkey.retromusic.R; public enum NowPlayingScreen { - + NORMAL(R.string.normal, R.drawable.np_normal, 0), + 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), - BLUR(R.string.blur, R.drawable.np_blur, 4); + //MATERIAL(R.string.material, R.drawable.np_material, 11), + FIT(R.string.fit, R.drawable.np_adaptive, 12); @StringRes public final int titleRes; diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/PlayingQueueFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/PlayingQueueFragment.java deleted file mode 100644 index 6f6865d7..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/PlayingQueueFragment.java +++ /dev/null @@ -1,148 +0,0 @@ -package code.name.monkey.retromusic.ui.fragments; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator; -import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator; -import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager; -import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.Unbinder; -import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.helper.MusicPlayerRemote; -import code.name.monkey.retromusic.ui.adapter.song.PlayingQueueAdapter; -import code.name.monkey.retromusic.ui.fragments.base.AbsMusicServiceFragment; -import code.name.monkey.retromusic.views.CollapsingFAB; - -public class PlayingQueueFragment extends AbsMusicServiceFragment { - - @BindView(R.id.recycler_view) - RecyclerView mRecyclerView; - - - Unbinder unbinder; - - private RecyclerView.Adapter mWrappedAdapter; - private RecyclerViewDragDropManager mRecyclerViewDragDropManager; - private PlayingQueueAdapter mPlayingQueueAdapter; - private LinearLayoutManager mLayoutManager; - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_main_activity_recycler_view, container, false); - unbinder = ButterKnife.bind(this, view); - return view; - } - - @Override - public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setUpRecyclerView(); - } - - private void setUpRecyclerView() { - mRecyclerViewDragDropManager = new RecyclerViewDragDropManager(); - final GeneralItemAnimator animator = new RefactoredDefaultItemAnimator(); - - mPlayingQueueAdapter = new PlayingQueueAdapter( - (AppCompatActivity) getActivity(), - MusicPlayerRemote.INSTANCE.getPlayingQueue(), - MusicPlayerRemote.INSTANCE.getPosition(), - R.layout.item_queue); - mWrappedAdapter = mRecyclerViewDragDropManager.createWrappedAdapter(mPlayingQueueAdapter); - - mLayoutManager = new LinearLayoutManager(getContext()); - - mRecyclerView.setLayoutManager(mLayoutManager); - mRecyclerView.setAdapter(mWrappedAdapter); - mRecyclerView.setItemAnimator(animator); - mRecyclerViewDragDropManager.attachRecyclerView(mRecyclerView); - mLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.INSTANCE.getPosition() + 1, 0); - - } - - @Override - public void onQueueChanged() { - updateQueue(); - updateCurrentSong(); - } - - @Override - public void onMediaStoreChanged() { - updateQueue(); - updateCurrentSong(); - } - - @SuppressWarnings("ConstantConditions") - private void updateCurrentSong() { - } - - @Override - public void onPlayingMetaChanged() { - //updateCurrentSong(); - //updateIsFavorite(); - updateQueuePosition(); - //updateLyrics(); - } - - private void updateQueuePosition() { - mPlayingQueueAdapter.setCurrent(MusicPlayerRemote.INSTANCE.getPosition()); - // if (slidingUpPanelLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) { - resetToCurrentPosition(); - //} - } - - private void updateQueue() { - mPlayingQueueAdapter - .swapDataSet(MusicPlayerRemote.INSTANCE.getPlayingQueue(), MusicPlayerRemote.INSTANCE.getPosition()); - resetToCurrentPosition(); - } - - private void resetToCurrentPosition() { - mRecyclerView.stopScroll(); - mLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.INSTANCE.getPosition() + 1, 0); - } - - @Override - public void onPause() { - if (mRecyclerViewDragDropManager != null) { - mRecyclerViewDragDropManager.cancelDrag(); - } - super.onPause(); - } - - @Override - public void onDestroyView() { - if (mRecyclerViewDragDropManager != null) { - mRecyclerViewDragDropManager.release(); - mRecyclerViewDragDropManager = null; - } - - if (mRecyclerView != null) { - mRecyclerView.setItemAnimator(null); - mRecyclerView.setAdapter(null); - mRecyclerView = null; - } - - if (mWrappedAdapter != null) { - WrapperAdapterUtils.releaseAll(mWrappedAdapter); - mWrappedAdapter = null; - } - mPlayingQueueAdapter = null; - mLayoutManager = null; - super.onDestroyView(); - unbinder.unbind(); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/VolumeFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/VolumeFragment.kt index 3fb07eea..5202281e 100755 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/VolumeFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/VolumeFragment.kt @@ -47,19 +47,19 @@ class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolum val audioManager = audioManager if (audioManager != null) { - volumeSeekBar!!.max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) - volumeSeekBar!!.progress = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) + volumeSeekBar.max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) + volumeSeekBar.progress = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) } - volumeSeekBar!!.setOnSeekBarChangeListener(this) + volumeSeekBar.setOnSeekBarChangeListener(this) } override fun onAudioVolumeChanged(currentVolume: Int, maxVolume: Int) { if (volumeSeekBar == null) { return } - volumeSeekBar!!.max = maxVolume - volumeSeekBar!!.progress = currentVolume - volumeDown!!.setImageResource(if (currentVolume == 0) R.drawable.ic_volume_off_white_24dp else R.drawable.ic_volume_down_white_24dp) + volumeSeekBar.max = maxVolume + volumeSeekBar.progress = currentVolume + volumeDown.setImageResource(if (currentVolume == 0) R.drawable.ic_volume_off_white_24dp else R.drawable.ic_volume_down_white_24dp) } override fun onDestroyView() { @@ -98,9 +98,9 @@ class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolum } private fun setProgressBarColor(newColor: Int) { - TintHelper.setTintAuto(volumeSeekBar!!, newColor, false) - volumeDown!!.setColorFilter(newColor, PorterDuff.Mode.SRC_IN) - volumeUp!!.setColorFilter(newColor, PorterDuff.Mode.SRC_IN) + TintHelper.setTintAuto(volumeSeekBar, newColor, false) + volumeDown.setColorFilter(newColor, PorterDuff.Mode.SRC_IN) + volumeUp.setColorFilter(newColor, PorterDuff.Mode.SRC_IN) } private fun setTintable(color: Int) { @@ -108,7 +108,7 @@ class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolum } fun removeThumb() { - volumeSeekBar!!.thumb = null + volumeSeekBar.thumb = null } private fun setPauseWhenZeroVolume(pauseWhenZeroVolume: Boolean) { diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerControlsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerControlsFragment.kt index efe3631c..239e3103 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerControlsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerControlsFragment.kt @@ -55,7 +55,7 @@ abstract class AbsPlayerControlsFragment : AbsMusicServiceFragment(), MusicProgr } - var prevButton: ImageButton? = null + /* var prevButton: ImageButton? = null var nextButton: ImageButton? = null var repeatButton: ImageButton? = null var shuffleButton: ImageButton? = null @@ -63,11 +63,12 @@ abstract class AbsPlayerControlsFragment : AbsMusicServiceFragment(), MusicProgr var songTotalTime: TextView? = null var songCurrentProgress: TextView? = null var volumeContainer: View? = null - var playPauseFab: ImageButton? = null + var playPauseFab: ImageButton? = null*/ override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - playPauseFab = view.findViewById(R.id.player_play_pause_button) + + /* playPauseFab = view.findViewById(R.id.player_play_pause_button) prevButton = view.findViewById(R.id.player_prev_button) nextButton = view.findViewById(R.id.player_next_button) repeatButton = view.findViewById(R.id.player_repeat_button) @@ -75,6 +76,6 @@ abstract class AbsPlayerControlsFragment : AbsMusicServiceFragment(), MusicProgr progressSlider = view.findViewById(R.id.player_progress_slider) songTotalTime = view.findViewById(R.id.player_song_total_time) songCurrentProgress = view.findViewById(R.id.player_song_current_progress) - volumeContainer = view.findViewById(R.id.volume_fragment_container) + volumeContainer = view.findViewById(R.id.volume_fragment_container)*/ } } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerFragment.kt index 4eff06f4..80286a76 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/base/AbsPlayerFragment.kt @@ -32,8 +32,6 @@ abstract class AbsPlayerFragment : AbsMusicServiceFragment(), Toolbar.OnMenuItem private set private var updateIsFavoriteTask: AsyncTask<*, *, *>? = null - protected var toolbar: Toolbar? = null - override fun onAttach(context: Context?) { super.onAttach(context) @@ -146,6 +144,8 @@ abstract class AbsPlayerFragment : AbsMusicServiceFragment(), Toolbar.OnMenuItem MusicUtil.toggleFavorite(activity!!, song) } + abstract fun toolbarGet(): Toolbar + abstract fun onShow() abstract fun onHide() @@ -193,7 +193,7 @@ abstract class AbsPlayerFragment : AbsMusicServiceFragment(), Toolbar.OnMenuItem else R.drawable.ic_favorite_border_white_24dp val drawable = RetroUtil.getTintedVectorDrawable(activity, res, toolbarIconColor()) - //toolbar!!.menu.findItem(R.id.action_toggle_favorite).setIcon(drawable).title = if (isFavorite) getString(R.string.action_remove_from_favorites) else getString(R.string.action_add_to_favorites) + toolbarGet().menu.findItem(R.id.action_toggle_favorite).setIcon(drawable).title = if (isFavorite) getString(R.string.action_remove_from_favorites) else getString(R.string.action_add_to_favorites) } } }.execute(MusicPlayerRemote.currentSong) diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/GenreFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/GenreFragment.kt index 84054572..519cdc3f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/GenreFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/GenreFragment.kt @@ -1,12 +1,9 @@ package code.name.monkey.retromusic.ui.fragments.mainactivity import android.os.Bundle -import androidx.recyclerview.widget.LinearLayoutManager import android.view.Menu import android.view.MenuInflater - -import java.util.ArrayList - +import androidx.recyclerview.widget.LinearLayoutManager import code.name.monkey.retromusic.R import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.mvp.contract.GenreContract @@ -14,6 +11,7 @@ import code.name.monkey.retromusic.mvp.presenter.GenrePresenter import code.name.monkey.retromusic.ui.adapter.GenreAdapter import code.name.monkey.retromusic.ui.fragments.base.AbsLibraryPagerRecyclerViewFragment import code.name.monkey.retromusic.util.PreferenceUtil +import java.util.* class GenreFragment : AbsLibraryPagerRecyclerViewFragment(), GenreContract.GenreView { 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 index a9d4b4e0..9ea0ad93 100644 --- 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 @@ -7,7 +7,6 @@ import android.widget.TextView import androidx.annotation.StringRes import androidx.appcompat.widget.Toolbar import androidx.fragment.app.Fragment -import butterknife.Unbinder import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.common.ATHToolbarActivity import code.name.monkey.appthemehelper.util.ATHUtil @@ -109,10 +108,7 @@ class LibraryFragment : AbsMainActivityFragment(), CabHolder, MainActivityFragme appbar.addOnOffsetChangedListener(this) mainActivity.title = null mainActivity.setSupportActionBar(toolbar) - - toolbar.setNavigationOnClickListener { NavigationUtil.goToSearch(mainActivity) } - toolbar.setOnClickListener { showMainMenu() } - toolbar.navigationIcon = RetroUtil.getTintedDrawable(mainActivity, R.drawable.ic_search_white_24dp, ThemeStore.textColorPrimary(mainActivity)) + toolbar.navigationIcon = RetroUtil.getTintedDrawable(mainActivity, R.drawable.ic_menu_white_24dp, ThemeStore.textColorPrimary(mainActivity)) } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/folders/FoldersFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/folders/FoldersFragment.java index 1fd8b121..5ab19f72 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/folders/FoldersFragment.java +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/mainactivity/folders/FoldersFragment.java @@ -40,7 +40,6 @@ import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; import code.name.monkey.appthemehelper.ThemeStore; @@ -74,8 +73,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements AppBarLayout.OnOffsetChangedListener, LoaderManager.LoaderCallbacks> { public static final String TAG = FoldersFragment.class.getSimpleName(); - public static final FileFilter AUDIO_FILE_FILTER = file -> !file.isHidden() && (file.isDirectory() - || + public static final FileFilter AUDIO_FILE_FILTER = file -> !file.isHidden() && (file.isDirectory() || FileUtil.fileIsMimeType(file, "audio/*", MimeTypeMap.getSingleton()) || FileUtil.fileIsMimeType(file, "application/opus", MimeTypeMap.getSingleton()) || FileUtil.fileIsMimeType(file, "application/ogg", MimeTypeMap.getSingleton())); @@ -83,30 +81,18 @@ public class FoldersFragment extends AbsMainActivityFragment implements private static final String PATH = "path"; private static final String CRUMBS = "crumbs"; private static final int LOADER_ID = LoaderIds.Companion.getFOLDERS_FRAGMENT(); - @BindView(R.id.coordinator_layout) - View coordinatorLayout; - @BindView(R.id.container) - View container; + private View coordinatorLayout, container, empty; - @BindView(R.id.title) - TextView title; + private TextView title; - @BindView(android.R.id.empty) - View empty; + private Toolbar toolbar; - @BindView(R.id.toolbar) - Toolbar toolbar; + private BreadCrumbLayout breadCrumbs; - @BindView(R.id.bread_crumbs) - BreadCrumbLayout breadCrumbs; - - @BindView(R.id.app_bar) - AppBarLayout appbar; - - @BindView(R.id.recycler_view) - FastScrollRecyclerView recyclerView; + private AppBarLayout appBarLayout; + private FastScrollRecyclerView recyclerView; private Comparator fileComparator = (lhs, rhs) -> { if (lhs.isDirectory() && !rhs.isDirectory()) { @@ -118,10 +104,8 @@ public class FoldersFragment extends AbsMainActivityFragment implements (rhs.getName()); } }; - private Unbinder unbinder; private SongFileAdapter adapter; private MaterialCab cab; - public FoldersFragment() { } @@ -162,6 +146,17 @@ public class FoldersFragment extends AbsMainActivityFragment implements } } + private void initViews(View view) { + coordinatorLayout = view.findViewById(R.id.coordinatorLayout); + recyclerView = view.findViewById(R.id.recyclerView); + appBarLayout = view.findViewById(R.id.appBarLayout); + breadCrumbs = view.findViewById(R.id.breadCrumbs); + toolbar = view.findViewById(R.id.toolbar); + empty = view.findViewById(android.R.id.empty); + title = view.findViewById(R.id.bannerTitle); + container = view.findViewById(R.id.container); + } + private void setCrumb(BreadCrumbLayout.Crumb crumb, boolean addToHistory) { if (crumb == null) { return; @@ -215,15 +210,13 @@ public class FoldersFragment extends AbsMainActivityFragment implements public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_folder, container, false); - unbinder = ButterKnife.bind(this, view); + initViews(view); return view; } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { setStatusbarColorAuto(view); - //getMainActivity().getSlidingUpPanelLayout().setShadowHeight(0); - setUpAppbarColor(); setUpBreadCrumbs(); setUpRecyclerView(); @@ -238,18 +231,17 @@ public class FoldersFragment extends AbsMainActivityFragment implements int primaryColor = ThemeStore.primaryColor(getContext()); - toolbar.setNavigationIcon(R.drawable.ic_keyboard_backspace_black_24dp); + toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp); //noinspection ConstantConditions getActivity().setTitle(null); getMainActivity().setSupportActionBar(toolbar); - toolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed()); TintHelper.setTintAuto(container, primaryColor, true); - appbar.setBackgroundColor(primaryColor); + appBarLayout.setBackgroundColor(primaryColor); toolbar.setBackgroundColor(primaryColor); breadCrumbs.setActivatedContentColor(ToolbarContentTintHelper.toolbarTitleColor(getActivity(), ColorUtil.darkenColor(primaryColor))); breadCrumbs.setDeactivatedContentColor(ToolbarContentTintHelper.toolbarSubtitleColor(getActivity(), ColorUtil.darkenColor(primaryColor))); - appbar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> getMainActivity().setLightStatusbar(!ATHUtil.isWindowBackgroundDark(getContext()))); + appBarLayout.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> getMainActivity().setLightStatusbar(!ATHUtil.isWindowBackgroundDark(getContext()))); } private void setUpBreadCrumbs() { @@ -261,7 +253,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements ViewUtil.setUpFastScrollRecyclerViewColor(getActivity(), recyclerView, ThemeStore.accentColor(getActivity())); recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); - appbar.addOnOffsetChangedListener(this); + appBarLayout.addOnOffsetChangedListener(this); } private void setUpAdapter() { @@ -286,8 +278,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements @Override public void onDestroyView() { - appbar.removeOnOffsetChangedListener(this); - unbinder.unbind(); + appBarLayout.removeOnOffsetChangedListener(this); super.onDestroyView(); } @@ -473,7 +464,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { container.setPadding(container.getPaddingLeft(), container.getPaddingTop(), - container.getPaddingRight(), appbar.getTotalScrollRange() + verticalOffset); + container.getPaddingRight(), this.appBarLayout.getTotalScrollRange() + verticalOffset); } private void checkIsEmpty() { 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 4b56b5b4..273ab2a9 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 @@ -1,18 +1,19 @@ package code.name.monkey.retromusic.ui.fragments.mainactivity.home import android.graphics.Bitmap +import android.graphics.Color import android.os.Bundle import android.util.DisplayMetrics import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView +import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import butterknife.OnClick import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.retromusic.Constants.USER_BANNER import code.name.monkey.retromusic.Constants.USER_PROFILE import code.name.monkey.retromusic.R @@ -34,80 +35,37 @@ import code.name.monkey.retromusic.util.Compressor import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.RetroUtil -import code.name.monkey.retromusic.views.CircularImageView -import code.name.monkey.retromusic.views.MetalRecyclerViewPager import com.bumptech.glide.Glide 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 import java.util.* class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallbacks, HomeContract.HomeView { + val disposable: CompositeDisposable = CompositeDisposable() + private lateinit var homePresenter: HomePresenter + private lateinit var contentContainerView: View + private lateinit var lastAdded: View + private lateinit var topPlayed: View + private lateinit var actionShuffle: View + private lateinit var history: View + private lateinit var userImage: ImageView + private lateinit var toolbar: Toolbar - override fun onCreateView(inflater: LayoutInflater, viewGroup: ViewGroup?, - savedInstanceState: Bundle?): View? { - val view = inflater.inflate(if (PreferenceUtil.getInstance().isHomeBanner) R.layout.fragment_banner_home else R.layout.fragment_home, viewGroup, false) - - if (!PreferenceUtil.getInstance().isHomeBanner) - setStatusbarColorAuto(view) - - imageView = view.findViewById(R.id.image) - userImage = view.findViewById(R.id.user_image) - recentArtistRV = view.findViewById(R.id.recycler_view) - recentAlbumRV = view.findViewById(R.id.recent_album) - topArtistRV = view.findViewById(R.id.top_artist) - topAlbumRV = view.findViewById(R.id.top_album) - recentArtistContainer = view.findViewById(R.id.recent_artist_container) - recentAlbumsContainer = view.findViewById(R.id.recent_albums_container) - topArtistContainer = view.findViewById(R.id.top_artist_container) - topAlbumContainer = view.findViewById(R.id.top_albums_container) - genresRecyclerView = view.findViewById(R.id.genres) - genreContainer = view.findViewById(R.id.genre_container) - contentContainer = view.findViewById(R.id.content_container) - container = view.findViewById(R.id.container) - suggestionsSongs = view.findViewById(R.id.suggestion_songs) - suggestionsContainer = view.findViewById(R.id.suggestion_container) - - /* lastAdded.setOnClickListener { - NavigationUtil.goToPlaylistNew(activity!!, LastAddedPlaylist(activity!!)) - } - topPlayed.setOnClickListener { - NavigationUtil.goToPlaylistNew(activity!!, MyTopTracksPlaylist(activity!!)) - } - actionShuffle.setOnClickListener { - MusicPlayerRemote.openAndShuffleQueue(SongLoader.getAllSongs(activity!!).blockingFirst(), true) - } - history.setOnClickListener { - NavigationUtil.goToPlaylistNew(activity!!, HistoryPlaylist(activity!!)) - }*/ - userImage.setOnClickListener { - NavigationUtil.goToUserInfo(activity!!) - } - return view + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + mainActivity.setBottomBarVisibility(View.GONE) + } + + override fun onCreateView(inflater: LayoutInflater, viewGroup: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(if (PreferenceUtil.getInstance().isHomeBanner) R.layout.fragment_banner_home else R.layout.fragment_home, viewGroup, false) } - private var imageView: ImageView? = null - private lateinit var userImage: CircularImageView - private lateinit var recentAlbumRV: MetalRecyclerViewPager - private lateinit var topAlbumRV: MetalRecyclerViewPager - private lateinit var topArtistRV: RecyclerView - private lateinit var genresRecyclerView: RecyclerView - private lateinit var suggestionsSongs: RecyclerView - private lateinit var recentArtistRV: RecyclerView - private lateinit var recentArtistContainer: View - private lateinit var recentAlbumsContainer: View - private lateinit var topArtistContainer: View - private lateinit var topAlbumContainer: View - private lateinit var genreContainer: View - private lateinit var container: View - private lateinit var contentContainer: View - private lateinit var suggestionsContainer: View - private lateinit var homePresenter: HomePresenter - val disposable: CompositeDisposable = CompositeDisposable() private val displayMetrics: DisplayMetrics get() { @@ -122,16 +80,12 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba val timeOfDay = c.get(Calendar.HOUR_OF_DAY) var images = arrayOf() - if (timeOfDay in 0..5) { - images = resources.getStringArray(R.array.night) - } else if (timeOfDay in 6..11) { - images = resources.getStringArray(R.array.morning) - } else if (timeOfDay in 12..15) { - images = resources.getStringArray(R.array.after_noon) - } else if (timeOfDay in 16..19) { - images = resources.getStringArray(R.array.evening) - } else if (timeOfDay in 20..23) { - images = resources.getStringArray(R.array.night) + when (timeOfDay) { + in 0..5 -> images = resources.getStringArray(R.array.night) + in 6..11 -> images = resources.getStringArray(R.array.morning) + in 12..15 -> images = resources.getStringArray(R.array.after_noon) + in 16..19 -> images = resources.getStringArray(R.array.evening) + in 20..23 -> images = resources.getStringArray(R.array.night) } val day = images[Random().nextInt(images.size)] @@ -141,47 +95,39 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba private fun loadTimeImage(day: String) { - if (imageView != null) { + if (bannerImage != null) { if (PreferenceUtil.getInstance().bannerImage.isEmpty()) { Glide.with(activity).load(day) .asBitmap() .placeholder(R.drawable.material_design_default) .diskCacheStrategy(DiskCacheStrategy.SOURCE) - .into(imageView!!) + .into(bannerImage!!) } else { - loadBannerFromStorage() + + disposable.add(Compressor(context!!) + .setQuality(100) + .setCompressFormat(Bitmap.CompressFormat.WEBP) + .compressToBitmapAsFlowable(File(PreferenceUtil.getInstance().bannerImage, USER_BANNER)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { bannerImage!!.setImageBitmap(it) }) } } } - private fun loadBannerFromStorage() { - - disposable.add(Compressor(context!!) - .setQuality(100) - .setCompressFormat(Bitmap.CompressFormat.WEBP) - .compressToBitmapAsFlowable( - File(PreferenceUtil.getInstance().bannerImage, USER_BANNER)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { imageView!!.setImageBitmap(it) }) - } - private fun loadImageFromStorage(imageView: ImageView) { - disposable.add(Compressor(context!!) .setMaxHeight(300) .setMaxWidth(300) .setQuality(75) .setCompressFormat(Bitmap.CompressFormat.WEBP) - .compressToBitmapAsFlowable( - File(PreferenceUtil.getInstance().profileImage, USER_PROFILE)) + .compressToBitmapAsFlowable(File(PreferenceUtil.getInstance().profileImage, USER_PROFILE)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ imageView.setImageBitmap(it) }) { - imageView.setImageDrawable(ContextCompat - .getDrawable(context!!, R.drawable.ic_person_flat)) + imageView.setImageDrawable(ContextCompat.getDrawable(context!!, R.drawable.ic_person_flat)) }) } @@ -193,20 +139,55 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + mainActivity.setBottomBarVisibility(View.GONE) + + toolbar = view.findViewById(R.id.toolbar) + + if (!PreferenceUtil.getInstance().isHomeBanner) + setStatusbarColorAuto(view) + + lastAdded = view.findViewById(R.id.lastAdded) + lastAdded.setOnClickListener { + NavigationUtil.goToPlaylistNew(activity!!, LastAddedPlaylist(activity!!)) + } + + topPlayed = view.findViewById(R.id.topPlayed) + topPlayed.setOnClickListener { + NavigationUtil.goToPlaylistNew(activity!!, MyTopTracksPlaylist(activity!!)) + } + + actionShuffle = view.findViewById(R.id.actionShuffle) + actionShuffle.setOnClickListener { + MusicPlayerRemote.openAndShuffleQueue(SongLoader.getAllSongs(activity!!).blockingFirst(), true) + } + + history = view.findViewById(R.id.history) + history.setOnClickListener { + NavigationUtil.goToPlaylistNew(activity!!, HistoryPlaylist(activity!!)) + } + + userImage = view.findViewById(R.id.userImage) + userImage.setOnClickListener { showMainMenu() } + + homePresenter = HomePresenter(this) + + contentContainerView = view.findViewById(R.id.contentContainer) + contentContainerView.setBackgroundColor(ThemeStore.primaryColor(context!!)) + + //bannerTitle.setTextColor(ThemeStore.textColorPrimary(context!!)) + setupToolbar() - loadImageFromStorage(userImage) homePresenter.subscribe() + + loadImageFromStorage(userImage) getTimeOfTheDay() } private fun setupToolbar() { - userImage.setOnClickListener { showMainMenu() } - contentContainer.setBackgroundColor(ThemeStore.primaryColor(mainActivity)) - } - - @OnClick(R.id.searchIcon) - internal fun search() { - NavigationUtil.goToSearch(mainActivity) + toolbar.navigationIcon = TintHelper.createTintedDrawable(ContextCompat.getDrawable(context!!, R.drawable.ic_menu_white_24dp), ThemeStore.textColorPrimary(context!!)) + mainActivity.title = null + mainActivity.setSupportActionBar(toolbar) + toolbar.setBackgroundColor(Color.TRANSPARENT) } override fun handleBackPress(): Boolean { @@ -237,41 +218,46 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba override fun recentArtist(artists: ArrayList) { recentArtistContainer.visibility = View.VISIBLE - recentArtistRV.layoutManager = GridLayoutManager(mainActivity, 1, GridLayoutManager.HORIZONTAL, false) - val artistAdapter = ArtistAdapter(mainActivity, artists, PreferenceUtil.getInstance().getHomeGridStyle(context!!), false, null) - recentArtistRV.adapter = artistAdapter + recentArtist.apply { + val artistAdapter = ArtistAdapter(mainActivity, artists, PreferenceUtil.getInstance().getHomeGridStyle(context!!), false, null) + layoutManager = GridLayoutManager(mainActivity, 1, GridLayoutManager.HORIZONTAL, false) + adapter = artistAdapter + } } override fun recentAlbum(albums: ArrayList) { recentAlbumsContainer.visibility = View.VISIBLE - val artistAdapter = AlbumFullWithAdapter(mainActivity, - displayMetrics) + val artistAdapter = AlbumFullWithAdapter(mainActivity, displayMetrics) artistAdapter.swapData(albums) - recentAlbumRV.adapter = artistAdapter + recentAlbum.adapter = artistAdapter } override fun topArtists(artists: ArrayList) { topArtistContainer.visibility = View.VISIBLE - topArtistRV.layoutManager = GridLayoutManager(mainActivity, 1, GridLayoutManager.HORIZONTAL, false) - val artistAdapter = ArtistAdapter(mainActivity, artists, PreferenceUtil.getInstance().getHomeGridStyle(context!!), false, null) - topArtistRV.adapter = artistAdapter + topArtist.apply { + layoutManager = GridLayoutManager(mainActivity, 1, GridLayoutManager.HORIZONTAL, false) + val artistAdapter = ArtistAdapter(mainActivity, artists, PreferenceUtil.getInstance().getHomeGridStyle(context!!), false, null) + adapter = artistAdapter + } } override fun topAlbums(albums: ArrayList) { - topAlbumContainer.visibility = View.VISIBLE + topAlbumsContainer.visibility = View.VISIBLE val artistAdapter = AlbumFullWithAdapter(mainActivity, displayMetrics) artistAdapter.swapData(albums) - topAlbumRV.adapter = artistAdapter + topAlbum.adapter = artistAdapter } override fun suggestions(songs: ArrayList) { if (!songs.isEmpty()) { - suggestionsContainer.visibility = View.VISIBLE + suggestionContainer.visibility = View.VISIBLE val artistAdapter = CollageSongAdapter(mainActivity, songs) - suggestionsSongs.layoutManager = if (RetroUtil.isTablet()) GridLayoutManager(mainActivity, 2) else LinearLayoutManager(mainActivity) - suggestionsSongs.adapter = artistAdapter + suggestionSongs.apply { + layoutManager = if (RetroUtil.isTablet()) GridLayoutManager(mainActivity, 2) else LinearLayoutManager(mainActivity) + adapter = artistAdapter + } } } @@ -281,10 +267,11 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba override fun geners(genres: ArrayList) { genreContainer.visibility = View.VISIBLE - genresRecyclerView.layoutManager = LinearLayoutManager(context) - - val genreAdapter = GenreAdapter(activity!!, genres, R.layout.item_list) - genresRecyclerView.adapter = genreAdapter + genresRecyclerView.apply { + val genreAdapter = GenreAdapter(activity!!, genres, R.layout.item_list) + layoutManager = LinearLayoutManager(context) + adapter = genreAdapter + } } 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 6739497f..008fa552 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 @@ -5,7 +5,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.viewpager.widget.ViewPager -import butterknife.Unbinder import code.name.monkey.retromusic.R import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.transform.ParallaxPagerTransformer 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 eaa45107..5735ebfd 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 @@ -4,6 +4,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.appcompat.widget.Toolbar import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper @@ -12,18 +13,22 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment +import kotlinx.android.synthetic.main.fragment_adaptive_player.* class AdaptiveFragment : AbsPlayerFragment(), PlayerAlbumCoverFragment.Callbacks { + override fun toolbarGet(): Toolbar { + return playerToolbar + } + private var lastColor: Int = 0 - lateinit var playbackControlsFragment: AdaptivePlaybackControlsFragment + private lateinit var playbackControlsFragment: AdaptivePlaybackControlsFragment override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_adaptive_player, container, false); + return inflater.inflate(R.layout.fragment_adaptive_player, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - toolbar = view.findViewById(R.id.toolbar) setUpSubFragments() setUpPlayerToolbar() } @@ -31,19 +36,21 @@ 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 - playerAlbumCoverFragment.setCallbacks(this) - playerAlbumCoverFragment.removeSlideEffect() + playerAlbumCoverFragment.apply { + removeSlideEffect() + }.setCallbacks(this) } private fun setUpPlayerToolbar() { - val primaryColor = ATHUtil.resolveColor(context, R.attr.iconColor) - /*toolbar!!.apply { + ATHUtil.resolveColor(context, R.attr.iconColor) + val primaryColor = ThemeStore.primaryColor(context!!) + playerToolbar.apply { inflateMenu(R.menu.menu_player) setNavigationOnClickListener { activity!!.onBackPressed() } ToolbarContentTintHelper.colorizeToolbar(this, primaryColor, activity) setTitleTextColor(primaryColor) setSubtitleTextColor(ThemeStore.textColorSecondary(context!!)) - }.setOnMenuItemClickListener(this)*/ + }.setOnMenuItemClickListener(this) } override fun onServiceConnected() { @@ -59,10 +66,10 @@ class AdaptiveFragment : AbsPlayerFragment(), PlayerAlbumCoverFragment.Callbacks private fun updateSong() { val song = MusicPlayerRemote.currentSong - /*toolbar!!.apply { + playerToolbar.apply { title = song.title subtitle = song.artistName - }*/ + } } override fun toggleFavorite(song: Song) { @@ -80,7 +87,7 @@ class AdaptiveFragment : AbsPlayerFragment(), PlayerAlbumCoverFragment.Callbacks playbackControlsFragment.setDark(color) lastColor = color callbacks!!.onPaletteColorChanged() - //ToolbarContentTintHelper.colorizeToolbar(toolbar, ATHUtil.resolveColor(context, R.attr.iconColor), activity) + ToolbarContentTintHelper.colorizeToolbar(playerToolbar, ATHUtil.resolveColor(context, R.attr.iconColor), activity) } override fun onShow() { diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptivePlaybackControlsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptivePlaybackControlsFragment.kt index 4ef44759..e607b269 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptivePlaybackControlsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/adaptive/AdaptivePlaybackControlsFragment.kt @@ -21,11 +21,10 @@ import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.PreferenceUtil -import code.name.monkey.retromusic.views.PlayPauseDrawable +import kotlinx.android.synthetic.main.fragment_adaptive_player_playback_controls.* class AdaptivePlaybackControlsFragment : AbsPlayerControlsFragment() { - private val playPauseDrawable: PlayPauseDrawable? = null private var lastPlaybackControlsColor: Int = 0 private var lastDisabledPlaybackControlsColor: Int = 0 private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null @@ -45,13 +44,13 @@ class AdaptivePlaybackControlsFragment : AbsPlayerControlsFragment() { setUpMusicControllers() hideVolumeIfAvailable() - playPauseFab!!.setOnClickListener { + playPauseButton.setOnClickListener { if (MusicPlayerRemote.isPlaying) { MusicPlayerRemote.pauseSong() } else { MusicPlayerRemote.resumePlaying() } - showBouceAnimation(playPauseFab!!) + showBouceAnimation(playPauseButton) } } @@ -97,9 +96,9 @@ class AdaptivePlaybackControlsFragment : AbsPlayerControlsFragment() { updatePrevNextColor() updatePlayPauseColor() - TintHelper.setTintAuto(playPauseFab!!, MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(color)), false) - TintHelper.setTintAuto(playPauseFab!!, color, true) - TintHelper.setTintAuto(progressSlider!!, color, false) + TintHelper.setTintAuto(playPauseButton, MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(color)), false) + TintHelper.setTintAuto(playPauseButton, color, true) + TintHelper.setTintAuto(progressSlider, color, false) } private fun updatePlayPauseColor() { @@ -107,18 +106,17 @@ class AdaptivePlaybackControlsFragment : AbsPlayerControlsFragment() { } private fun setUpPlayPauseFab() { - playPauseFab!!.setOnClickListener(PlayPauseButtonOnClickHandler()) + playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler()) } - protected fun updatePlayPauseDrawableState() { + private fun updatePlayPauseDrawableState() { if (MusicPlayerRemote.isPlaying) { - playPauseFab!!.setImageResource(R.drawable.ic_pause_white_24dp) + playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp) } else { - playPauseFab!!.setImageResource(R.drawable.ic_play_arrow_white_24dp) + playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp) } } - private fun setUpMusicControllers() { setUpPlayPauseFab() setUpPrevNext() @@ -129,47 +127,62 @@ class AdaptivePlaybackControlsFragment : AbsPlayerControlsFragment() { private fun setUpPrevNext() { updatePrevNextColor() - nextButton!!.setOnClickListener { MusicPlayerRemote.playNextSong() } - prevButton!!.setOnClickListener { MusicPlayerRemote.back() } + nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() } + previousButton.setOnClickListener { MusicPlayerRemote.back() } } private fun updatePrevNextColor() { - nextButton!!.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) - prevButton!!.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) } private fun setUpShuffleButton() { - shuffleButton!!.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() } + 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) + 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() } + 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) + 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) + 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) + repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp) + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) } } } + 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()) + } + + private fun hideVolumeIfAvailable() { + volumeFragmentContainer.visibility = if (PreferenceUtil.getInstance().volumeToggle) View.VISIBLE else View.GONE + } public override fun show() { //Ignore @@ -180,7 +193,7 @@ class AdaptivePlaybackControlsFragment : AbsPlayerControlsFragment() { } override fun setUpProgressSlider() { - progressSlider!!.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() { + progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() { override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { if (fromUser) { MusicPlayerRemote.seekTo(progress) @@ -191,19 +204,5 @@ class AdaptivePlaybackControlsFragment : AbsPlayerControlsFragment() { }) } - 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()) - } - - private fun hideVolumeIfAvailable() { - volumeContainer!!.visibility = if (PreferenceUtil.getInstance().volumeToggle) View.VISIBLE else View.GONE - } } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlaybackControlsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlaybackControlsFragment.kt index f643ad47..90312741 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlaybackControlsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlaybackControlsFragment.kt @@ -3,19 +3,23 @@ package code.name.monkey.retromusic.ui.fragments.player.blur import android.animation.ObjectAnimator import android.graphics.Color import android.graphics.PorterDuff +import android.graphics.drawable.ClipDrawable +import android.graphics.drawable.LayerDrawable import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.animation.AccelerateInterpolator import android.view.animation.DecelerateInterpolator import android.view.animation.LinearInterpolator import android.widget.SeekBar import android.widget.TextView import androidx.appcompat.widget.AppCompatTextView import androidx.core.content.ContextCompat -import butterknife.BindView -import butterknife.ButterKnife -import butterknife.Unbinder +import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.appthemehelper.util.ATHUtil +import code.name.monkey.appthemehelper.util.ColorUtil +import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.helper.MusicPlayerRemote @@ -27,13 +31,14 @@ import code.name.monkey.retromusic.ui.fragments.VolumeFragment import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.PreferenceUtil +import kotlinx.android.synthetic.main.fragment_player_playback_controls.* +import kotlinx.android.synthetic.main.media_button.* +import kotlinx.android.synthetic.main.player_time.* +import kotlinx.android.synthetic.main.volume_controls.* class BlurPlaybackControlsFragment : AbsPlayerControlsFragment() { - lateinit var songTitle: AppCompatTextView - lateinit var text: TextView - private var lastPlaybackControlsColor: Int = 0 private var lastDisabledPlaybackControlsColor: Int = 0 private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null @@ -43,27 +48,35 @@ class BlurPlaybackControlsFragment : AbsPlayerControlsFragment() { progressViewUpdateHelper = MusicProgressViewUpdateHelper(this) } - override fun onCreateView(inflater: LayoutInflater, - container: ViewGroup?, + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val view = inflater.inflate(R.layout.fragment_blur_playback_controls, container, false) - songTitle = view.findViewById(R.id.title) - text = view.findViewById(R.id.text) - return view + + return inflater.inflate(R.layout.fragment_player_playback_controls, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setUpMusicControllers() - volumeContainer!!.visibility = if (PreferenceUtil.getInstance().volumeToggle) View.VISIBLE else View.GONE - val mVolumeFragment = childFragmentManager.findFragmentById(R.id.volume_fragment) as VolumeFragment - mVolumeFragment.tintWhiteColor() + if (PreferenceUtil.getInstance().volumeToggle) { + volumeFragmentContainer.visibility = View.VISIBLE + } else { + volumeFragmentContainer.visibility = View.GONE + } + + playPauseButton.setOnClickListener { + if (MusicPlayerRemote.isPlaying) { + MusicPlayerRemote.pauseSong() + } else { + MusicPlayerRemote.resumePlaying() + } + showBonceAnimation() + } } private fun updateSong() { val song = MusicPlayerRemote.currentSong - songTitle.text = song.title + title.text = song.title text.text = song.artistName } @@ -102,41 +115,50 @@ class BlurPlaybackControlsFragment : AbsPlayerControlsFragment() { } override fun setDark(color: Int) { - lastPlaybackControlsColor = Color.WHITE - lastDisabledPlaybackControlsColor = ContextCompat.getColor(context!!, R.color.md_grey_500) + 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) + } - songTitle.setTextColor(lastPlaybackControlsColor) - text.setTextColor(lastDisabledPlaybackControlsColor) - - setProgressBarColor() - - songCurrentProgress!!.setTextColor(lastPlaybackControlsColor) - songTotalTime!!.setTextColor(lastPlaybackControlsColor) + if (PreferenceUtil.getInstance().adaptiveColor) { + setFabColor(color) + } else { + setFabColor(ThemeStore.accentColor(context!!)) + } updateRepeatState() updateShuffleState() updatePrevNextColor() } - private fun setProgressBarColor() { - TintHelper.setTintAuto(progressSlider!!, Color.WHITE, false) + private fun setFabColor(i: Int) { + TintHelper.setTintAuto(playPauseButton, MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(i)), false) + TintHelper.setTintAuto(playPauseButton, i, true) + setProgressBarColor(i) + } + + private fun setProgressBarColor(newColor: Int) { + val ld = progressSlider.progressDrawable as LayerDrawable + val clipDrawable = ld.findDrawableByLayerId(android.R.id.progress) as ClipDrawable + clipDrawable.setColorFilter(newColor, PorterDuff.Mode.SRC_IN) } private fun setUpPlayPauseFab() { - TintHelper.setTintAuto(playPauseFab!!, Color.WHITE, true) - TintHelper.setTintAuto(playPauseFab!!, Color.BLACK, false) - playPauseFab!!.setOnClickListener(PlayPauseButtonOnClickHandler()) + playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler()) } - protected fun updatePlayPauseDrawableState() { + private fun updatePlayPauseDrawableState() { if (MusicPlayerRemote.isPlaying) { - playPauseFab!!.setImageResource(R.drawable.ic_pause_white_24dp) + playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp) } else { - playPauseFab!!.setImageResource(R.drawable.ic_play_arrow_white_24dp) + playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp) } } - private fun setUpMusicControllers() { setUpPlayPauseFab() setUpPrevNext() @@ -147,50 +169,49 @@ class BlurPlaybackControlsFragment : AbsPlayerControlsFragment() { private fun setUpPrevNext() { updatePrevNextColor() - nextButton!!.setOnClickListener { MusicPlayerRemote.playNextSong() } - prevButton!!.setOnClickListener { MusicPlayerRemote.back() } + nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() } + previousButton.setOnClickListener { MusicPlayerRemote.back() } } private fun updatePrevNextColor() { - nextButton!!.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) - prevButton!!.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) + previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) } private fun setUpShuffleButton() { - shuffleButton!!.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() } + shuffleButton.setOnClickListener { v -> 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) + 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() } + 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) + 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) + 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) + repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp) + repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN) } } } - - override fun show() { - playPauseFab!!.animate() + public override fun show() { + playPauseButton!!.animate() .scaleX(1f) .scaleY(1f) .rotation(360f) @@ -198,34 +219,61 @@ class BlurPlaybackControlsFragment : AbsPlayerControlsFragment() { .start() } - override fun hide() { - if (playPauseFab != null) { - playPauseFab!!.scaleX = 0f - playPauseFab!!.scaleY = 0f - playPauseFab!!.rotation = 0f + public override fun hide() { + if (playPauseButton != null) { + playPauseButton!!.apply { + scaleX = 0f + scaleY = 0f + rotation = 0f + } } } override fun setUpProgressSlider() { - progressSlider!!.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() { + progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() { override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { if (fromUser) { MusicPlayerRemote.seekTo(progress) - onUpdateProgressViews(MusicPlayerRemote.songProgressMillis, MusicPlayerRemote.songDurationMillis) + onUpdateProgressViews(MusicPlayerRemote.songProgressMillis, + MusicPlayerRemote.songDurationMillis) } } }) } + private fun showBonceAnimation() { + playPauseButton.apply { + clearAnimation() + scaleX = 0.9f + scaleY = 0.9f + visibility = View.VISIBLE + pivotX = (width / 2).toFloat() + pivotY = (height / 2).toFloat() + + animate().setDuration(200) + .setInterpolator(DecelerateInterpolator()) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction { + animate().setDuration(200) + .setInterpolator(AccelerateInterpolator()) + .scaleX(1f) + .scaleY(1f) + .alpha(1f).start() + }.start() + } + } + + override fun onUpdateProgressViews(progress: Int, total: Int) { - progressSlider!!.max = total + 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()) + songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong()) + songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong()) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlayerFragment.kt index a29a82c3..52ce65b3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/blur/BlurPlayerFragment.kt @@ -6,10 +6,7 @@ import android.preference.PreferenceManager import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.ImageView -import androidx.appcompat.app.AppCompatActivity -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView +import androidx.appcompat.widget.Toolbar import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.glide.BlurTransformation @@ -17,20 +14,19 @@ 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.adapter.song.PlayingQueueAdapter import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment import com.bumptech.glide.Glide -import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator +import kotlinx.android.synthetic.main.fragment_blur.* class BlurPlayerFragment : AbsPlayerFragment() { - lateinit var playbackControlsFragment: BlurPlaybackControlsFragment + override fun toolbarGet(): Toolbar { + return playerToolbar + } + + private lateinit var playbackControlsFragment: BlurPlaybackControlsFragment - private var colorBackground: ImageView? = null private var lastColor: Int = 0 - private var playingQueueAdapter: PlayingQueueAdapter? = null - private var layoutManager: LinearLayoutManager? = null - private var recyclerView: RecyclerView? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, @@ -51,7 +47,7 @@ class BlurPlayerFragment : AbsPlayerFragment() { } private fun setUpPlayerToolbar() { - toolbar!!.apply { + playerToolbar!!.apply { inflateMenu(R.menu.menu_player) setNavigationOnClickListener { activity!!.onBackPressed() } ToolbarContentTintHelper.colorizeToolbar(this, Color.WHITE, activity) @@ -66,7 +62,7 @@ class BlurPlayerFragment : AbsPlayerFragment() { playbackControlsFragment.setDark(color) lastColor = color callbacks!!.onPaletteColorChanged() - ToolbarContentTintHelper.colorizeToolbar(toolbar!!, Color.WHITE, activity) + ToolbarContentTintHelper.colorizeToolbar(playerToolbar!!, Color.WHITE, activity) } override fun toggleFavorite(song: Song) { @@ -95,15 +91,6 @@ class BlurPlayerFragment : AbsPlayerFragment() { override val paletteColor: Int get() = lastColor - override fun onDestroyView() { - recyclerView!!.apply { - itemAnimator = null - adapter = null - } - playingQueueAdapter = null - layoutManager = null - super.onDestroyView() - } private fun updateBlur() { val activity = activity ?: return @@ -130,69 +117,11 @@ class BlurPlayerFragment : AbsPlayerFragment() { override fun onServiceConnected() { updateIsFavorite() updateBlur() - setUpRecyclerView() } override fun onPlayingMetaChanged() { updateIsFavorite() updateBlur() - updateQueuePosition() - } - - private fun setUpRecyclerView() { - if (recyclerView != null) { - val animator = RefactoredDefaultItemAnimator() - - playingQueueAdapter = PlayingQueueAdapter((activity as AppCompatActivity), - MusicPlayerRemote.playingQueue, - MusicPlayerRemote.position, - R.layout.item_song, - Color.WHITE) - layoutManager = LinearLayoutManager(context) - - recyclerView!!.apply { - layoutManager = layoutManager - adapter = playingQueueAdapter - itemAnimator = animator - } - layoutManager!!.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0) - } - } - - override fun onQueueChanged() { - updateQueue() - updateCurrentSong() - } - - override fun onMediaStoreChanged() { - updateQueue() - updateCurrentSong() - } - - private fun updateCurrentSong() {} - - private fun updateQueuePosition() { - - playingQueueAdapter!!.apply { - setCurrent(MusicPlayerRemote.position) - resetToCurrentPosition() - } - - } - - private fun updateQueue() { - playingQueueAdapter!!.apply { - swapDataSet(MusicPlayerRemote.playingQueue, MusicPlayerRemote.position) - resetToCurrentPosition() - } - - } - - private fun resetToCurrentPosition() { - recyclerView!!.apply { - stopScroll() - } - layoutManager!!.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/cardblur/CardBlurFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/cardblur/CardBlurFragment.kt new file mode 100644 index 00000000..b5347a69 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/cardblur/CardBlurFragment.kt @@ -0,0 +1,151 @@ +package code.name.monkey.retromusic.ui.fragments.player.cardblur + +import android.graphics.Color +import android.os.Bundle +import android.preference.PreferenceManager +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.widget.Toolbar +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.glide.BlurTransformation +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.fragments.base.AbsPlayerFragment +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment +import code.name.monkey.retromusic.ui.fragments.player.normal.PlayerFragment +import com.bumptech.glide.Glide +import kotlinx.android.synthetic.main.fragment_card_blur_player.* + +class CardBlurFragment : AbsPlayerFragment(), PlayerAlbumCoverFragment.Callbacks { + override fun toolbarGet(): Toolbar { + return playerToolbar + } + + private var lastColor: Int = 0 + override val paletteColor: Int + get() = lastColor + private lateinit var playbackControlsFragment: CardBlurPlaybackControlsFragment + + + override fun onShow() { + playbackControlsFragment.show() + } + + override fun onHide() { + playbackControlsFragment.hide() + onBackPressed() + } + + override fun onBackPressed(): Boolean { + return false + } + + override fun toolbarIconColor(): Int { + return Color.WHITE + } + + override fun onColorChanged(color: Int) { + playbackControlsFragment.setDark(color) + lastColor = color + callbacks!!.onPaletteColorChanged() + ToolbarContentTintHelper.colorizeToolbar(playerToolbar, Color.WHITE, activity) + + playerToolbar.setTitleTextColor(Color.WHITE) + playerToolbar.setSubtitleTextColor(Color.WHITE) + } + + override fun toggleFavorite(song: Song) { + super.toggleFavorite(song) + if (song.id == MusicPlayerRemote.currentSong.id) { + updateIsFavorite() + } + } + + override fun onFavoriteToggled() { + toggleFavorite(MusicPlayerRemote.currentSong) + } + + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + + return inflater.inflate(R.layout.fragment_card_blur_player, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setUpSubFragments() + setUpPlayerToolbar() + } + + private fun setUpSubFragments() { + playbackControlsFragment = childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as CardBlurPlaybackControlsFragment + val playerAlbumCoverFragment = childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment? + if (playerAlbumCoverFragment != null) { + playerAlbumCoverFragment.setCallbacks(this) + playerAlbumCoverFragment.removeEffect() + } + + } + + private fun setUpPlayerToolbar() { + playerToolbar.apply { + inflateMenu(R.menu.menu_player) + setNavigationOnClickListener { activity!!.onBackPressed() } + setTitleTextColor(Color.WHITE) + setSubtitleTextColor(Color.WHITE) + ToolbarContentTintHelper.colorizeToolbar(playerToolbar, Color.WHITE, activity) + }.setOnMenuItemClickListener(this) + } + + override fun onServiceConnected() { + updateIsFavorite() + updateBlur() + updateSong() + } + + override fun onPlayingMetaChanged() { + updateIsFavorite() + updateBlur() + updateSong() + } + + private fun updateSong() { + val song = MusicPlayerRemote.currentSong + playerToolbar.apply { + title = song.title + subtitle = song.artistName + } + } + + private fun updateBlur() { + val activity = activity ?: return + val blurAmount = PreferenceManager.getDefaultSharedPreferences(context) + .getInt("new_blur_amount", 25) + + colorBackground!!.clearColorFilter() + SongGlideRequest.Builder.from(Glide.with(activity), MusicPlayerRemote.currentSong) + .checkIgnoreMediaStore(activity) + .generatePalette(activity) + .build() + .transform(BlurTransformation.Builder(getActivity()!!).blurRadius(blurAmount.toFloat()).build()) + .into(object : RetroMusicColoredTarget(colorBackground!!) { + override fun onColorReady(color: Int) { + if (color == defaultFooterColor) { + colorBackground!!.setColorFilter(color) + } + } + }) + } + + companion object { + + fun newInstance(): PlayerFragment { + return PlayerFragment() + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/cardblur/CardBlurPlaybackControlsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/cardblur/CardBlurPlaybackControlsFragment.kt new file mode 100644 index 00000000..f5602749 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/cardblur/CardBlurPlaybackControlsFragment.kt @@ -0,0 +1,222 @@ +package code.name.monkey.retromusic.ui.fragments.player.cardblur + +import android.animation.ObjectAnimator +import android.graphics.Color +import android.graphics.PorterDuff +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.animation.AccelerateInterpolator +import android.view.animation.DecelerateInterpolator +import android.view.animation.LinearInterpolator +import android.widget.SeekBar +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.VolumeFragment +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerControlsFragment +import code.name.monkey.retromusic.util.MusicUtil +import code.name.monkey.retromusic.util.PreferenceUtil +import kotlinx.android.synthetic.main.fragment_card_blur_player_playback_controls.* +import kotlinx.android.synthetic.main.media_button.* +import kotlinx.android.synthetic.main.player_time.* +import kotlinx.android.synthetic.main.volume_controls.* + +class CardBlurPlaybackControlsFragment : AbsPlayerControlsFragment() { + + private var lastPlaybackControlsColor: Int = 0 + private var lastDisabledPlaybackControlsColor: Int = 0 + private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + progressViewUpdateHelper = MusicProgressViewUpdateHelper(this) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + + return inflater.inflate(R.layout.fragment_card_blur_player_playback_controls, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setUpMusicControllers() + setupVolumeControls() + hideVolumeIfAvailable() + } + + private fun hideVolumeIfAvailable() { + volumeFragmentContainer.visibility = if (PreferenceUtil.getInstance().volumeToggle) View.VISIBLE else View.GONE + } + + override fun setDark(color: Int) { + lastPlaybackControlsColor = Color.WHITE + lastDisabledPlaybackControlsColor = ColorUtil.withAlpha(Color.WHITE, 0.3f) + + updateRepeatState() + updateShuffleState() + updatePrevNextColor() + updateProgressTextColor() + } + + + private fun setUpPlayPauseFab() { + playPauseButton.apply { + TintHelper.setTintAuto(this, Color.WHITE, true) + TintHelper.setTintAuto(this, Color.BLACK, false) + setOnClickListener(PlayPauseButtonOnClickHandler()) + } + + } + + private fun updatePlayPauseDrawableState() { + when { + MusicPlayerRemote.isPlaying -> playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp) + else -> playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp) + } + } + + private fun setupVolumeControls() { + val volumeFragment = childFragmentManager.findFragmentById(R.id.volumeFragment) as VolumeFragment + volumeFragment.tintWhiteColor() + } + + private fun updateProgressTextColor() { + val color = MaterialValueHelper.getPrimaryTextColor(context, false) + songTotalTime.setTextColor(color) + songCurrentProgress.setTextColor(color) + } + + + override fun onResume() { + super.onResume() + progressViewUpdateHelper!!.start() + } + + override fun onPause() { + super.onPause() + progressViewUpdateHelper!!.stop() + } + + override fun onServiceConnected() { + updatePlayPauseDrawableState() + updateRepeatState() + updateShuffleState() + } + + override fun onPlayStateChanged() { + updatePlayPauseDrawableState() + } + + override fun onRepeatModeChanged() { + updateRepeatState() + } + + override fun onShuffleModeChanged() { + updateShuffleState() + } + + private fun setUpMusicControllers() { + setUpPlayPauseFab() + setUpPrevNext() + setUpRepeatButton() + setUpShuffleButton() + setUpProgressSlider() + } + + 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()) + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/fit/FitFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/fit/FitFragment.kt new file mode 100644 index 00000000..06543780 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/fit/FitFragment.kt @@ -0,0 +1,110 @@ +package code.name.monkey.retromusic.ui.fragments.player.fit + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.widget.Toolbar +import code.name.monkey.appthemehelper.util.ATHUtil +import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.helper.MusicPlayerRemote +import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment +import kotlinx.android.synthetic.main.fragment_fit.* + + +class FitFragment : AbsPlayerFragment(), PlayerAlbumCoverFragment.Callbacks { + override fun toolbarGet(): Toolbar { + return playerToolbar + } + + private var lastColor: Int = 0 + override val paletteColor: Int + get() = lastColor + + private lateinit var playbackControlsFragment: FitPlaybackControlsFragment + + override fun onShow() { + playbackControlsFragment.show() + } + + override fun onHide() { + playbackControlsFragment.hide() + onBackPressed() + } + + override fun onBackPressed(): Boolean { + return false + } + + override fun toolbarIconColor(): Int { + return ATHUtil.resolveColor(context, R.attr.iconColor) + } + + override fun onColorChanged(color: Int) { + playbackControlsFragment.setDark(color) + lastColor = color + callbacks!!.onPaletteColorChanged() + + ToolbarContentTintHelper.colorizeToolbar(playerToolbar, ATHUtil.resolveColor(context, R.attr.iconColor), activity) + + } + + override fun toggleFavorite(song: Song) { + super.toggleFavorite(song) + if (song.id == MusicPlayerRemote.currentSong.id) { + updateIsFavorite() + } + } + + override fun onFavoriteToggled() { + toggleFavorite(MusicPlayerRemote.currentSong) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + + return inflater.inflate(R.layout.fragment_fit, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setUpSubFragments() + setUpPlayerToolbar() + } + + private fun setUpSubFragments() { + playbackControlsFragment = childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as FitPlaybackControlsFragment + + val playerAlbumCoverFragment = childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment + playerAlbumCoverFragment.setCallbacks(this) + playerAlbumCoverFragment.removeEffect() + } + + private fun setUpPlayerToolbar() { + playerToolbar!!.apply { + inflateMenu(R.menu.menu_player) + setNavigationOnClickListener { activity!!.onBackPressed() } + setOnMenuItemClickListener(this@FitFragment) + ToolbarContentTintHelper.colorizeToolbar(this, ATHUtil.resolveColor(context, R.attr.iconColor), activity) + } + } + + override fun onServiceConnected() { + updateIsFavorite() + + } + + override fun onPlayingMetaChanged() { + updateIsFavorite() + } + + companion object { + + fun newInstance(): FitFragment { + return FitFragment() + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/fit/FitPlaybackControlsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/fit/FitPlaybackControlsFragment.kt new file mode 100644 index 00000000..5c508a72 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/fit/FitPlaybackControlsFragment.kt @@ -0,0 +1,271 @@ +package code.name.monkey.retromusic.ui.fragments.player.fit + +import android.animation.ObjectAnimator +import android.graphics.PorterDuff +import android.graphics.drawable.ClipDrawable +import android.graphics.drawable.LayerDrawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.animation.AccelerateInterpolator +import android.view.animation.DecelerateInterpolator +import android.view.animation.LinearInterpolator +import android.widget.SeekBar +import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.appthemehelper.util.ATHUtil +import code.name.monkey.appthemehelper.util.ColorUtil +import code.name.monkey.appthemehelper.util.MaterialValueHelper +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 code.name.monkey.retromusic.util.PreferenceUtil +import kotlinx.android.synthetic.main.fragment_player_playback_controls.* +import kotlinx.android.synthetic.main.media_button.* +import kotlinx.android.synthetic.main.player_time.* +import kotlinx.android.synthetic.main.volume_controls.* + +class FitPlaybackControlsFragment : AbsPlayerControlsFragment() { + + + private var lastPlaybackControlsColor: Int = 0 + private var lastDisabledPlaybackControlsColor: Int = 0 + private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + progressViewUpdateHelper = MusicProgressViewUpdateHelper(this) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + + return inflater.inflate(R.layout.fragment_fit_playback_controls, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setUpMusicControllers() + playPauseButton.setOnClickListener { + if (MusicPlayerRemote.isPlaying) { + MusicPlayerRemote.pauseSong() + } else { + MusicPlayerRemote.resumePlaying() + } + showBonceAnimation() + } + } + + private fun updateSong() { + val song = MusicPlayerRemote.currentSong + title.text = song.title + text.text = song.artistName + } + + 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) { + 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) + } + + if (PreferenceUtil.getInstance().adaptiveColor) { + setFabColor(color) + } else { + setFabColor(ThemeStore.accentColor(context!!)) + } + + updateRepeatState() + updateShuffleState() + updatePrevNextColor() + } + + private fun setFabColor(i: Int) { + TintHelper.setTintAuto(playPauseButton, MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(i)), false) + TintHelper.setTintAuto(playPauseButton, i, true) + + } + + 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 setProgressBarColor(newColor: Int) { + val ld = progressSlider!!.progressDrawable as LayerDrawable + val clipDrawable = ld.findDrawableByLayerId(android.R.id.progress) as ClipDrawable + clipDrawable.setColorFilter(newColor, PorterDuff.Mode.SRC_IN) + } + + + private fun setUpMusicControllers() { + setUpPlayPauseFab() + setUpPrevNext() + setUpRepeatButton() + setUpShuffleButton() + setUpProgressSlider() + } + + 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 { v -> 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) + } + } + }) + } + + private fun showBonceAnimation() { + playPauseButton.apply { + clearAnimation() + scaleX = 0.9f + scaleY = 0.9f + visibility = View.VISIBLE + pivotX = (width / 2).toFloat() + pivotY = (height / 2).toFloat() + + animate().setDuration(200) + .setInterpolator(DecelerateInterpolator()) + .scaleX(1.1f) + .scaleY(1.1f) + .withEndAction { + animate().setDuration(200) + .setInterpolator(AccelerateInterpolator()) + .scaleX(1f) + .scaleY(1f) + .alpha(1f).start() + }.start() + } + } + + 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()) + } + + private fun hideVolumeIfAvailable() { + volumeFragmentContainer.visibility = if (PreferenceUtil.getInstance().volumeToggle) View.VISIBLE else View.GONE + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/flat/FlatPlaybackControlsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/flat/FlatPlaybackControlsFragment.kt new file mode 100644 index 00000000..bab7b04f --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/flat/FlatPlaybackControlsFragment.kt @@ -0,0 +1,230 @@ +package code.name.monkey.retromusic.ui.fragments.player.flat + +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.ThemeStore +import code.name.monkey.appthemehelper.util.ATHUtil +import code.name.monkey.appthemehelper.util.ColorUtil +import code.name.monkey.appthemehelper.util.MaterialValueHelper +import code.name.monkey.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.MusicProgressViewUpdateHelper.Callback +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 code.name.monkey.retromusic.util.PreferenceUtil +import kotlinx.android.synthetic.main.fragment_flat_player_playback_controls.* +import kotlinx.android.synthetic.main.player_time.* +import kotlinx.android.synthetic.main.volume_controls.* + +class FlatPlaybackControlsFragment : AbsPlayerControlsFragment(), Callback { + + private var lastPlaybackControlsColor: Int = 0 + private var lastDisabledPlaybackControlsColor: Int = 0 + private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + progressViewUpdateHelper = MusicProgressViewUpdateHelper(this) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_flat_player_playback_controls, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setUpMusicControllers() + hideVolumeIfAvailable() + } + + override fun onResume() { + super.onResume() + progressViewUpdateHelper!!.start() + } + + override fun onPause() { + super.onPause() + progressViewUpdateHelper!!.stop() + } + + 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()) + } + + private fun hideVolumeIfAvailable() { + volumeFragmentContainer.visibility = if (PreferenceUtil.getInstance().volumeToggle) View.VISIBLE else View.GONE + } + + public override fun show() { + playPauseButton!!.animate() + .scaleX(1f) + .scaleY(1f) + .setInterpolator(DecelerateInterpolator()) + .start() + } + + + public override fun hide() { + playPauseButton!!.apply { + scaleX = 0f + scaleY = 0f + rotation = 0f + } + } + + override fun setDark(color: Int) { + val colorBg = ATHUtil.resolveColor(activity, android.R.attr.colorBackground) + val isDark = ColorUtil.isColorLight(colorBg) + if (isDark) { + lastPlaybackControlsColor = MaterialValueHelper.getSecondaryTextColor(activity, true) + lastDisabledPlaybackControlsColor = MaterialValueHelper.getSecondaryDisabledTextColor(activity, true) + } else { + lastPlaybackControlsColor = MaterialValueHelper.getPrimaryTextColor(activity, false) + lastDisabledPlaybackControlsColor = MaterialValueHelper.getPrimaryDisabledTextColor(activity, false) + } + val accentColor = ThemeStore.accentColor(context!!) + val b = PreferenceUtil.getInstance().adaptiveColor + updateTextColors(if (b) color else accentColor) + setProgressBarColor(if (b) color else accentColor) + + + updateRepeatState() + updateShuffleState() + } + + private fun setProgressBarColor(dark: Int) { + TintHelper.setTintAuto(progressSlider!!, dark, false) + } + + private fun updateTextColors(color: Int) { + val isDark = ColorUtil.isColorLight(color) + val darkColor = ColorUtil.darkenColor(color) + val colorPrimary = MaterialValueHelper.getPrimaryTextColor(context, isDark) + val colorSecondary = MaterialValueHelper.getSecondaryTextColor(context, ColorUtil.isColorLight(darkColor)) + + TintHelper.setTintAuto(playPauseButton!!, colorPrimary, false) + TintHelper.setTintAuto(playPauseButton!!, color, true) + + title.setBackgroundColor(color) + title.setTextColor(colorPrimary) + text.setBackgroundColor(darkColor) + text.setTextColor(colorSecondary) + } + + override fun onServiceConnected() { + updatePlayPauseDrawableState() + updateRepeatState() + updateShuffleState() + updateSong() + } + + override fun onPlayingMetaChanged() { + super.onPlayingMetaChanged() + updateSong() + } + + override fun onPlayStateChanged() { + updatePlayPauseDrawableState() + } + + 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() + setUpRepeatButton() + setUpShuffleButton() + setUpProgressSlider() + } + + private fun updateSong() { + //TransitionManager.beginDelayedTransition(viewGroup, new ChangeText().setChangeBehavior(ChangeText.CHANGE_BEHAVIOR_OUT_IN)); + val song = MusicPlayerRemote.currentSong + title.text = song.title + text.text = song.artistName + + } + + 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 onRepeatModeChanged() { + updateRepeatState() + } + + override fun onShuffleModeChanged() { + updateShuffleState() + } + + private fun setUpRepeatButton() { + repeatButton.setOnClickListener { v -> 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) + } + } + } + + 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) + } + } + +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/flat/FlatPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/flat/FlatPlayerFragment.kt new file mode 100644 index 00000000..4ace7ed4 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/player/flat/FlatPlayerFragment.kt @@ -0,0 +1,128 @@ +package code.name.monkey.retromusic.ui.fragments.player.flat + +import android.animation.ArgbEvaluator +import android.animation.ValueAnimator +import android.graphics.drawable.GradientDrawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.widget.Toolbar +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.ToolbarContentTintHelper +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.helper.MusicPlayerRemote +import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.ui.fragments.base.AbsPlayerFragment +import code.name.monkey.retromusic.ui.fragments.player.PlayerAlbumCoverFragment +import code.name.monkey.retromusic.util.PreferenceUtil +import code.name.monkey.retromusic.util.ViewUtil +import code.name.monkey.retromusic.views.DrawableGradient +import kotlinx.android.synthetic.main.fragment_flat_player.* + +class FlatPlayerFragment : AbsPlayerFragment(), PlayerAlbumCoverFragment.Callbacks { + override fun toolbarGet(): Toolbar { + return playerToolbar + } + + private var valueAnimator: ValueAnimator? = null + private lateinit var flatPlaybackControlsFragment: FlatPlaybackControlsFragment + private var lastColor: Int = 0 + override val paletteColor: Int + get() = lastColor + + private fun setUpSubFragments() { + flatPlaybackControlsFragment = childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as FlatPlaybackControlsFragment + val playerAlbumCoverFragment = childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment + playerAlbumCoverFragment.setCallbacks(this) + } + + private fun setUpPlayerToolbar() { + playerToolbar.inflateMenu(R.menu.menu_player) + playerToolbar.setNavigationOnClickListener { _ -> activity!!.onBackPressed() } + playerToolbar.setOnMenuItemClickListener(this) + ToolbarContentTintHelper.colorizeToolbar(playerToolbar, ATHUtil.resolveColor(context, + R.attr.iconColor), activity) + } + + private fun colorize(i: Int) { + if (valueAnimator != null) { + valueAnimator!!.cancel() + } + + valueAnimator = ValueAnimator.ofObject(ArgbEvaluator(), android.R.color.transparent, i) + valueAnimator!!.addUpdateListener { animation -> + val drawable = DrawableGradient(GradientDrawable.Orientation.TOP_BOTTOM, + intArrayOf(animation.animatedValue as Int, android.R.color.transparent), 0) + colorGradientBackground.background = drawable + + } + valueAnimator!!.setDuration(ViewUtil.RETRO_MUSIC_ANIM_TIME.toLong()).start() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_flat_player, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setUpPlayerToolbar() + setUpSubFragments() + + } + + override fun onShow() { + flatPlaybackControlsFragment.show() + } + + override fun onHide() { + flatPlaybackControlsFragment.hide() + onBackPressed() + } + + override fun onBackPressed(): Boolean { + return false + } + + override fun toolbarIconColor(): Int { + val isLight = ColorUtil.isColorLight(paletteColor) + return if (PreferenceUtil.getInstance().adaptiveColor) + MaterialValueHelper.getPrimaryTextColor(context, isLight) + else + ATHUtil.resolveColor(context, R.attr.iconColor) + } + + override fun onColorChanged(color: Int) { + lastColor = color + flatPlaybackControlsFragment.setDark(color) + callbacks!!.onPaletteColorChanged() + + val isLight = ColorUtil.isColorLight(color) + + //TransitionManager.beginDelayedTransition(mToolbar); + val iconColor = if (PreferenceUtil.getInstance().adaptiveColor) + MaterialValueHelper.getPrimaryTextColor(context, isLight) + else + ATHUtil.resolveColor(context, R.attr.iconColor) + ToolbarContentTintHelper.colorizeToolbar(playerToolbar, iconColor, activity) + if (PreferenceUtil.getInstance().adaptiveColor) { + colorize(color) + } + } + + + override fun onFavoriteToggled() { + toggleFavorite(MusicPlayerRemote.currentSong) + } + + + override fun toggleFavorite(song: Song) { + super.toggleFavorite(song) + if (song.id == MusicPlayerRemote.currentSong.id) { + updateIsFavorite() + } + } +} diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/MainSettingsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/MainSettingsFragment.java deleted file mode 100644 index 20b352a4..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/MainSettingsFragment.java +++ /dev/null @@ -1,162 +0,0 @@ -package code.name.monkey.retromusic.ui.fragments.settings; - -import android.graphics.Bitmap; -import android.graphics.PorterDuff; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import java.io.File; -import java.util.Calendar; -import java.util.List; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; -import androidx.appcompat.widget.AppCompatTextView; -import androidx.core.content.ContextCompat; -import androidx.fragment.app.Fragment; -import butterknife.BindView; -import butterknife.BindViews; -import butterknife.ButterKnife; -import butterknife.OnClick; -import butterknife.Unbinder; -import code.name.monkey.appthemehelper.ThemeStore; -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 code.name.monkey.retromusic.views.CircularImageView; -import code.name.monkey.retromusic.views.IconImageView; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; - -import static code.name.monkey.retromusic.Constants.USER_PROFILE; - -public class MainSettingsFragment extends Fragment { - - @BindViews({R.id.general_settings_icon, R.id.audio_settings_icon, - R.id.now_playing_settings_icon, R.id.personalize_settings_icon, - R.id.image_settings_icon, R.id.notification_settings_icon, R.id.other_settings_icon}) - List icons; - - @BindView(R.id.container) - ViewGroup container; - @BindView(R.id.user_image_bottom) - CircularImageView userImageBottom; - @BindView(R.id.title_welcome) - AppCompatTextView titleWelcome; - @BindView(R.id.text) - AppCompatTextView text; - private Unbinder unbinder; - private ButterKnife.Action apply = (view, index) -> { - //noinspection ConstantConditions - ((IconImageView) view).setColorFilter(ThemeStore.accentColor(getContext()), PorterDuff.Mode.SRC_IN); - }; - private CompositeDisposable disposable = new CompositeDisposable(); - - @Nullable - @Override - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.fragment_main_settings, container, false); - unbinder = ButterKnife.bind(this, layout); - ButterKnife.apply(icons, apply); - return layout; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - text.setTextColor(ThemeStore.textColorSecondary(getContext())); - titleWelcome.setTextColor(ThemeStore.textColorPrimary(getContext())); - titleWelcome.setText(String.format("%s %s!", getTimeOfTheDay(), PreferenceUtil.getInstance().getUserName())); - loadImageFromStorage(); - } - - - @Override - public void onDestroyView() { - super.onDestroyView(); - disposable.clear(); - unbinder.unbind(); - } - - @OnClick({R.id.general_settings, R.id.audio_settings, R.id.now_playing_settings, - R.id.user_info_container, R.id.image_settings, R.id.personalize_settings, R.id.notification_settings, R.id.other_settings}) - public void onViewClicked(View view) { - switch (view.getId()) { - case R.id.general_settings: - inflateFragment(new ThemeSettingsFragment(), R.string.general_settings_title); - break; - case R.id.audio_settings: - inflateFragment(new AudioSettings(), R.string.pref_header_audio); - break; - case R.id.user_info_container: - NavigationUtil.goToUserInfo(getActivity()); - break; - case R.id.now_playing_settings: - inflateFragment(new NowPlayingSettingsFragment(), R.string.now_playing); - break; - case R.id.personalize_settings: - inflateFragment(new PersonaizeSettingsFragment(), R.string.personalize); - break; - case R.id.image_settings: - inflateFragment(new ImageSettingFragment(), R.string.pref_header_images); - break; - case R.id.notification_settings: - inflateFragment(new NotificationSettingsFragment(), R.string.notification); - break; - case R.id.other_settings: - inflateFragment(new OtherSettingsFragment(), R.string.others); - break; - } - } - - private void inflateFragment(Fragment fragment, @StringRes int title) { - if (getActivity() != null) { - ((SettingsActivity) getActivity()).setupFragment(fragment, title); - } - } - - private String getTimeOfTheDay() { - String message = getString(R.string.title_good_day); - Calendar c = Calendar.getInstance(); - int timeOfDay = c.get(Calendar.HOUR_OF_DAY); - - if (timeOfDay >= 0 && timeOfDay < 6) { - message = getString(R.string.title_good_night); - } else if (timeOfDay >= 6 && timeOfDay < 12) { - message = getString(R.string.title_good_morning); - } else if (timeOfDay >= 12 && timeOfDay < 16) { - message = getString(R.string.title_good_afternoon); - } else if (timeOfDay >= 16 && timeOfDay < 20) { - message = getString(R.string.title_good_evening); - } else if (timeOfDay >= 20 && timeOfDay < 24) { - message = getString(R.string.title_good_night); - } - return message; - } - - - private void loadImageFromStorage() { - //noinspection ConstantConditions - disposable.add(new Compressor(getContext()) - .setMaxHeight(300) - .setMaxWidth(300) - .setQuality(75) - .setCompressFormat(Bitmap.CompressFormat.WEBP) - .compressToBitmapAsFlowable( - new File(PreferenceUtil.getInstance().getProfileImage(),USER_PROFILE)) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(userImageBottom::setImageBitmap, - throwable -> userImageBottom.setImageDrawable(ContextCompat - .getDrawable(getContext(), 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/MainSettingsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/MainSettingsFragment.kt new file mode 100644 index 00000000..8bafb141 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/MainSettingsFragment.kt @@ -0,0 +1,54 @@ +package code.name.monkey.retromusic.ui.fragments.settings + +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.fragment.app.Fragment +import code.name.monkey.appthemehelper.ThemeStore +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.ui.activities.SettingsActivity +import kotlinx.android.synthetic.main.fragment_main_settings.* + +class MainSettingsFragment : Fragment(), View.OnClickListener { + override fun onClick(v: View) { + when (v.id) { + R.id.generalSettings -> inflateFragment(ThemeSettingsFragment(), R.string.general_settings_title) + R.id.audioSettings -> inflateFragment(AudioSettings(), R.string.pref_header_audio) + R.id.nowPlayingSettings -> inflateFragment(NowPlayingSettingsFragment(), R.string.now_playing) + R.id.personalizeSettings -> inflateFragment(PersonaizeSettingsFragment(), R.string.personalize) + R.id.imageSettings -> inflateFragment(ImageSettingFragment(), R.string.pref_header_images) + R.id.notificationSettings -> inflateFragment(NotificationSettingsFragment(), R.string.notification) + R.id.otherSettings -> inflateFragment(OtherSettingsFragment(), R.string.others) + } + } + + private val settingsIcons = arrayOf(R.id.general_settings_icon, R.id.audio_settings_icon, R.id.now_playing_settings_icon, R.id.personalize_settings_icon, R.id.image_settings_icon, R.id.notification_settings_icon, R.id.other_settings_icon) + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_main_settings, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + settingsIcons.forEach { + view.findViewById(it).setColorFilter(ThemeStore.accentColor(context!!)) + } + generalSettings.setOnClickListener(this) + audioSettings.setOnClickListener(this) + nowPlayingSettings.setOnClickListener(this) + personalizeSettings.setOnClickListener(this) + imageSettings.setOnClickListener(this) + notificationSettings.setOnClickListener(this) + otherSettings.setOnClickListener(this) + } + + private fun inflateFragment(fragment: Fragment, @StringRes title: Int) { + if (activity != null) { + (activity as SettingsActivity).setupFragment(fragment, title) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/NowPlayingSettingsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/NowPlayingSettingsFragment.java index ee67454f..74da5bfe 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/NowPlayingSettingsFragment.java +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/NowPlayingSettingsFragment.java @@ -7,7 +7,7 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.preference.TwoStatePreference; import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.App; import code.name.monkey.retromusic.util.PreferenceUtil; /** @@ -25,7 +25,7 @@ public class NowPlayingSettingsFragment extends AbsSettingsFragment implements final TwoStatePreference carouselEffect = (TwoStatePreference) findPreference("carousel_effect"); carouselEffect.setOnPreferenceChangeListener((preference, newValue) -> { - if ((Boolean) newValue && !RetroApplication.Companion.isProVersion()) { + if ((Boolean) newValue && !App.Companion.isProVersion()) { showProToastAndNavigate(getActivity().getString(R.string.pref_title_toggle_carousel_effect)); return false; } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/PersonaizeSettingsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/PersonaizeSettingsFragment.java index 39dc558d..879c0a1a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/PersonaizeSettingsFragment.java +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/PersonaizeSettingsFragment.java @@ -7,7 +7,7 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.preference.TwoStatePreference; import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.App; import code.name.monkey.retromusic.util.PreferenceUtil; public class PersonaizeSettingsFragment extends AbsSettingsFragment implements SharedPreferences.OnSharedPreferenceChangeListener { @@ -16,7 +16,7 @@ public class PersonaizeSettingsFragment extends AbsSettingsFragment implements S public void invalidateSettings() { final TwoStatePreference cornerWindow = (TwoStatePreference) findPreference("corner_window"); cornerWindow.setOnPreferenceChangeListener((preference, newValue) -> { - if ((Boolean) newValue && !RetroApplication.Companion.isProVersion()) { + if ((Boolean) newValue && !App.Companion.isProVersion()) { showProToastAndNavigate(getActivity().getString(R.string.pref_title_round_corners)); return false; } diff --git a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ThemeSettingsFragment.java b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ThemeSettingsFragment.java index 2a4e0095..60e4f8af 100644 --- a/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ThemeSettingsFragment.java +++ b/app/src/main/java/code/name/monkey/retromusic/ui/fragments/settings/ThemeSettingsFragment.java @@ -14,7 +14,7 @@ import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEColorPreference import code.name.monkey.appthemehelper.util.ColorUtil; import code.name.monkey.appthemehelper.util.VersionUtils; import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.App; import code.name.monkey.retromusic.ui.activities.SettingsActivity; import code.name.monkey.retromusic.util.PreferenceUtil; @@ -48,7 +48,7 @@ public class ThemeSettingsFragment extends AbsSettingsFragment { generalTheme.setOnPreferenceChangeListener((preference, newValue) -> { String theme = (String) newValue; - if (theme.equals("color") && !RetroApplication.Companion.isProVersion()) { + if (theme.equals("color") && !App.Companion.isProVersion()) { primaryColorPref.setVisible(false); showProToastAndNavigate("Color theme"); return false; diff --git a/app/src/main/java/code/name/monkey/retromusic/util/CustomArtistImageUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/CustomArtistImageUtil.java index 34406ea7..462630f5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/CustomArtistImageUtil.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/CustomArtistImageUtil.java @@ -22,7 +22,7 @@ import java.io.OutputStream; import java.util.Locale; import androidx.annotation.NonNull; -import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.App; import code.name.monkey.retromusic.model.Artist; @@ -55,12 +55,12 @@ public class CustomArtistImageUtil { } public static File getFile(Artist artist) { - File dir = new File(RetroApplication.Companion.getInstance().getFilesDir(), FOLDER_NAME); + File dir = new File(App.Companion.getInstance().getFilesDir(), FOLDER_NAME); return new File(dir, getFileName(artist)); } public void setCustomArtistImage(final Artist artist, Uri uri) { - Glide.with(RetroApplication.Companion.getInstance()) + Glide.with(App.Companion.getInstance()) .load(uri) .asBitmap() .diskCacheStrategy(DiskCacheStrategy.NONE) @@ -70,7 +70,7 @@ public class CustomArtistImageUtil { public void onLoadFailed(Exception e, Drawable errorDrawable) { super.onLoadFailed(e, errorDrawable); e.printStackTrace(); - Toast.makeText(RetroApplication.Companion.getInstance(), e.toString(), Toast.LENGTH_LONG).show(); + Toast.makeText(App.Companion.getInstance(), e.toString(), Toast.LENGTH_LONG).show(); } @SuppressLint("StaticFieldLeak") @@ -80,7 +80,7 @@ public class CustomArtistImageUtil { @SuppressLint("ApplySharedPref") @Override protected Void doInBackground(Void... params) { - File dir = new File(RetroApplication.Companion.getInstance().getFilesDir(), FOLDER_NAME); + File dir = new File(App.Companion.getInstance().getFilesDir(), FOLDER_NAME); if (!dir.exists()) { if (!dir.mkdirs()) { // create the folder return null; @@ -94,13 +94,13 @@ public class CustomArtistImageUtil { succesful = ImageUtil.resizeBitmap(resource, 2048).compress(Bitmap.CompressFormat.JPEG, 100, os); os.close(); } catch (IOException e) { - Toast.makeText(RetroApplication.Companion.getInstance(), e.toString(), Toast.LENGTH_LONG).show(); + Toast.makeText(App.Companion.getInstance(), e.toString(), Toast.LENGTH_LONG).show(); } if (succesful) { mPreferences.edit().putBoolean(getFileName(artist), true).commit(); - ArtistSignatureUtil.getInstance(RetroApplication.Companion.getInstance()).updateArtistSignature(artist.getName()); - RetroApplication.Companion.getInstance().getContentResolver().notifyChange(Uri.parse("content://media"), null); // trigger media store changed to force artist image reload + ArtistSignatureUtil.getInstance(App.Companion.getInstance()).updateArtistSignature(artist.getName()); + App.Companion.getInstance().getContentResolver().notifyChange(Uri.parse("content://media"), null); // trigger media store changed to force artist image reload } return null; } @@ -116,8 +116,8 @@ public class CustomArtistImageUtil { @Override protected Void doInBackground(Void... params) { mPreferences.edit().putBoolean(getFileName(artist), false).commit(); - ArtistSignatureUtil.getInstance(RetroApplication.Companion.getInstance()).updateArtistSignature(artist.getName()); - RetroApplication.Companion.getInstance().getContentResolver().notifyChange(Uri.parse("content://media"), null); // trigger media store changed to force artist image reload + ArtistSignatureUtil.getInstance(App.Companion.getInstance()).updateArtistSignature(artist.getName()); + App.Companion.getInstance().getContentResolver().notifyChange(Uri.parse("content://media"), null); // trigger media store changed to force artist image reload File file = getFile(artist); if (!file.exists()) { diff --git a/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.java index 44ad3fcb..7389773f 100755 --- a/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.java @@ -34,7 +34,6 @@ import code.name.monkey.retromusic.ui.activities.UserInfoActivity; import code.name.monkey.retromusic.ui.activities.WhatsNewActivity; import static code.name.monkey.retromusic.Constants.RATE_ON_GOOGLE_PLAY; -import static code.name.monkey.retromusic.ui.activities.GenreDetailsActivity.EXTRA_GENRE_ID; import static code.name.monkey.retromusic.util.RetroUtil.openUrl; @@ -60,7 +59,7 @@ public class NavigationUtil { public static void goToPlaylistNew(@NonNull Activity activity, Playlist playlist) { Intent intent = new Intent(activity, PlaylistDetailActivity.class); - intent.putExtra(PlaylistDetailActivity.EXTRA_PLAYLIST, playlist); + intent.putExtra(PlaylistDetailActivity.Companion.getEXTRA_PLAYLIST(), playlist); ActivityCompat.startActivity(activity, intent, null); } @@ -102,7 +101,7 @@ public class NavigationUtil { public static void goToGenre(@NonNull Activity activity, @NonNull Genre genre) { Intent intent = new Intent(activity, GenreDetailsActivity.class); - intent.putExtra(EXTRA_GENRE_ID, genre); + intent.putExtra(GenreDetailsActivity.EXTRA_GENRE_ID, genre); ActivityCompat.startActivity(activity, intent, null); } 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 9b93568b..4b8e93d7 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 @@ -21,8 +21,8 @@ import androidx.annotation.LayoutRes; import androidx.annotation.NonNull; import androidx.annotation.StyleRes; import androidx.viewpager.widget.ViewPager; +import code.name.monkey.retromusic.App; import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.RetroApplication; import code.name.monkey.retromusic.helper.SortOrder; import code.name.monkey.retromusic.model.CategoryInfo; import code.name.monkey.retromusic.transform.CascadingPageTransformer; @@ -122,7 +122,7 @@ public final class PreferenceUtil { public static PreferenceUtil getInstance() { if (sInstance == null) { - sInstance = new PreferenceUtil(RetroApplication.Companion.getContext()); + sInstance = new PreferenceUtil(App.Companion.getContext()); } return sInstance; } @@ -279,7 +279,7 @@ public final class PreferenceUtil { public final int getLastPage() { - return mPreferences.getInt(LAST_PAGE, R.id.action_home); + return mPreferences.getInt(LAST_PAGE, R.id.action_song); } public void setLastPage(final int value) { diff --git a/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java index 01bfe30b..a37f0233 100755 --- a/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java @@ -46,7 +46,7 @@ import androidx.core.content.ContextCompat; import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; import code.name.monkey.appthemehelper.ThemeStore; import code.name.monkey.appthemehelper.util.TintHelper; -import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.App; public class RetroUtil { @@ -84,11 +84,11 @@ public class RetroUtil { } public static boolean isTablet() { - return RetroApplication.Companion.getContext().getResources().getConfiguration().smallestScreenWidthDp >= 600; + return App.Companion.getContext().getResources().getConfiguration().smallestScreenWidthDp >= 600; } public static boolean isLandscape() { - return RetroApplication.Companion.getContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; + return App.Companion.getContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) @@ -199,8 +199,8 @@ public class RetroUtil { public static Drawable getTintedDrawable(@DrawableRes int id) { return TintHelper - .createTintedDrawable(ContextCompat.getDrawable(RetroApplication.Companion.getInstance(), id), - ThemeStore.accentColor(RetroApplication.Companion.getInstance())); + .createTintedDrawable(ContextCompat.getDrawable(App.Companion.getInstance(), id), + ThemeStore.accentColor(App.Companion.getInstance())); } public static Bitmap createBitmap(Drawable drawable, float sizeMultiplier) { @@ -297,9 +297,9 @@ public class RetroUtil { public static int getStatusBarHeight() { int result = 0; - int resourceId = RetroApplication.Companion.getContext().getResources().getIdentifier("status_bar_height", "dimen", "android"); + int resourceId = App.Companion.getContext().getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { - result = RetroApplication.Companion.getContext().getResources().getDimensionPixelSize(resourceId); + result = App.Companion.getContext().getResources().getDimensionPixelSize(resourceId); } return result; } @@ -337,9 +337,9 @@ public class RetroUtil { public static int getNavigationBarHeight(Activity activity) { /* int result = 0; - int resourceId = RetroApplication.getContext().getResources().getIdentifier("navigation_bar_height", "dimen", "android"); + int resourceId = App.getContext().getResources().getIdentifier("navigation_bar_height", "dimen", "android"); if (resourceId > 0) { - result = RetroApplication.getContext().getResources().getDimensionPixelSize(resourceId); + result = App.getContext().getResources().getDimensionPixelSize(resourceId); } return result;*/ DisplayMetrics metrics = new DisplayMetrics(); @@ -415,7 +415,7 @@ public class RetroUtil { } public static boolean checkNavigationBarHeight() { - Resources resources = RetroApplication.Companion.getContext().getResources(); + Resources resources = App.Companion.getContext().getResources(); int orientation = resources.getConfiguration().orientation; if (!hasNavBar(resources)) { return false; diff --git a/app/src/main/java/code/name/monkey/retromusic/util/SystemUtils.java b/app/src/main/java/code/name/monkey/retromusic/util/SystemUtils.java index 2d4b7199..5e4b6072 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/SystemUtils.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/SystemUtils.java @@ -7,7 +7,7 @@ import android.content.res.Resources; import android.util.DisplayMetrics; import android.view.ViewGroup; -import code.name.monkey.retromusic.RetroApplication; +import code.name.monkey.retromusic.App; public class SystemUtils { @@ -38,9 +38,9 @@ public class SystemUtils { public static int getNavigationBarHeight() { int result = 0; - int resourceId = RetroApplication.Companion.getContext().getResources().getIdentifier("navigation_bar_height", "dimen", "android"); + int resourceId = App.Companion.getContext().getResources().getIdentifier("navigation_bar_height", "dimen", "android"); if (resourceId > 0) { - result = RetroApplication.Companion.getContext().getResources().getDimensionPixelSize(resourceId); + result = App.Companion.getContext().getResources().getDimensionPixelSize(resourceId); } return result; } diff --git a/app/src/main/java/code/name/monkey/retromusic/views/MaterialButtonTextColor.java b/app/src/main/java/code/name/monkey/retromusic/views/MaterialButtonTextColor.java new file mode 100644 index 00000000..b5ff0287 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/MaterialButtonTextColor.java @@ -0,0 +1,25 @@ +package code.name.monkey.retromusic.views; + +import android.content.Context; +import android.util.AttributeSet; + +import com.google.android.material.button.MaterialButton; + +import code.name.monkey.appthemehelper.ThemeStore; +import code.name.monkey.appthemehelper.util.ColorUtil; +import code.name.monkey.appthemehelper.util.MaterialValueHelper; + +public class MaterialButtonTextColor extends MaterialButton { + public MaterialButtonTextColor(Context context) { + this(context, null); + } + + public MaterialButtonTextColor(Context context, AttributeSet attrs) { + this(context, attrs, -1); + } + + public MaterialButtonTextColor(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setTextColor(MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(ThemeStore.primaryColor(getContext())))); + } +} diff --git a/app/src/main/res/drawable/navigation_item.xml b/app/src/main/res/drawable/navigation_item.xml new file mode 100644 index 00000000..4238c61c --- /dev/null +++ b/app/src/main/res/drawable/navigation_item.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/navigation_view_item.xml b/app/src/main/res/drawable/navigation_view_item.xml new file mode 100644 index 00000000..9e3c2556 --- /dev/null +++ b/app/src/main/res/drawable/navigation_view_item.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/font/circular_std_black.otf b/app/src/main/res/font/circular_std_black.otf deleted file mode 100755 index c62b210c..00000000 Binary files a/app/src/main/res/font/circular_std_black.otf and /dev/null differ diff --git a/app/src/main/res/font/circular_std_book.otf b/app/src/main/res/font/circular_std_book.otf deleted file mode 100755 index 3a1f1ad8..00000000 Binary files a/app/src/main/res/font/circular_std_book.otf and /dev/null differ diff --git a/app/src/main/res/font/font.xml b/app/src/main/res/font/font.xml index 485b0418..4fe9ca2d 100644 --- a/app/src/main/res/font/font.xml +++ b/app/src/main/res/font/font.xml @@ -1,11 +1,11 @@ \ No newline at end of file diff --git a/app/src/main/res/font/sans_bold.ttf b/app/src/main/res/font/sans_bold.ttf new file mode 100755 index 00000000..80497666 Binary files /dev/null and b/app/src/main/res/font/sans_bold.ttf differ diff --git a/app/src/main/res/font/sans_regular.ttf b/app/src/main/res/font/sans_regular.ttf new file mode 100755 index 00000000..ab605f9e Binary files /dev/null and b/app/src/main/res/font/sans_regular.ttf differ diff --git a/app/src/main/res/layout-land/fragment_card_blur_player.xml b/app/src/main/res/layout-land/fragment_card_blur_player.xml index 565480bc..f8ae76af 100644 --- a/app/src/main/res/layout-land/fragment_card_blur_player.xml +++ b/app/src/main/res/layout-land/fragment_card_blur_player.xml @@ -8,7 +8,7 @@ android:focusable="true"> @@ -31,16 +31,20 @@ android:layout_height="match_parent" android:orientation="vertical"> - + + + + @@ -78,7 +82,7 @@ android:layout_marginEnd="96dp"> - - @@ -71,7 +66,7 @@ android:layout_height="match_parent"> @@ -42,7 +42,7 @@ android:layout_height="match_parent"> - - - - + tools:ignore="MissingPrefix" /> - + @@ -61,7 +61,7 @@ android:layout_weight="0"> diff --git a/app/src/main/res/layout-xlarge-land/fragment_home.xml b/app/src/main/res/layout-xlarge-land/fragment_home.xml index db53cbb0..6c216571 100644 --- a/app/src/main/res/layout-xlarge-land/fragment_home.xml +++ b/app/src/main/res/layout-xlarge-land/fragment_home.xml @@ -27,24 +27,19 @@ android:elevation="0dp" app:elevation="0dp"> - - - - + tools:ignore="MissingPrefix" /> - + diff --git a/app/src/main/res/layout-xlarge-land/fragment_player.xml b/app/src/main/res/layout-xlarge-land/fragment_player.xml index 9284e24d..68862dbd 100644 --- a/app/src/main/res/layout-xlarge-land/fragment_player.xml +++ b/app/src/main/res/layout-xlarge-land/fragment_player.xml @@ -8,7 +8,7 @@ android:focusable="true"> @@ -54,13 +54,12 @@ diff --git a/app/src/main/res/layout-xlarge/fragment_home.xml b/app/src/main/res/layout-xlarge/fragment_home.xml index 5bc9820c..76f220b8 100644 --- a/app/src/main/res/layout-xlarge/fragment_home.xml +++ b/app/src/main/res/layout-xlarge/fragment_home.xml @@ -28,24 +28,19 @@ android:elevation="0dp" app:elevation="0dp"> - - - - + tools:ignore="MissingPrefix" /> - + @@ -54,13 +54,12 @@ diff --git a/app/src/main/res/layout/fragment_adaptive_player.xml b/app/src/main/res/layout/fragment_adaptive_player.xml index c377147d..1150691a 100644 --- a/app/src/main/res/layout/fragment_adaptive_player.xml +++ b/app/src/main/res/layout/fragment_adaptive_player.xml @@ -34,7 +34,7 @@ @@ -69,7 +69,7 @@ android:layout_weight="0"> @@ -36,13 +36,19 @@ android:orientation="vertical"> + + + + + @@ -77,7 +82,7 @@ android:layout_gravity="bottom"> - + - - + - - - - - - - - - - - - - - - - - - - - - - - - + - + @@ -70,7 +67,7 @@ android:layout_height="match_parent"> - - - + + + + + + android:clickable="true" + android:focusable="true" + android:foreground="?rectSelector" + android:minHeight="72dp" + android:orientation="horizontal" + tools:ignore="UnusedAttribute"> - + android:layout_gravity="center_vertical" + android:layout_weight="0" + app:cardCornerRadius="6dp" + app:cardElevation="0dp" + app:contentPaddingLeft="16dp"> - + - + - - - - - - - - - - - - + android:layout_marginTop="12dp" + android:layout_marginBottom="12dp" + android:layout_weight="1.0" + android:orientation="vertical" + android:paddingStart="16dp" + android:paddingEnd="16dp"> - + + + + + diff --git a/app/src/main/res/layout/fragment_fit.xml b/app/src/main/res/layout/fragment_fit.xml index b45af0d6..2fddff91 100644 --- a/app/src/main/res/layout/fragment_fit.xml +++ b/app/src/main/res/layout/fragment_fit.xml @@ -14,13 +14,12 @@ android:orientation="vertical"> - - @@ -93,98 +88,7 @@ android:textColor="?android:attr/textColorSecondary" /> - + - - - - - - - - - - - - - - - - - - + diff --git a/app/src/main/res/layout/fragment_flat_player.xml b/app/src/main/res/layout/fragment_flat_player.xml index 7f3ef825..f24de9d1 100644 --- a/app/src/main/res/layout/fragment_flat_player.xml +++ b/app/src/main/res/layout/fragment_flat_player.xml @@ -9,7 +9,7 @@ android:orientation="vertical"> @@ -33,26 +33,24 @@ - - - - - - - + - - - - + diff --git a/app/src/main/res/layout/fragment_full.xml b/app/src/main/res/layout/fragment_full.xml index 0782b84b..0bc5d5c5 100644 --- a/app/src/main/res/layout/fragment_full.xml +++ b/app/src/main/res/layout/fragment_full.xml @@ -44,7 +44,7 @@ diff --git a/app/src/main/res/layout/fragment_hmm_player.xml b/app/src/main/res/layout/fragment_hmm_player.xml index b3d534a5..a65dde76 100644 --- a/app/src/main/res/layout/fragment_hmm_player.xml +++ b/app/src/main/res/layout/fragment_hmm_player.xml @@ -103,8 +103,7 @@ diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index c7649a14..4237b4c2 100755 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -27,13 +27,13 @@ - @@ -32,12 +32,11 @@ - - - - - - - - + - + - + - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_volume.xml b/app/src/main/res/layout/fragment_volume.xml index ebe69c00..456c394f 100755 --- a/app/src/main/res/layout/fragment_volume.xml +++ b/app/src/main/res/layout/fragment_volume.xml @@ -20,7 +20,7 @@ android:id="@+id/volumeSeekBar" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_weight="1" /> + android:layout_weight="1" /> - - + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index b7958152..a79edbc1 100755 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -105,7 +105,6 @@ @layout/activity_album - @layout/activity_album_style_2 @@ -201,7 +200,6 @@ @layout/activity_album - @layout/activity_album_small diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml deleted file mode 100644 index a6b3daec..00000000 --- a/app/src/main/res/values/ic_launcher_background.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/values/md_colors.xml b/app/src/main/res/values/md_colors.xml deleted file mode 100644 index 0d2c4cc4..00000000 --- a/app/src/main/res/values/md_colors.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ac68a315..a9fcb4c0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -558,4 +558,5 @@ Click or Slide Click to open with or slide to without transparent navigation of now playing screen Clear queue + Buy Retro Music Pro diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index bb7d822a..3a97910a 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -40,13 +40,10 @@ 16dp - - @@ -100,5 +99,11 @@ start + + diff --git a/app/src/main/res/values/swipe_button_attrs.xml b/app/src/main/res/values/swipe_button_attrs.xml deleted file mode 100644 index ecd20f74..00000000 --- a/app/src/main/res/values/swipe_button_attrs.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/sans/res/font/font.xml b/app/src/sans/res/font/font.xml index e4827093..00bae1c3 100644 --- a/app/src/sans/res/font/font.xml +++ b/app/src/sans/res/font/font.xml @@ -4,4 +4,8 @@ android:font="@font/product_sans_regular" android:fontStyle="normal" android:fontWeight="400" /> + \ No newline at end of file diff --git a/app/src/sans/res/font/product_sans_bold.ttf b/app/src/sans/res/font/product_sans_bold.ttf new file mode 100755 index 00000000..d847195c Binary files /dev/null and b/app/src/sans/res/font/product_sans_bold.ttf differ