move fragments to root directory
This commit is contained in:
parent
53657919af
commit
e0a184daa3
30 changed files with 59 additions and 59 deletions
|
|
@ -0,0 +1,71 @@
|
|||
package com.dkanada.gramophone.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.dkanada.gramophone.interfaces.MusicServiceEventListener;
|
||||
import com.dkanada.gramophone.activities.base.AbsMusicServiceActivity;
|
||||
|
||||
public class AbsMusicServiceFragment extends Fragment implements MusicServiceEventListener {
|
||||
private AbsMusicServiceActivity activity;
|
||||
|
||||
@Override
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
try {
|
||||
activity = (AbsMusicServiceActivity) context;
|
||||
} catch (ClassCastException e) {
|
||||
throw new RuntimeException(context.getClass().getSimpleName() + " must be an instance of " + AbsMusicServiceActivity.class.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
activity = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
activity.addMusicServiceEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
activity.removeMusicServiceEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueueChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayMetadataChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayStateChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepeatModeChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShuffleModeChanged() {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.dkanada.gramophone.fragments.mainactivity;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.dkanada.gramophone.activities.MainActivity;
|
||||
|
||||
public abstract class AbsMainActivityFragment extends Fragment {
|
||||
public MainActivity getMainActivity() {
|
||||
return (MainActivity) getActivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,461 @@
|
|||
package com.dkanada.gramophone.fragments.mainactivity.library;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.SubMenu;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.dkanada.gramophone.databinding.FragmentLibraryBinding;
|
||||
import com.google.android.material.appbar.AppBarLayout;
|
||||
import com.afollestad.materialcab.MaterialCab;
|
||||
import com.kabouzeid.appthemehelper.ThemeStore;
|
||||
import com.kabouzeid.appthemehelper.common.ATHToolbarActivity;
|
||||
import com.kabouzeid.appthemehelper.util.TabLayoutUtil;
|
||||
import com.kabouzeid.appthemehelper.util.ToolbarContentTintHelper;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.adapter.MusicLibraryPagerAdapter;
|
||||
import com.dkanada.gramophone.dialogs.CreatePlaylistDialog;
|
||||
import com.dkanada.gramophone.helper.sort.SortMethod;
|
||||
import com.dkanada.gramophone.helper.sort.SortOrder;
|
||||
import com.dkanada.gramophone.interfaces.CabHolder;
|
||||
import com.dkanada.gramophone.activities.MainActivity;
|
||||
import com.dkanada.gramophone.activities.SearchActivity;
|
||||
import com.dkanada.gramophone.fragments.mainactivity.AbsMainActivityFragment;
|
||||
import com.dkanada.gramophone.fragments.mainactivity.library.pager.AbsLibraryPagerRecyclerViewCustomGridSizeFragment;
|
||||
import com.dkanada.gramophone.fragments.mainactivity.library.pager.AlbumsFragment;
|
||||
import com.dkanada.gramophone.fragments.mainactivity.library.pager.ArtistsFragment;
|
||||
import com.dkanada.gramophone.fragments.mainactivity.library.pager.PlaylistsFragment;
|
||||
import com.dkanada.gramophone.fragments.mainactivity.library.pager.SongsFragment;
|
||||
import com.dkanada.gramophone.util.ThemeUtil;
|
||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
|
||||
public class LibraryFragment extends AbsMainActivityFragment implements CabHolder, MainActivity.MainActivityFragmentCallbacks, ViewPager.OnPageChangeListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private FragmentLibraryBinding binding;
|
||||
|
||||
private MusicLibraryPagerAdapter pagerAdapter;
|
||||
private MaterialCab cab;
|
||||
|
||||
public static LibraryFragment newInstance() {
|
||||
return new LibraryFragment();
|
||||
}
|
||||
|
||||
public LibraryFragment() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentLibraryBinding.inflate(inflater);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
PreferenceUtil.getInstance(getActivity()).unregisterOnSharedPreferenceChangedListener(this);
|
||||
super.onDestroyView();
|
||||
binding.pager.removeOnPageChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
PreferenceUtil.getInstance(getActivity()).registerOnSharedPreferenceChangedListener(this);
|
||||
getMainActivity().setStatusbarColorAuto();
|
||||
getMainActivity().setNavigationbarColorAuto();
|
||||
getMainActivity().setTaskDescriptionColorAuto();
|
||||
|
||||
setUpToolbar();
|
||||
setUpViewPager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
||||
if (PreferenceUtil.CATEGORIES.equals(key)) {
|
||||
Fragment current = getCurrentFragment();
|
||||
pagerAdapter.setCategoryInfos(PreferenceUtil.getInstance(getActivity()).getCategories());
|
||||
binding.pager.setOffscreenPageLimit(pagerAdapter.getCount() - 1);
|
||||
int position = pagerAdapter.getItemPosition(current);
|
||||
if (position < 0) position = 0;
|
||||
binding.pager.setCurrentItem(position);
|
||||
PreferenceUtil.getInstance(getContext()).setLastTab(position);
|
||||
|
||||
updateTabVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpToolbar() {
|
||||
int primaryColor = ThemeStore.primaryColor(requireActivity());
|
||||
binding.appbar.setBackgroundColor(primaryColor);
|
||||
binding.toolbar.setBackgroundColor(primaryColor);
|
||||
binding.toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp);
|
||||
requireActivity().setTitle(R.string.app_name);
|
||||
getMainActivity().setSupportActionBar(binding.toolbar);
|
||||
}
|
||||
|
||||
private void setUpViewPager() {
|
||||
pagerAdapter = new MusicLibraryPagerAdapter(requireActivity(), getChildFragmentManager());
|
||||
binding.pager.setAdapter(pagerAdapter);
|
||||
binding.pager.setOffscreenPageLimit(pagerAdapter.getCount() - 1);
|
||||
|
||||
binding.tabs.setupWithViewPager(binding.pager);
|
||||
|
||||
int primaryColor = ThemeStore.primaryColor(requireActivity());
|
||||
int normalColor = ToolbarContentTintHelper.toolbarSubtitleColor(requireActivity(), primaryColor);
|
||||
int selectedColor = ToolbarContentTintHelper.toolbarTitleColor(requireActivity(), primaryColor);
|
||||
TabLayoutUtil.setTabIconColors(binding.tabs, normalColor, selectedColor);
|
||||
binding.tabs.setTabTextColors(normalColor, selectedColor);
|
||||
binding.tabs.setSelectedTabIndicatorColor(ThemeStore.accentColor(requireActivity()));
|
||||
|
||||
updateTabVisibility();
|
||||
|
||||
if (PreferenceUtil.getInstance(getContext()).getRememberLastTab()) {
|
||||
binding.pager.setCurrentItem(PreferenceUtil.getInstance(getContext()).getLastTab());
|
||||
}
|
||||
|
||||
binding.pager.addOnPageChangeListener(this);
|
||||
}
|
||||
|
||||
private void updateTabVisibility() {
|
||||
// hide the tab bar when only a single tab is visible
|
||||
binding.tabs.setVisibility(pagerAdapter.getCount() == 1 ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
public Fragment getCurrentFragment() {
|
||||
return pagerAdapter.getFragment(binding.pager.getCurrentItem());
|
||||
}
|
||||
|
||||
private boolean isPlaylistPage() {
|
||||
return getCurrentFragment() instanceof PlaylistsFragment;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MaterialCab openCab(final int menuRes, final MaterialCab.Callback callback) {
|
||||
if (cab != null && cab.isActive()) cab.finish();
|
||||
cab = new MaterialCab(getMainActivity(), R.id.cab_stub)
|
||||
.setMenu(menuRes)
|
||||
.setCloseDrawableRes(R.drawable.ic_close_white_24dp)
|
||||
.setBackgroundColor(ThemeUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor(requireActivity())))
|
||||
.start(callback);
|
||||
|
||||
return cab;
|
||||
}
|
||||
|
||||
public void addOnAppBarOffsetChangedListener(AppBarLayout.OnOffsetChangedListener onOffsetChangedListener) {
|
||||
binding.appbar.addOnOffsetChangedListener(onOffsetChangedListener);
|
||||
}
|
||||
|
||||
public void removeOnAppBarOffsetChangedListener(AppBarLayout.OnOffsetChangedListener onOffsetChangedListener) {
|
||||
binding.appbar.removeOnOffsetChangedListener(onOffsetChangedListener);
|
||||
}
|
||||
|
||||
public int getTotalAppBarScrollingRange() {
|
||||
return binding.appbar.getTotalScrollRange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
inflater.inflate(R.menu.menu_main, menu);
|
||||
if (isPlaylistPage()) {
|
||||
menu.add(0, R.id.action_new_playlist, 0, R.string.action_new_playlist);
|
||||
}
|
||||
|
||||
Fragment currentFragment = getCurrentFragment();
|
||||
if (currentFragment instanceof AbsLibraryPagerRecyclerViewCustomGridSizeFragment && currentFragment.isAdded()) {
|
||||
AbsLibraryPagerRecyclerViewCustomGridSizeFragment absLibraryRecyclerViewCustomGridSizeFragment = (AbsLibraryPagerRecyclerViewCustomGridSizeFragment) currentFragment;
|
||||
|
||||
MenuItem gridSizeItem = menu.findItem(R.id.action_grid_size);
|
||||
setUpGridSizeMenu(absLibraryRecyclerViewCustomGridSizeFragment, gridSizeItem.getSubMenu());
|
||||
|
||||
menu.findItem(R.id.action_colored_footers).setChecked(absLibraryRecyclerViewCustomGridSizeFragment.usePalette());
|
||||
menu.findItem(R.id.action_colored_footers).setEnabled(absLibraryRecyclerViewCustomGridSizeFragment.canUsePalette());
|
||||
|
||||
// TODO the API doesn't support artist sorting
|
||||
if (currentFragment instanceof ArtistsFragment) {
|
||||
menu.removeItem(R.id.action_sort_method);
|
||||
menu.removeItem(R.id.action_sort_order);
|
||||
} else {
|
||||
setUpSortMethodMenu(absLibraryRecyclerViewCustomGridSizeFragment, menu.findItem(R.id.action_sort_method).getSubMenu());
|
||||
setUpSortOrderMenu(absLibraryRecyclerViewCustomGridSizeFragment, menu.findItem(R.id.action_sort_order).getSubMenu());
|
||||
}
|
||||
} else {
|
||||
menu.removeItem(R.id.action_grid_size);
|
||||
menu.removeItem(R.id.action_colored_footers);
|
||||
menu.removeItem(R.id.action_sort_method);
|
||||
menu.removeItem(R.id.action_sort_order);
|
||||
}
|
||||
|
||||
Activity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
ToolbarContentTintHelper.handleOnCreateOptionsMenu(getActivity(), binding.toolbar, menu, ATHToolbarActivity.getToolbarBackgroundColor(binding.toolbar));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(@NonNull Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
Activity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(activity, binding.toolbar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
Fragment currentFragment = getCurrentFragment();
|
||||
if (currentFragment instanceof AbsLibraryPagerRecyclerViewCustomGridSizeFragment) {
|
||||
AbsLibraryPagerRecyclerViewCustomGridSizeFragment absLibraryRecyclerViewCustomGridSizeFragment = (AbsLibraryPagerRecyclerViewCustomGridSizeFragment) currentFragment;
|
||||
if (item.getItemId() == R.id.action_colored_footers) {
|
||||
item.setChecked(!item.isChecked());
|
||||
absLibraryRecyclerViewCustomGridSizeFragment.setAndSaveUsePalette(item.isChecked());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (handleGridSizeMenuItem(absLibraryRecyclerViewCustomGridSizeFragment, item)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (handleSortMethodMenuItem(absLibraryRecyclerViewCustomGridSizeFragment, item)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (handleSortOrderMenuItem(absLibraryRecyclerViewCustomGridSizeFragment, item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int id = item.getItemId();
|
||||
switch (id) {
|
||||
case R.id.action_shuffle_all:
|
||||
Toast.makeText(requireActivity(), requireActivity().getResources().getString(R.string.error_unexpected), Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
case R.id.action_new_playlist:
|
||||
CreatePlaylistDialog.create().show(getChildFragmentManager(), "CREATE_PLAYLIST");
|
||||
return true;
|
||||
case R.id.action_search:
|
||||
startActivity(new Intent(getActivity(), SearchActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void setUpGridSizeMenu(@NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment, @NonNull SubMenu gridSizeMenu) {
|
||||
switch (fragment.getGridSize()) {
|
||||
case 1:
|
||||
gridSizeMenu.findItem(R.id.action_grid_size_1).setChecked(true);
|
||||
break;
|
||||
case 2:
|
||||
gridSizeMenu.findItem(R.id.action_grid_size_2).setChecked(true);
|
||||
break;
|
||||
case 3:
|
||||
gridSizeMenu.findItem(R.id.action_grid_size_3).setChecked(true);
|
||||
break;
|
||||
case 4:
|
||||
gridSizeMenu.findItem(R.id.action_grid_size_4).setChecked(true);
|
||||
break;
|
||||
case 5:
|
||||
gridSizeMenu.findItem(R.id.action_grid_size_5).setChecked(true);
|
||||
break;
|
||||
case 6:
|
||||
gridSizeMenu.findItem(R.id.action_grid_size_6).setChecked(true);
|
||||
break;
|
||||
case 7:
|
||||
gridSizeMenu.findItem(R.id.action_grid_size_7).setChecked(true);
|
||||
break;
|
||||
case 8:
|
||||
gridSizeMenu.findItem(R.id.action_grid_size_8).setChecked(true);
|
||||
break;
|
||||
}
|
||||
|
||||
int maxGridSize = fragment.getMaxGridSize();
|
||||
if (maxGridSize < 8) {
|
||||
gridSizeMenu.findItem(R.id.action_grid_size_8).setVisible(false);
|
||||
}
|
||||
if (maxGridSize < 7) {
|
||||
gridSizeMenu.findItem(R.id.action_grid_size_7).setVisible(false);
|
||||
}
|
||||
if (maxGridSize < 6) {
|
||||
gridSizeMenu.findItem(R.id.action_grid_size_6).setVisible(false);
|
||||
}
|
||||
if (maxGridSize < 5) {
|
||||
gridSizeMenu.findItem(R.id.action_grid_size_5).setVisible(false);
|
||||
}
|
||||
if (maxGridSize < 4) {
|
||||
gridSizeMenu.findItem(R.id.action_grid_size_4).setVisible(false);
|
||||
}
|
||||
if (maxGridSize < 3) {
|
||||
gridSizeMenu.findItem(R.id.action_grid_size_3).setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleGridSizeMenuItem(@NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment, @NonNull MenuItem item) {
|
||||
int gridSize = 0;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_grid_size_1:
|
||||
gridSize = 1;
|
||||
break;
|
||||
case R.id.action_grid_size_2:
|
||||
gridSize = 2;
|
||||
break;
|
||||
case R.id.action_grid_size_3:
|
||||
gridSize = 3;
|
||||
break;
|
||||
case R.id.action_grid_size_4:
|
||||
gridSize = 4;
|
||||
break;
|
||||
case R.id.action_grid_size_5:
|
||||
gridSize = 5;
|
||||
break;
|
||||
case R.id.action_grid_size_6:
|
||||
gridSize = 6;
|
||||
break;
|
||||
case R.id.action_grid_size_7:
|
||||
gridSize = 7;
|
||||
break;
|
||||
case R.id.action_grid_size_8:
|
||||
gridSize = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gridSize > 0) {
|
||||
item.setChecked(true);
|
||||
fragment.setAndSaveGridSize(gridSize);
|
||||
binding.toolbar.getMenu().findItem(R.id.action_colored_footers).setEnabled(fragment.canUsePalette());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setUpSortMethodMenu(@NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment, @NonNull SubMenu sortMethodMenu) {
|
||||
String currentSortMethod = fragment.getSortMethod();
|
||||
sortMethodMenu.clear();
|
||||
|
||||
if (fragment instanceof AlbumsFragment) {
|
||||
sortMethodMenu.add(0, R.id.action_sort_method_name, 0, R.string.sort_method_name)
|
||||
.setChecked(currentSortMethod.equals(SortMethod.NAME));
|
||||
sortMethodMenu.add(0, R.id.action_sort_method_artist, 1, R.string.sort_method_artist)
|
||||
.setChecked(currentSortMethod.equals(SortMethod.ARTIST));
|
||||
sortMethodMenu.add(0, R.id.action_sort_method_year, 2, R.string.sort_method_year)
|
||||
.setChecked(currentSortMethod.equals(SortMethod.YEAR));
|
||||
sortMethodMenu.add(0, R.id.action_sort_method_added, 3, R.string.sort_method_added)
|
||||
.setChecked(currentSortMethod.equals(SortMethod.ADDED));
|
||||
sortMethodMenu.add(0, R.id.action_sort_method_random, 4, R.string.sort_method_random)
|
||||
.setChecked(currentSortMethod.equals(SortMethod.RANDOM));
|
||||
} else if (fragment instanceof SongsFragment) {
|
||||
sortMethodMenu.add(0, R.id.action_sort_method_name, 0, R.string.sort_method_name)
|
||||
.setChecked(currentSortMethod.equals(SortMethod.NAME));
|
||||
sortMethodMenu.add(0, R.id.action_sort_method_album, 1, R.string.sort_method_album)
|
||||
.setChecked(currentSortMethod.equals(SortMethod.ALBUM));
|
||||
sortMethodMenu.add(0, R.id.action_sort_method_artist, 2, R.string.sort_method_artist)
|
||||
.setChecked(currentSortMethod.equals(SortMethod.ARTIST));
|
||||
sortMethodMenu.add(0, R.id.action_sort_method_year, 3, R.string.sort_method_year)
|
||||
.setChecked(currentSortMethod.equals(SortMethod.YEAR));
|
||||
sortMethodMenu.add(0, R.id.action_sort_method_added, 4, R.string.sort_method_added)
|
||||
.setChecked(currentSortMethod.equals(SortMethod.ADDED));
|
||||
sortMethodMenu.add(0, R.id.action_sort_method_random, 5, R.string.sort_method_random)
|
||||
.setChecked(currentSortMethod.equals(SortMethod.RANDOM));
|
||||
}
|
||||
|
||||
sortMethodMenu.setGroupCheckable(0, true, true);
|
||||
}
|
||||
|
||||
private void setUpSortOrderMenu(@NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment, @NonNull SubMenu sortOrderMenu) {
|
||||
String currentSortOrder = fragment.getSortOrder();
|
||||
sortOrderMenu.clear();
|
||||
|
||||
sortOrderMenu.add(0, R.id.action_sort_order_ascending, 0, R.string.sort_order_ascending)
|
||||
.setChecked(currentSortOrder.equals(SortOrder.ASCENDING));
|
||||
sortOrderMenu.add(0, R.id.action_sort_order_descending, 1, R.string.sort_order_descending)
|
||||
.setChecked(currentSortOrder.equals(SortOrder.DESCENDING));
|
||||
|
||||
sortOrderMenu.setGroupCheckable(0, true, true);
|
||||
}
|
||||
|
||||
private boolean handleSortMethodMenuItem(@NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment, @NonNull MenuItem item) {
|
||||
String sortMethod = null;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_sort_method_name:
|
||||
sortMethod = SortMethod.NAME;
|
||||
break;
|
||||
case R.id.action_sort_method_album:
|
||||
sortMethod = SortMethod.ALBUM;
|
||||
break;
|
||||
case R.id.action_sort_method_artist:
|
||||
sortMethod = SortMethod.ARTIST;
|
||||
break;
|
||||
case R.id.action_sort_method_year:
|
||||
sortMethod = SortMethod.YEAR;
|
||||
break;
|
||||
case R.id.action_sort_method_added:
|
||||
sortMethod = SortMethod.ADDED;
|
||||
break;
|
||||
case R.id.action_sort_method_random:
|
||||
sortMethod = SortMethod.RANDOM;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sortMethod != null) {
|
||||
item.setChecked(true);
|
||||
fragment.setAndSaveSortMethod(sortMethod);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean handleSortOrderMenuItem(@NonNull AbsLibraryPagerRecyclerViewCustomGridSizeFragment fragment, @NonNull MenuItem item) {
|
||||
String sortOrder = null;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_sort_order_ascending:
|
||||
sortOrder = SortOrder.ASCENDING;
|
||||
break;
|
||||
case R.id.action_sort_order_descending:
|
||||
sortOrder = SortOrder.DESCENDING;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sortOrder != null) {
|
||||
item.setChecked(true);
|
||||
fragment.setAndSaveSortOrder(sortOrder);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleBackPress() {
|
||||
if (cab != null && cab.isActive()) {
|
||||
cab.finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
PreferenceUtil.getInstance(getActivity()).setLastTab(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.dkanada.gramophone.fragments.mainactivity.library.pager;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.dkanada.gramophone.fragments.AbsMusicServiceFragment;
|
||||
import com.dkanada.gramophone.fragments.mainactivity.library.LibraryFragment;
|
||||
|
||||
public class AbsLibraryPagerFragment extends AbsMusicServiceFragment {
|
||||
public LibraryFragment getLibraryFragment() {
|
||||
return (LibraryFragment) getParentFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
package com.dkanada.gramophone.fragments.mainactivity.library.pager;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.util.Util;
|
||||
|
||||
public abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment<A extends RecyclerView.Adapter, L extends RecyclerView.LayoutManager, Q> extends AbsLibraryPagerRecyclerViewFragment<A, L, Q> {
|
||||
private int gridSize;
|
||||
private String sortMethod;
|
||||
private String sortOrder;
|
||||
|
||||
private boolean usePaletteInitialized;
|
||||
private boolean usePalette;
|
||||
private int currentLayoutRes;
|
||||
|
||||
public final int getGridSize() {
|
||||
if (gridSize == 0) {
|
||||
if (isLandscape()) {
|
||||
gridSize = loadGridSizeLand();
|
||||
} else {
|
||||
gridSize = loadGridSize();
|
||||
}
|
||||
}
|
||||
|
||||
return gridSize;
|
||||
}
|
||||
|
||||
public int getMaxGridSize() {
|
||||
if (isLandscape()) {
|
||||
return getResources().getInteger(R.integer.max_columns_land);
|
||||
} else {
|
||||
return getResources().getInteger(R.integer.max_columns);
|
||||
}
|
||||
}
|
||||
|
||||
public final boolean usePalette() {
|
||||
if (!usePaletteInitialized) {
|
||||
usePalette = loadUsePalette();
|
||||
usePaletteInitialized = true;
|
||||
}
|
||||
|
||||
return usePalette;
|
||||
}
|
||||
|
||||
public final String getSortMethod() {
|
||||
if (sortMethod == null) {
|
||||
sortMethod = loadSortMethod();
|
||||
}
|
||||
|
||||
return sortMethod;
|
||||
}
|
||||
|
||||
public final String getSortOrder() {
|
||||
if (sortOrder == null) {
|
||||
sortOrder = loadSortOrder();
|
||||
}
|
||||
|
||||
return sortOrder;
|
||||
}
|
||||
|
||||
public void setAndSaveGridSize(final int gridSize) {
|
||||
int oldLayoutRes = getItemLayoutRes();
|
||||
this.gridSize = gridSize;
|
||||
if (isLandscape()) {
|
||||
saveGridSizeLand(gridSize);
|
||||
} else {
|
||||
saveGridSize(gridSize);
|
||||
}
|
||||
|
||||
// only recreate the adapter and layout manager if the layout currentLayoutRes has changed
|
||||
if (oldLayoutRes != getItemLayoutRes()) {
|
||||
invalidateLayoutManager();
|
||||
invalidateAdapter();
|
||||
} else {
|
||||
setGridSize(gridSize);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAndSaveUsePalette(final boolean usePalette) {
|
||||
this.usePalette = usePalette;
|
||||
saveUsePalette(usePalette);
|
||||
setUsePalette(usePalette);
|
||||
}
|
||||
|
||||
public void setAndSaveSortMethod(final String sortMethod) {
|
||||
this.sortMethod = sortMethod;
|
||||
saveSortMethod(sortMethod);
|
||||
setSortMethod(sortMethod);
|
||||
invalidateAdapter();
|
||||
}
|
||||
|
||||
public void setAndSaveSortOrder(final String sortOrder) {
|
||||
this.sortOrder = sortOrder;
|
||||
saveSortOrder(sortOrder);
|
||||
setSortOrder(sortOrder);
|
||||
invalidateAdapter();
|
||||
}
|
||||
|
||||
public boolean canUsePalette() {
|
||||
return getItemLayoutRes() == R.layout.item_grid;
|
||||
}
|
||||
|
||||
@LayoutRes
|
||||
protected int getItemLayoutRes() {
|
||||
if (getGridSize() > getMaxGridSizeForList()) {
|
||||
return R.layout.item_grid;
|
||||
}
|
||||
|
||||
return R.layout.item_list;
|
||||
}
|
||||
|
||||
protected final void notifyLayoutResChanged(@LayoutRes int res) {
|
||||
this.currentLayoutRes = res;
|
||||
|
||||
RecyclerView recyclerView = getRecyclerView();
|
||||
if (recyclerView != null) {
|
||||
applyRecyclerViewPaddingForLayoutRes(recyclerView, currentLayoutRes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
applyRecyclerViewPaddingForLayoutRes(getRecyclerView(), currentLayoutRes);
|
||||
}
|
||||
|
||||
protected void applyRecyclerViewPaddingForLayoutRes(@NonNull RecyclerView recyclerView, @LayoutRes int res) {
|
||||
int padding;
|
||||
if (res == R.layout.item_grid) {
|
||||
padding = (int) (getResources().getDisplayMetrics().density * 2);
|
||||
} else {
|
||||
padding = 0;
|
||||
}
|
||||
|
||||
recyclerView.setPadding(padding, padding, padding, padding);
|
||||
}
|
||||
|
||||
protected abstract int loadGridSize();
|
||||
|
||||
protected abstract void saveGridSize(int gridColumns);
|
||||
|
||||
protected abstract int loadGridSizeLand();
|
||||
|
||||
protected abstract void saveGridSizeLand(int gridColumns);
|
||||
|
||||
protected abstract void saveUsePalette(boolean usePalette);
|
||||
|
||||
protected abstract boolean loadUsePalette();
|
||||
|
||||
protected abstract void setUsePalette(boolean usePalette);
|
||||
|
||||
protected abstract void setGridSize(int gridSize);
|
||||
|
||||
protected abstract String loadSortMethod();
|
||||
|
||||
protected abstract void saveSortMethod(String sortMethod);
|
||||
|
||||
protected abstract void setSortMethod(String sortMethod);
|
||||
|
||||
protected abstract String loadSortOrder();
|
||||
|
||||
protected abstract void saveSortOrder(String sortOrder);
|
||||
|
||||
protected abstract void setSortOrder(String sortOrder);
|
||||
|
||||
protected int getMaxGridSizeForList() {
|
||||
if (isLandscape()) {
|
||||
return requireActivity().getResources().getInteger(R.integer.default_list_columns_land);
|
||||
}
|
||||
|
||||
return requireActivity().getResources().getInteger(R.integer.default_list_columns);
|
||||
}
|
||||
|
||||
protected final boolean isLandscape() {
|
||||
return Util.isLandscape(getResources());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
package com.dkanada.gramophone.fragments.mainactivity.library.pager;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import com.dkanada.gramophone.App;
|
||||
import com.dkanada.gramophone.databinding.FragmentMainActivityRecyclerViewBinding;
|
||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
import com.google.android.material.appbar.AppBarLayout;
|
||||
import com.google.android.material.appbar.AppBarLayout.OnOffsetChangedListener;
|
||||
import com.kabouzeid.appthemehelper.ThemeStore;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.util.ViewUtil;
|
||||
|
||||
public abstract class AbsLibraryPagerRecyclerViewFragment<A extends RecyclerView.Adapter, L extends RecyclerView.LayoutManager, Q> extends AbsLibraryPagerFragment implements OnOffsetChangedListener {
|
||||
private FragmentMainActivityRecyclerViewBinding binding;
|
||||
|
||||
private A adapter;
|
||||
private L layoutManager;
|
||||
private Q query;
|
||||
|
||||
public int size;
|
||||
public boolean loading;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentMainActivityRecyclerViewBinding.inflate(getLayoutInflater(), container, false);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
getLibraryFragment().addOnAppBarOffsetChangedListener(this);
|
||||
|
||||
initAdapter();
|
||||
initLayoutManager();
|
||||
initQuery();
|
||||
|
||||
initRecyclerView();
|
||||
loadItems(0);
|
||||
}
|
||||
|
||||
private void initAdapter() {
|
||||
adapter = createAdapter();
|
||||
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
checkIsEmpty();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initLayoutManager() {
|
||||
layoutManager = createLayoutManager();
|
||||
}
|
||||
|
||||
private void initQuery() {
|
||||
query = createQuery();
|
||||
}
|
||||
|
||||
private void initRecyclerView() {
|
||||
ViewUtil.setUpFastScrollRecyclerViewColor(getActivity(), binding.recyclerView, ThemeStore.accentColor(requireActivity()));
|
||||
|
||||
binding.recyclerView.setLayoutManager(layoutManager);
|
||||
binding.recyclerView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
protected void invalidateAdapter() {
|
||||
initAdapter();
|
||||
initQuery();
|
||||
|
||||
binding.recyclerView.setAdapter(adapter);
|
||||
loadItems(0);
|
||||
}
|
||||
|
||||
protected void invalidateLayoutManager() {
|
||||
initLayoutManager();
|
||||
binding.recyclerView.setLayoutManager(layoutManager);
|
||||
}
|
||||
|
||||
protected RecyclerView getRecyclerView() {
|
||||
return binding.recyclerView;
|
||||
}
|
||||
|
||||
protected A getAdapter() {
|
||||
return adapter;
|
||||
}
|
||||
|
||||
protected L getLayoutManager() {
|
||||
return layoutManager;
|
||||
}
|
||||
|
||||
protected Q getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
@StringRes
|
||||
protected int getEmptyMessage() {
|
||||
return R.string.empty;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected abstract A createAdapter();
|
||||
|
||||
@NonNull
|
||||
protected abstract L createLayoutManager();
|
||||
|
||||
@NonNull
|
||||
protected abstract Q createQuery();
|
||||
|
||||
protected abstract void loadItems(int index);
|
||||
|
||||
@Override
|
||||
public void onOffsetChanged(AppBarLayout appBarLayout, int i) {
|
||||
binding.container.setPadding(binding.container.getPaddingLeft(), binding.container.getPaddingTop(), binding.container.getPaddingRight(), getLibraryFragment().getTotalAppBarScrollingRange() + i);
|
||||
|
||||
int last = 0;
|
||||
if (!loading && getLayoutManager() instanceof GridLayoutManager) {
|
||||
GridLayoutManager layoutManager = (GridLayoutManager) getLayoutManager();
|
||||
last = layoutManager.findLastVisibleItemPosition();
|
||||
} else if (!loading && getLayoutManager() instanceof LinearLayoutManager) {
|
||||
LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager();
|
||||
last = layoutManager.findLastVisibleItemPosition();
|
||||
}
|
||||
|
||||
int page = PreferenceUtil.getInstance(App.getInstance()).getPageSize();
|
||||
int total = getAdapter().getItemCount();
|
||||
if (last > total - page / 2 && total < size) {
|
||||
query = createQuery();
|
||||
loading = true;
|
||||
|
||||
loadItems(getAdapter().getItemCount());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
getLibraryFragment().removeOnAppBarOffsetChangedListener(this);
|
||||
}
|
||||
|
||||
private void checkIsEmpty() {
|
||||
binding.empty.setText(getEmptyMessage());
|
||||
binding.empty.setVisibility(adapter == null || adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
package com.dkanada.gramophone.fragments.mainactivity.library.pager;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
||||
import com.dkanada.gramophone.App;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.adapter.album.AlbumAdapter;
|
||||
import com.dkanada.gramophone.model.Album;
|
||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
import com.dkanada.gramophone.util.QueryUtil;
|
||||
|
||||
import org.jellyfin.apiclient.interaction.Response;
|
||||
import org.jellyfin.apiclient.model.dto.BaseItemDto;
|
||||
import org.jellyfin.apiclient.model.querying.ItemQuery;
|
||||
import org.jellyfin.apiclient.model.querying.ItemsResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AlbumsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager, ItemQuery> {
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected GridLayoutManager createLayoutManager() {
|
||||
return new GridLayoutManager(getActivity(), getGridSize());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected AlbumAdapter createAdapter() {
|
||||
int itemLayoutRes = getItemLayoutRes();
|
||||
notifyLayoutResChanged(itemLayoutRes);
|
||||
|
||||
List<Album> dataSet = getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet();
|
||||
return new AlbumAdapter(getLibraryFragment().getMainActivity(), dataSet, itemLayoutRes, loadUsePalette(), getLibraryFragment());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ItemQuery createQuery() {
|
||||
ItemQuery query = new ItemQuery();
|
||||
|
||||
query.setIncludeItemTypes(new String[]{"MusicAlbum"});
|
||||
query.setUserId(App.getApiClient().getCurrentUserId());
|
||||
query.setRecursive(true);
|
||||
query.setLimit(PreferenceUtil.getInstance(App.getInstance()).getPageSize());
|
||||
query.setStartIndex(getAdapter().getItemCount());
|
||||
query.setParentId(QueryUtil.currentLibrary.getId());
|
||||
|
||||
QueryUtil.applySortMethod(query, PreferenceUtil.getInstance(App.getInstance()).getAlbumSortMethod());
|
||||
QueryUtil.applySortOrder(query, PreferenceUtil.getInstance(App.getInstance()).getAlbumSortOrder());
|
||||
return query;
|
||||
}
|
||||
|
||||
protected void loadItems(int index) {
|
||||
ItemQuery query = getQuery();
|
||||
query.setStartIndex(index);
|
||||
|
||||
App.getApiClient().GetItemsAsync(query, new Response<ItemsResult>() {
|
||||
@Override
|
||||
public void onResponse(ItemsResult result) {
|
||||
if (index == 0) getAdapter().getDataSet().clear();
|
||||
for (BaseItemDto itemDto : result.getItems()) {
|
||||
getAdapter().getDataSet().add(new Album(itemDto));
|
||||
}
|
||||
|
||||
size = result.getTotalRecordCount();
|
||||
getAdapter().notifyDataSetChanged();
|
||||
loading = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getEmptyMessage() {
|
||||
return R.string.no_albums;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String loadSortMethod() {
|
||||
return PreferenceUtil.getInstance(getActivity()).getAlbumSortMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveSortMethod(String sortMethod) {
|
||||
PreferenceUtil.getInstance(getActivity()).setAlbumSortMethod(sortMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setSortMethod(String sortMethod) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String loadSortOrder() {
|
||||
return PreferenceUtil.getInstance(getActivity()).getAlbumSortOrder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveSortOrder(String sortOrder) {
|
||||
PreferenceUtil.getInstance(getActivity()).setAlbumSortOrder(sortOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setSortOrder(String sortOrder) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean loadUsePalette() {
|
||||
return PreferenceUtil.getInstance(getActivity()).getAlbumColoredFooters();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUsePalette(boolean usePalette) {
|
||||
getAdapter().usePalette(usePalette);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setGridSize(int gridSize) {
|
||||
getLayoutManager().setSpanCount(gridSize);
|
||||
getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int loadGridSize() {
|
||||
return PreferenceUtil.getInstance(getActivity()).getAlbumGridSize(requireActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveGridSize(int gridSize) {
|
||||
PreferenceUtil.getInstance(getActivity()).setAlbumGridSize(gridSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int loadGridSizeLand() {
|
||||
return PreferenceUtil.getInstance(getActivity()).getAlbumGridSizeLand(requireActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveGridSizeLand(int gridSize) {
|
||||
PreferenceUtil.getInstance(getActivity()).setAlbumGridSizeLand(gridSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveUsePalette(boolean usePalette) {
|
||||
PreferenceUtil.getInstance(getActivity()).setAlbumColoredFooters(usePalette);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
package com.dkanada.gramophone.fragments.mainactivity.library.pager;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
||||
import com.dkanada.gramophone.App;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.adapter.artist.ArtistAdapter;
|
||||
import com.dkanada.gramophone.helper.sort.SortMethod;
|
||||
import com.dkanada.gramophone.helper.sort.SortOrder;
|
||||
import com.dkanada.gramophone.model.Artist;
|
||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
import com.dkanada.gramophone.util.QueryUtil;
|
||||
|
||||
import org.jellyfin.apiclient.interaction.Response;
|
||||
import org.jellyfin.apiclient.model.dto.BaseItemDto;
|
||||
import org.jellyfin.apiclient.model.querying.ArtistsQuery;
|
||||
import org.jellyfin.apiclient.model.querying.ItemFields;
|
||||
import org.jellyfin.apiclient.model.querying.ItemsResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ArtistsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager, ArtistsQuery> {
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected GridLayoutManager createLayoutManager() {
|
||||
return new GridLayoutManager(getActivity(), getGridSize());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ArtistAdapter createAdapter() {
|
||||
int itemLayoutRes = getItemLayoutRes();
|
||||
notifyLayoutResChanged(itemLayoutRes);
|
||||
|
||||
List<Artist> dataSet = getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet();
|
||||
return new ArtistAdapter(getLibraryFragment().getMainActivity(), dataSet, itemLayoutRes, loadUsePalette(), getLibraryFragment());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ArtistsQuery createQuery() {
|
||||
ArtistsQuery query = new ArtistsQuery();
|
||||
|
||||
query.setFields(new ItemFields[]{ItemFields.Genres});
|
||||
query.setUserId(App.getApiClient().getCurrentUserId());
|
||||
query.setRecursive(true);
|
||||
query.setLimit(PreferenceUtil.getInstance(App.getInstance()).getPageSize());
|
||||
query.setStartIndex(getAdapter().getItemCount());
|
||||
query.setParentId(QueryUtil.currentLibrary.getId());
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadItems(int index) {
|
||||
ArtistsQuery query = getQuery();
|
||||
query.setStartIndex(index);
|
||||
|
||||
App.getApiClient().GetAlbumArtistsAsync(query, new Response<ItemsResult>() {
|
||||
@Override
|
||||
public void onResponse(ItemsResult result) {
|
||||
if (index == 0) getAdapter().getDataSet().clear();
|
||||
for (BaseItemDto itemDto : result.getItems()) {
|
||||
getAdapter().getDataSet().add(new Artist(itemDto));
|
||||
}
|
||||
|
||||
size = result.getTotalRecordCount();
|
||||
getAdapter().notifyDataSetChanged();
|
||||
loading = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getEmptyMessage() {
|
||||
return R.string.no_artists;
|
||||
}
|
||||
|
||||
@LayoutRes
|
||||
protected int getItemLayoutRes() {
|
||||
if (getGridSize() > getMaxGridSizeForList()) {
|
||||
return R.layout.item_grid;
|
||||
}
|
||||
|
||||
return R.layout.item_list_single_row;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String loadSortMethod() {
|
||||
return SortMethod.NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveSortMethod(String sortMethod) {
|
||||
// not supported through API
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setSortMethod(String sortMethod) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String loadSortOrder() {
|
||||
return SortOrder.ASCENDING;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveSortOrder(String sortOrder) {
|
||||
// not supported through API
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setSortOrder(String sortOrder) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int loadGridSize() {
|
||||
return PreferenceUtil.getInstance(getActivity()).getArtistGridSize(requireActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveGridSize(int gridSize) {
|
||||
PreferenceUtil.getInstance(getActivity()).setArtistGridSize(gridSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int loadGridSizeLand() {
|
||||
return PreferenceUtil.getInstance(getActivity()).getArtistGridSizeLand(requireActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveGridSizeLand(int gridSize) {
|
||||
PreferenceUtil.getInstance(getActivity()).setArtistGridSizeLand(gridSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveUsePalette(boolean usePalette) {
|
||||
PreferenceUtil.getInstance(getActivity()).setArtistColoredFooters(usePalette);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean loadUsePalette() {
|
||||
return PreferenceUtil.getInstance(getActivity()).getArtistColoredFooters();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUsePalette(boolean usePalette) {
|
||||
getAdapter().usePalette(usePalette);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setGridSize(int gridSize) {
|
||||
getLayoutManager().setSpanCount(gridSize);
|
||||
getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package com.dkanada.gramophone.fragments.mainactivity.library.pager;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.dkanada.gramophone.App;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.adapter.GenreAdapter;
|
||||
import com.dkanada.gramophone.model.Genre;
|
||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
import com.dkanada.gramophone.util.QueryUtil;
|
||||
|
||||
import org.jellyfin.apiclient.interaction.Response;
|
||||
import org.jellyfin.apiclient.model.dto.BaseItemDto;
|
||||
import org.jellyfin.apiclient.model.querying.ItemsByNameQuery;
|
||||
import org.jellyfin.apiclient.model.querying.ItemsResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GenresFragment extends AbsLibraryPagerRecyclerViewFragment<GenreAdapter, LinearLayoutManager, ItemsByNameQuery> {
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected LinearLayoutManager createLayoutManager() {
|
||||
return new LinearLayoutManager(getActivity());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected GenreAdapter createAdapter() {
|
||||
List<Genre> dataSet = getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet();
|
||||
return new GenreAdapter(getLibraryFragment().getMainActivity(), dataSet, R.layout.item_list_single_row);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ItemsByNameQuery createQuery() {
|
||||
ItemsByNameQuery query = new ItemsByNameQuery();
|
||||
|
||||
query.setUserId(App.getApiClient().getCurrentUserId());
|
||||
query.setRecursive(true);
|
||||
query.setLimit(PreferenceUtil.getInstance(App.getInstance()).getPageSize());
|
||||
query.setStartIndex(getAdapter().getItemCount());
|
||||
query.setParentId(QueryUtil.currentLibrary.getId());
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadItems(int index) {
|
||||
ItemsByNameQuery query = getQuery();
|
||||
query.setStartIndex(index);
|
||||
|
||||
App.getApiClient().GetGenresAsync(query, new Response<ItemsResult>() {
|
||||
@Override
|
||||
public void onResponse(ItemsResult result) {
|
||||
if (index == 0) getAdapter().getDataSet().clear();
|
||||
for (BaseItemDto itemDto : result.getItems()) {
|
||||
getAdapter().getDataSet().add(new Genre(itemDto));
|
||||
}
|
||||
|
||||
size = result.getTotalRecordCount();
|
||||
getAdapter().notifyDataSetChanged();
|
||||
loading = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getEmptyMessage() {
|
||||
return R.string.no_genres;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
package com.dkanada.gramophone.fragments.mainactivity.library.pager;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.dkanada.gramophone.App;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.adapter.PlaylistAdapter;
|
||||
import com.dkanada.gramophone.model.Playlist;
|
||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
import com.dkanada.gramophone.util.QueryUtil;
|
||||
|
||||
import org.jellyfin.apiclient.interaction.Response;
|
||||
import org.jellyfin.apiclient.model.dto.BaseItemDto;
|
||||
import org.jellyfin.apiclient.model.querying.ItemQuery;
|
||||
import org.jellyfin.apiclient.model.querying.ItemsResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PlaylistsFragment extends AbsLibraryPagerRecyclerViewFragment<PlaylistAdapter, LinearLayoutManager, ItemQuery> {
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected LinearLayoutManager createLayoutManager() {
|
||||
return new LinearLayoutManager(getActivity());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected PlaylistAdapter createAdapter() {
|
||||
List<Playlist> dataSet = getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet();
|
||||
return new PlaylistAdapter(getLibraryFragment().getMainActivity(), dataSet, R.layout.item_list_single_row, getLibraryFragment());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ItemQuery createQuery() {
|
||||
ItemQuery query = new ItemQuery();
|
||||
|
||||
query.setIncludeItemTypes(new String[]{"Playlist"});
|
||||
query.setUserId(App.getApiClient().getCurrentUserId());
|
||||
query.setRecursive(true);
|
||||
query.setLimit(PreferenceUtil.getInstance(App.getInstance()).getPageSize());
|
||||
query.setStartIndex(getAdapter().getItemCount());
|
||||
query.setParentId(QueryUtil.currentLibrary.getId());
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadItems(int index) {
|
||||
ItemQuery query = getQuery();
|
||||
query.setStartIndex(index);
|
||||
|
||||
App.getApiClient().GetItemsAsync(query, new Response<ItemsResult>() {
|
||||
@Override
|
||||
public void onResponse(ItemsResult result) {
|
||||
if (index == 0) getAdapter().getDataSet().clear();
|
||||
for (BaseItemDto itemDto : result.getItems()) {
|
||||
getAdapter().getDataSet().add(new Playlist(itemDto));
|
||||
}
|
||||
|
||||
size = result.getTotalRecordCount();
|
||||
getAdapter().notifyDataSetChanged();
|
||||
loading = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getEmptyMessage() {
|
||||
return R.string.no_playlists;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
package com.dkanada.gramophone.fragments.mainactivity.library.pager;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
||||
import com.dkanada.gramophone.App;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.adapter.song.ShuffleButtonSongAdapter;
|
||||
import com.dkanada.gramophone.adapter.song.SongAdapter;
|
||||
import com.dkanada.gramophone.model.Song;
|
||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
import com.dkanada.gramophone.util.QueryUtil;
|
||||
|
||||
import org.jellyfin.apiclient.interaction.Response;
|
||||
import org.jellyfin.apiclient.model.dto.BaseItemDto;
|
||||
import org.jellyfin.apiclient.model.querying.ItemFields;
|
||||
import org.jellyfin.apiclient.model.querying.ItemQuery;
|
||||
import org.jellyfin.apiclient.model.querying.ItemsResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SongsFragment extends AbsLibraryPagerRecyclerViewCustomGridSizeFragment<SongAdapter, GridLayoutManager, ItemQuery> {
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected GridLayoutManager createLayoutManager() {
|
||||
return new GridLayoutManager(getActivity(), getGridSize());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected SongAdapter createAdapter() {
|
||||
int itemLayoutRes = getItemLayoutRes();
|
||||
notifyLayoutResChanged(itemLayoutRes);
|
||||
boolean usePalette = loadUsePalette();
|
||||
|
||||
List<Song> dataSet = getAdapter() == null ? new ArrayList<>() : getAdapter().getDataSet();
|
||||
SongAdapter adapter;
|
||||
|
||||
if (getGridSize() <= getMaxGridSizeForList()) {
|
||||
adapter = new ShuffleButtonSongAdapter(
|
||||
getLibraryFragment().getMainActivity(),
|
||||
dataSet,
|
||||
itemLayoutRes,
|
||||
usePalette,
|
||||
getLibraryFragment());
|
||||
} else {
|
||||
adapter = new SongAdapter(
|
||||
getLibraryFragment().getMainActivity(),
|
||||
dataSet,
|
||||
itemLayoutRes,
|
||||
usePalette,
|
||||
getLibraryFragment());
|
||||
}
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected ItemQuery createQuery() {
|
||||
ItemQuery query = new ItemQuery();
|
||||
|
||||
query.setIncludeItemTypes(new String[]{"Audio"});
|
||||
query.setFields(new ItemFields[]{ItemFields.MediaSources});
|
||||
query.setUserId(App.getApiClient().getCurrentUserId());
|
||||
query.setRecursive(true);
|
||||
query.setLimit(PreferenceUtil.getInstance(App.getInstance()).getPageSize());
|
||||
query.setStartIndex(getAdapter().getItemCount());
|
||||
query.setParentId(QueryUtil.currentLibrary.getId());
|
||||
|
||||
QueryUtil.applySortMethod(query, PreferenceUtil.getInstance(App.getInstance()).getSongSortMethod());
|
||||
QueryUtil.applySortOrder(query, PreferenceUtil.getInstance(App.getInstance()).getSongSortOrder());
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadItems(int index) {
|
||||
ItemQuery query = getQuery();
|
||||
query.setStartIndex(index);
|
||||
|
||||
App.getApiClient().GetItemsAsync(query, new Response<ItemsResult>() {
|
||||
@Override
|
||||
public void onResponse(ItemsResult result) {
|
||||
if (index == 0) getAdapter().getDataSet().clear();
|
||||
for (BaseItemDto itemDto : result.getItems()) {
|
||||
getAdapter().getDataSet().add(new Song(itemDto));
|
||||
}
|
||||
|
||||
size = result.getTotalRecordCount();
|
||||
getAdapter().notifyDataSetChanged();
|
||||
loading = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getEmptyMessage() {
|
||||
return R.string.no_songs;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String loadSortMethod() {
|
||||
return PreferenceUtil.getInstance(getActivity()).getSongSortMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveSortMethod(String sortMethod) {
|
||||
PreferenceUtil.getInstance(getActivity()).setSongSortMethod(sortMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setSortMethod(String sortMethod) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String loadSortOrder() {
|
||||
return PreferenceUtil.getInstance(getActivity()).getSongSortOrder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveSortOrder(String sortOrder) {
|
||||
PreferenceUtil.getInstance(getActivity()).setSongSortOrder(sortOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setSortOrder(String sortOrder) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int loadGridSize() {
|
||||
return PreferenceUtil.getInstance(getActivity()).getSongGridSize(requireActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveGridSize(int gridSize) {
|
||||
PreferenceUtil.getInstance(getActivity()).setSongGridSize(gridSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int loadGridSizeLand() {
|
||||
return PreferenceUtil.getInstance(getActivity()).getSongGridSizeLand(requireActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveGridSizeLand(int gridSize) {
|
||||
PreferenceUtil.getInstance(getActivity()).setSongGridSizeLand(gridSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveUsePalette(boolean usePalette) {
|
||||
PreferenceUtil.getInstance(getActivity()).setSongColoredFooters(usePalette);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean loadUsePalette() {
|
||||
return PreferenceUtil.getInstance(getActivity()).getSongColoredFooters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsePalette(boolean usePalette) {
|
||||
getAdapter().usePalette(usePalette);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setGridSize(int gridSize) {
|
||||
getLayoutManager().setSpanCount(gridSize);
|
||||
getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
package com.dkanada.gramophone.fragments.player;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.dialogs.AddToPlaylistDialog;
|
||||
import com.dkanada.gramophone.dialogs.CreatePlaylistDialog;
|
||||
import com.dkanada.gramophone.dialogs.SleepTimerDialog;
|
||||
import com.dkanada.gramophone.dialogs.SongDetailDialog;
|
||||
import com.dkanada.gramophone.dialogs.SongShareDialog;
|
||||
import com.dkanada.gramophone.helper.MusicPlayerRemote;
|
||||
import com.dkanada.gramophone.interfaces.PaletteColorHolder;
|
||||
import com.dkanada.gramophone.model.Album;
|
||||
import com.dkanada.gramophone.model.Artist;
|
||||
import com.dkanada.gramophone.model.Song;
|
||||
import com.dkanada.gramophone.fragments.AbsMusicServiceFragment;
|
||||
import com.dkanada.gramophone.util.MusicUtil;
|
||||
import com.dkanada.gramophone.util.NavigationUtil;
|
||||
|
||||
public abstract class AbsPlayerFragment extends AbsMusicServiceFragment implements Toolbar.OnMenuItemClickListener, PaletteColorHolder {
|
||||
private static boolean isToolbarShown = true;
|
||||
|
||||
private Callbacks callbacks;
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
try {
|
||||
callbacks = (Callbacks) context;
|
||||
} catch (ClassCastException e) {
|
||||
throw new RuntimeException(context.getClass().getSimpleName() + " must implement " + Callbacks.class.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
callbacks = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
final Song song = MusicPlayerRemote.getCurrentSong();
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_sleep_timer:
|
||||
new SleepTimerDialog().show(getParentFragmentManager(), "SET_SLEEP_TIMER");
|
||||
return true;
|
||||
case R.id.action_toggle_favorite:
|
||||
toggleFavorite(song);
|
||||
return true;
|
||||
case R.id.action_share:
|
||||
SongShareDialog.create(song).show(getParentFragmentManager(), "SHARE_SONG");
|
||||
return true;
|
||||
case R.id.action_add_to_playlist:
|
||||
AddToPlaylistDialog.create(song).show(getParentFragmentManager(), "ADD_PLAYLIST");
|
||||
return true;
|
||||
case R.id.action_clear_queue:
|
||||
MusicPlayerRemote.clearQueue();
|
||||
return true;
|
||||
case R.id.action_save_queue:
|
||||
CreatePlaylistDialog.create(MusicPlayerRemote.getPlayingQueue()).show(getParentFragmentManager(), "ADD_TO_PLAYLIST");
|
||||
return true;
|
||||
case R.id.action_details:
|
||||
SongDetailDialog.create(song).show(getParentFragmentManager(), "SONG_DETAIL");
|
||||
return true;
|
||||
case R.id.action_go_to_album:
|
||||
NavigationUtil.goToAlbum(requireActivity(), new Album(song));
|
||||
return true;
|
||||
case R.id.action_go_to_artist:
|
||||
NavigationUtil.goToArtist(requireActivity(), new Artist(song));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void toggleFavorite(Song song) {
|
||||
MusicUtil.toggleFavorite(requireActivity(), song);
|
||||
}
|
||||
|
||||
protected boolean isToolbarShown() {
|
||||
return isToolbarShown;
|
||||
}
|
||||
|
||||
protected void setToolbarShown(boolean toolbarShown) {
|
||||
isToolbarShown = toolbarShown;
|
||||
}
|
||||
|
||||
protected void showToolbar(@Nullable final View toolbar) {
|
||||
if (toolbar == null) return;
|
||||
|
||||
setToolbarShown(true);
|
||||
|
||||
toolbar.setVisibility(View.VISIBLE);
|
||||
toolbar.animate().alpha(1f).setDuration(PlayerAlbumCoverFragment.VISIBILITY_ANIM_DURATION);
|
||||
}
|
||||
|
||||
protected void hideToolbar(@Nullable final View toolbar) {
|
||||
if (toolbar == null) return;
|
||||
|
||||
setToolbarShown(false);
|
||||
|
||||
toolbar.animate().alpha(0f).setDuration(PlayerAlbumCoverFragment.VISIBILITY_ANIM_DURATION).withEndAction(() -> toolbar.setVisibility(View.GONE));
|
||||
}
|
||||
|
||||
protected void toggleToolbar(@Nullable final View toolbar) {
|
||||
if (isToolbarShown()) {
|
||||
hideToolbar(toolbar);
|
||||
} else {
|
||||
showToolbar(toolbar);
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkToggleToolbar(@Nullable final View toolbar) {
|
||||
if (toolbar != null && !isToolbarShown() && toolbar.getVisibility() != View.GONE) {
|
||||
hideToolbar(toolbar);
|
||||
} else if (toolbar != null && isToolbarShown() && toolbar.getVisibility() != View.VISIBLE) {
|
||||
showToolbar(toolbar);
|
||||
}
|
||||
}
|
||||
|
||||
protected String getUpNextAndQueueTime() {
|
||||
final long duration = MusicPlayerRemote.getQueueDurationMillis(MusicPlayerRemote.getPosition());
|
||||
|
||||
return MusicUtil.buildInfoString(
|
||||
getResources().getString(R.string.up_next),
|
||||
MusicUtil.getReadableDurationString(duration)
|
||||
);
|
||||
}
|
||||
|
||||
public abstract void onShow();
|
||||
|
||||
public abstract void onHide();
|
||||
|
||||
public abstract boolean onBackPressed();
|
||||
|
||||
public Callbacks getCallbacks() {
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
public interface Callbacks {
|
||||
void onPaletteColorChanged();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
package com.dkanada.gramophone.fragments.player;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.Bundle;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.dkanada.gramophone.databinding.FragmentMiniPlayerBinding;
|
||||
import com.kabouzeid.appthemehelper.ThemeStore;
|
||||
import com.kabouzeid.appthemehelper.util.ATHUtil;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.helper.MusicPlayerRemote;
|
||||
import com.dkanada.gramophone.helper.MusicProgressViewUpdateHelper;
|
||||
import com.dkanada.gramophone.helper.PlayPauseButtonOnClickHandler;
|
||||
import com.dkanada.gramophone.fragments.AbsMusicServiceFragment;
|
||||
import com.dkanada.gramophone.views.PlayPauseDrawable;
|
||||
|
||||
public class MiniPlayerFragment extends AbsMusicServiceFragment implements MusicProgressViewUpdateHelper.Callback {
|
||||
private FragmentMiniPlayerBinding binding;
|
||||
|
||||
private PlayPauseDrawable miniPlayerPlayPauseDrawable;
|
||||
|
||||
private MusicProgressViewUpdateHelper progressViewUpdateHelper;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentMiniPlayerBinding.inflate(inflater);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
view.setOnTouchListener(new FlingPlayBackController(getActivity()));
|
||||
setUpMiniPlayer();
|
||||
}
|
||||
|
||||
private void setUpMiniPlayer() {
|
||||
setUpPlayPauseButton();
|
||||
binding.progressBar.setProgressTintList(ColorStateList.valueOf(ThemeStore.accentColor(requireActivity())));
|
||||
}
|
||||
|
||||
private void setUpPlayPauseButton() {
|
||||
miniPlayerPlayPauseDrawable = new PlayPauseDrawable(requireActivity());
|
||||
binding.miniPlayerPlayPauseButton.setImageDrawable(miniPlayerPlayPauseDrawable);
|
||||
binding.miniPlayerPlayPauseButton.setColorFilter(ATHUtil.resolveColor(requireActivity(), R.attr.iconColor, ThemeStore.textColorSecondary(requireActivity())), PorterDuff.Mode.SRC_IN);
|
||||
binding.miniPlayerPlayPauseButton.setOnClickListener(new PlayPauseButtonOnClickHandler());
|
||||
}
|
||||
|
||||
private void updateSongTitle() {
|
||||
binding.miniPlayerTitle.setText(MusicPlayerRemote.getCurrentSong().title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
updateSongTitle();
|
||||
updatePlayPauseDrawableState(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayMetadataChanged() {
|
||||
updateSongTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayStateChanged() {
|
||||
updatePlayPauseDrawableState(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateProgressViews(int progress, int total) {
|
||||
binding.progressBar.setMax(total);
|
||||
binding.progressBar.setProgress(progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
progressViewUpdateHelper.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
progressViewUpdateHelper.stop();
|
||||
}
|
||||
|
||||
private static class FlingPlayBackController implements View.OnTouchListener {
|
||||
GestureDetector flingPlayBackController;
|
||||
|
||||
public FlingPlayBackController(Context context) {
|
||||
flingPlayBackController = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override
|
||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
if (Math.abs(velocityX) > Math.abs(velocityY)) {
|
||||
if (velocityX < 0) {
|
||||
MusicPlayerRemote.playNextSong();
|
||||
return true;
|
||||
} else if (velocityX > 0) {
|
||||
MusicPlayerRemote.playPreviousSong();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
return flingPlayBackController.onTouchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updatePlayPauseDrawableState(boolean animate) {
|
||||
if (MusicPlayerRemote.isPlaying()) {
|
||||
miniPlayerPlayPauseDrawable.setPause(animate);
|
||||
} else {
|
||||
miniPlayerPlayPauseDrawable.setPlay(animate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.dkanada.gramophone.fragments.player;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import com.dkanada.gramophone.R;
|
||||
|
||||
public enum NowPlayingScreen {
|
||||
CARD(R.string.card, R.drawable.np_card, 0),
|
||||
FLAT(R.string.flat, R.drawable.np_flat, 1);
|
||||
|
||||
@StringRes
|
||||
public final int titleRes;
|
||||
|
||||
@DrawableRes
|
||||
public final int drawableRes;
|
||||
|
||||
public final int id;
|
||||
|
||||
NowPlayingScreen(@StringRes int titleRes, @DrawableRes int drawableRes, int id) {
|
||||
this.titleRes = titleRes;
|
||||
this.drawableRes = drawableRes;
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
package com.dkanada.gramophone.fragments.player;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Bundle;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.dkanada.gramophone.adapter.AlbumCoverPagerAdapter;
|
||||
import com.dkanada.gramophone.databinding.FragmentPlayerAlbumCoverBinding;
|
||||
import com.dkanada.gramophone.helper.MusicPlayerRemote;
|
||||
import com.dkanada.gramophone.misc.SimpleAnimatorListener;
|
||||
import com.dkanada.gramophone.fragments.AbsMusicServiceFragment;
|
||||
import com.dkanada.gramophone.util.ViewUtil;
|
||||
|
||||
public class PlayerAlbumCoverFragment extends AbsMusicServiceFragment implements ViewPager.OnPageChangeListener {
|
||||
|
||||
public static final int VISIBILITY_ANIM_DURATION = 300;
|
||||
|
||||
private FragmentPlayerAlbumCoverBinding binding;
|
||||
|
||||
private Callbacks callbacks;
|
||||
private int currentPosition;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentPlayerAlbumCoverBinding.inflate(inflater);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
binding.playerAlbumCoverViewPager.addOnPageChangeListener(this);
|
||||
binding.playerAlbumCoverViewPager.setOnTouchListener(new View.OnTouchListener() {
|
||||
GestureDetector gestureDetector = new GestureDetector(getActivity(), new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override
|
||||
public boolean onSingleTapConfirmed(MotionEvent e) {
|
||||
if (callbacks != null) {
|
||||
callbacks.onToolbarToggled();
|
||||
return true;
|
||||
}
|
||||
return super.onSingleTapConfirmed(e);
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
return gestureDetector.onTouchEvent(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
binding.playerAlbumCoverViewPager.removeOnPageChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
updatePlayingQueue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayMetadataChanged() {
|
||||
binding.playerAlbumCoverViewPager.setCurrentItem(MusicPlayerRemote.getPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueueChanged() {
|
||||
updatePlayingQueue();
|
||||
}
|
||||
|
||||
private void updatePlayingQueue() {
|
||||
binding.playerAlbumCoverViewPager.setAdapter(new AlbumCoverPagerAdapter(getFragmentManager(), MusicPlayerRemote.getPlayingQueue()));
|
||||
binding.playerAlbumCoverViewPager.setCurrentItem(MusicPlayerRemote.getPosition());
|
||||
onPageSelected(MusicPlayerRemote.getPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
currentPosition = position;
|
||||
((AlbumCoverPagerAdapter) binding.playerAlbumCoverViewPager.getAdapter()).receiveColor(colorReceiver, position);
|
||||
if (position != MusicPlayerRemote.getPosition()) {
|
||||
MusicPlayerRemote.playSongAt(position);
|
||||
}
|
||||
}
|
||||
|
||||
private AlbumCoverPagerAdapter.AlbumCoverFragment.ColorReceiver colorReceiver = new AlbumCoverPagerAdapter.AlbumCoverFragment.ColorReceiver() {
|
||||
@Override
|
||||
public void onColorReady(int color, int requestCode) {
|
||||
if (currentPosition == requestCode) {
|
||||
notifyColorChange(color);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
|
||||
public void showHeartAnimation() {
|
||||
binding.playerFavoriteIcon.clearAnimation();
|
||||
|
||||
binding.playerFavoriteIcon.setAlpha(0f);
|
||||
binding.playerFavoriteIcon.setScaleX(0f);
|
||||
binding.playerFavoriteIcon.setScaleY(0f);
|
||||
binding.playerFavoriteIcon.setVisibility(View.VISIBLE);
|
||||
binding.playerFavoriteIcon.setPivotX(binding.playerFavoriteIcon.getWidth() / 2);
|
||||
binding.playerFavoriteIcon.setPivotY(binding.playerFavoriteIcon.getHeight() / 2);
|
||||
|
||||
binding.playerFavoriteIcon.animate()
|
||||
.setDuration(ViewUtil.PHONOGRAPH_ANIM_TIME / 2)
|
||||
.setInterpolator(new DecelerateInterpolator())
|
||||
.scaleX(1f)
|
||||
.scaleY(1f)
|
||||
.alpha(1f)
|
||||
.setListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
binding.playerFavoriteIcon.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
})
|
||||
.withEndAction(() -> binding.playerFavoriteIcon.animate()
|
||||
.setDuration(ViewUtil.PHONOGRAPH_ANIM_TIME / 2)
|
||||
.setInterpolator(new AccelerateInterpolator())
|
||||
.scaleX(0f)
|
||||
.scaleY(0f)
|
||||
.alpha(0f)
|
||||
.start())
|
||||
.start();
|
||||
}
|
||||
|
||||
private void notifyColorChange(int color) {
|
||||
if (callbacks != null) callbacks.onColorChanged(color);
|
||||
}
|
||||
|
||||
public void setCallbacks(Callbacks listener) {
|
||||
callbacks = listener;
|
||||
}
|
||||
|
||||
public interface Callbacks {
|
||||
void onColorChanged(int color);
|
||||
|
||||
void onFavoriteToggled();
|
||||
|
||||
void onToolbarToggled();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,497 @@
|
|||
package com.dkanada.gramophone.fragments.player.card;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewAnimationUtils;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.dkanada.gramophone.databinding.FragmentCardPlayerBinding;
|
||||
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.kabouzeid.appthemehelper.ThemeStore;
|
||||
import com.kabouzeid.appthemehelper.util.ATHUtil;
|
||||
import com.kabouzeid.appthemehelper.util.ColorUtil;
|
||||
import com.kabouzeid.appthemehelper.util.ToolbarContentTintHelper;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.adapter.base.MediaEntryViewHolder;
|
||||
import com.dkanada.gramophone.adapter.song.PlayingQueueAdapter;
|
||||
import com.dkanada.gramophone.dialogs.SongShareDialog;
|
||||
import com.dkanada.gramophone.helper.MusicPlayerRemote;
|
||||
import com.dkanada.gramophone.helper.menu.SongMenuHelper;
|
||||
import com.dkanada.gramophone.model.Song;
|
||||
import com.dkanada.gramophone.activities.base.AbsSlidingMusicPanelActivity;
|
||||
import com.dkanada.gramophone.fragments.player.AbsPlayerFragment;
|
||||
import com.dkanada.gramophone.fragments.player.PlayerAlbumCoverFragment;
|
||||
import com.dkanada.gramophone.util.ImageUtil;
|
||||
import com.dkanada.gramophone.util.MusicUtil;
|
||||
import com.dkanada.gramophone.util.Util;
|
||||
import com.dkanada.gramophone.util.ViewUtil;
|
||||
import com.dkanada.gramophone.views.WidthFitSquareLayout;
|
||||
import com.sothree.slidinguppanel.SlidingUpPanelLayout;
|
||||
|
||||
public class CardPlayerFragment extends AbsPlayerFragment implements PlayerAlbumCoverFragment.Callbacks, SlidingUpPanelLayout.PanelSlideListener {
|
||||
private FragmentCardPlayerBinding binding;
|
||||
|
||||
private int lastColor;
|
||||
|
||||
private CardPlayerPlaybackControlsFragment playbackControlsFragment;
|
||||
private PlayerAlbumCoverFragment playerAlbumCoverFragment;
|
||||
|
||||
private LinearLayoutManager layoutManager;
|
||||
|
||||
private PlayingQueueAdapter playingQueueAdapter;
|
||||
|
||||
private RecyclerView.Adapter wrappedAdapter;
|
||||
private RecyclerViewDragDropManager recyclerViewDragDropManager;
|
||||
|
||||
private Impl impl;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentCardPlayerBinding.inflate(inflater);
|
||||
|
||||
if (Util.isLandscape(getResources())) {
|
||||
impl = new LandscapeImpl(this, binding);
|
||||
} else {
|
||||
impl = new PortraitImpl(this, binding);
|
||||
}
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
impl.init();
|
||||
|
||||
setUpPlayerToolbar();
|
||||
setUpSubFragments();
|
||||
|
||||
setUpRecyclerView();
|
||||
|
||||
binding.playerSlidingLayout.addPanelSlideListener(this);
|
||||
binding.playerSlidingLayout.setAntiDragView(view.findViewById(R.id.draggable_area));
|
||||
|
||||
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
impl.setUpPanelAndAlbumCoverHeight();
|
||||
}
|
||||
});
|
||||
|
||||
// for some reason the xml attribute doesn't get applied here.
|
||||
binding.playingQueueCard.setCardBackgroundColor(ATHUtil.resolveColor(getActivity(), R.attr.cardBackgroundColor));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
binding.playerSlidingLayout.removePanelSlideListener(this);
|
||||
|
||||
if (recyclerViewDragDropManager != null) {
|
||||
recyclerViewDragDropManager.release();
|
||||
recyclerViewDragDropManager = null;
|
||||
}
|
||||
|
||||
binding.playerRecyclerView.setItemAnimator(null);
|
||||
binding.playerRecyclerView.setAdapter(null);
|
||||
|
||||
if (wrappedAdapter != null) {
|
||||
WrapperAdapterUtils.releaseAll(wrappedAdapter);
|
||||
wrappedAdapter = null;
|
||||
}
|
||||
|
||||
playingQueueAdapter = null;
|
||||
layoutManager = null;
|
||||
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
if (recyclerViewDragDropManager != null) {
|
||||
recyclerViewDragDropManager.cancelDrag();
|
||||
}
|
||||
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
checkToggleToolbar(binding.toolbarContainer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
updateQueue();
|
||||
updateCurrentSong();
|
||||
updateIsFavorite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayMetadataChanged() {
|
||||
updateCurrentSong();
|
||||
updateIsFavorite();
|
||||
updateQueuePosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueueChanged() {
|
||||
updateQueue();
|
||||
}
|
||||
|
||||
private void updateQueue() {
|
||||
playingQueueAdapter.swapDataSet(MusicPlayerRemote.getPlayingQueue(), MusicPlayerRemote.getPosition());
|
||||
binding.playerQueueSubHeader.setText(getUpNextAndQueueTime());
|
||||
if (binding.playerSlidingLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
|
||||
resetToCurrentPosition();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateQueuePosition() {
|
||||
playingQueueAdapter.setCurrent(MusicPlayerRemote.getPosition());
|
||||
binding.playerQueueSubHeader.setText(getUpNextAndQueueTime());
|
||||
if (binding.playerSlidingLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
|
||||
resetToCurrentPosition();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCurrentSong() {
|
||||
impl.updateCurrentSong(MusicPlayerRemote.getCurrentSong());
|
||||
}
|
||||
|
||||
private void setUpSubFragments() {
|
||||
playbackControlsFragment = (CardPlayerPlaybackControlsFragment) getChildFragmentManager().findFragmentById(R.id.playback_controls_fragment);
|
||||
playerAlbumCoverFragment = (PlayerAlbumCoverFragment) getChildFragmentManager().findFragmentById(R.id.player_album_cover_fragment);
|
||||
|
||||
playerAlbumCoverFragment.setCallbacks(this);
|
||||
}
|
||||
|
||||
private void setUpPlayerToolbar() {
|
||||
binding.playerToolbar.inflateMenu(R.menu.menu_player);
|
||||
binding.playerToolbar.setNavigationIcon(R.drawable.ic_close_white_24dp);
|
||||
binding.playerToolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed());
|
||||
binding.playerToolbar.setOnMenuItemClickListener(this);
|
||||
}
|
||||
|
||||
private void setUpRecyclerView() {
|
||||
recyclerViewDragDropManager = new RecyclerViewDragDropManager();
|
||||
final GeneralItemAnimator animator = new RefactoredDefaultItemAnimator();
|
||||
|
||||
playingQueueAdapter = new PlayingQueueAdapter(
|
||||
((AppCompatActivity) getActivity()),
|
||||
MusicPlayerRemote.getPlayingQueue(),
|
||||
MusicPlayerRemote.getPosition(),
|
||||
R.layout.item_list,
|
||||
false,
|
||||
null);
|
||||
wrappedAdapter = recyclerViewDragDropManager.createWrappedAdapter(playingQueueAdapter);
|
||||
|
||||
layoutManager = new LinearLayoutManager(getActivity());
|
||||
|
||||
binding.playerRecyclerView.setLayoutManager(layoutManager);
|
||||
binding.playerRecyclerView.setAdapter(wrappedAdapter);
|
||||
binding.playerRecyclerView.setItemAnimator(animator);
|
||||
|
||||
recyclerViewDragDropManager.attachRecyclerView(binding.playerRecyclerView);
|
||||
|
||||
layoutManager.scrollToPositionWithOffset(MusicPlayerRemote.getPosition() + 1, 0);
|
||||
}
|
||||
|
||||
private void updateIsFavorite() {
|
||||
boolean favorite = MusicPlayerRemote.getCurrentSong().favorite;
|
||||
int res = favorite ? R.drawable.ic_favorite_white_24dp : R.drawable.ic_favorite_border_white_24dp;
|
||||
int color = ToolbarContentTintHelper.toolbarContentColor(getActivity(), Color.TRANSPARENT);
|
||||
Drawable drawable = ImageUtil.getTintedVectorDrawable(getActivity(), res, color);
|
||||
binding.playerToolbar.getMenu().findItem(R.id.action_toggle_favorite)
|
||||
.setIcon(drawable)
|
||||
.setTitle(favorite ? getString(R.string.action_remove_from_favorites) : getString(R.string.action_add_to_favorites));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ColorInt
|
||||
public int getPaletteColor() {
|
||||
return lastColor;
|
||||
}
|
||||
|
||||
private void animateColorChange(final int newColor) {
|
||||
impl.animateColorChange(newColor);
|
||||
lastColor = newColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toggleFavorite(Song song) {
|
||||
super.toggleFavorite(song);
|
||||
if (song.id.equals(MusicPlayerRemote.getCurrentSong().id)) {
|
||||
if (song.favorite) {
|
||||
playerAlbumCoverFragment.showHeartAnimation();
|
||||
}
|
||||
|
||||
updateIsFavorite();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShow() {
|
||||
playbackControlsFragment.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHide() {
|
||||
playbackControlsFragment.hide();
|
||||
onBackPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBackPressed() {
|
||||
boolean wasExpanded = binding.playerSlidingLayout.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED;
|
||||
binding.playerSlidingLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
|
||||
|
||||
return wasExpanded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onColorChanged(int color) {
|
||||
animateColorChange(color);
|
||||
playbackControlsFragment.setDark(ColorUtil.isColorLight(color));
|
||||
getCallbacks().onPaletteColorChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFavoriteToggled() {
|
||||
toggleFavorite(MusicPlayerRemote.getCurrentSong());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onToolbarToggled() {
|
||||
toggleToolbar(binding.toolbarContainer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelSlide(View view, float slide) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
float density = getResources().getDisplayMetrics().density;
|
||||
binding.playingQueueCard.setCardElevation((6 * slide + 2) * density);
|
||||
playbackControlsFragment.binding.playerPlayPauseFab.setElevation((2 * Math.max(0, (1 - (slide * 16))) + 2) * density);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelStateChanged(View panel, SlidingUpPanelLayout.PanelState previousState, SlidingUpPanelLayout.PanelState newState) {
|
||||
switch (newState) {
|
||||
case COLLAPSED:
|
||||
onPanelCollapsed(panel);
|
||||
break;
|
||||
case ANCHORED:
|
||||
binding.playerSlidingLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); // this fixes a bug where the panel would get stuck for some reason
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void onPanelCollapsed(View panel) {
|
||||
resetToCurrentPosition();
|
||||
}
|
||||
|
||||
private void resetToCurrentPosition() {
|
||||
binding.playerRecyclerView.stopScroll();
|
||||
layoutManager.scrollToPositionWithOffset(MusicPlayerRemote.getPosition() + 1, 0);
|
||||
}
|
||||
|
||||
interface Impl {
|
||||
void init();
|
||||
|
||||
void updateCurrentSong(Song song);
|
||||
|
||||
void animateColorChange(final int newColor);
|
||||
|
||||
void setUpPanelAndAlbumCoverHeight();
|
||||
}
|
||||
|
||||
private static abstract class BaseImpl implements Impl {
|
||||
protected CardPlayerFragment fragment;
|
||||
protected FragmentCardPlayerBinding binding;
|
||||
|
||||
public BaseImpl(CardPlayerFragment fragment, FragmentCardPlayerBinding binding) {
|
||||
this.fragment = fragment;
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public AnimatorSet createDefaultColorChangeAnimatorSet(int newColor) {
|
||||
Animator backgroundAnimator;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
// noinspection ConstantConditions
|
||||
int x = (int) (fragment.playbackControlsFragment.binding.playerPlayPauseFab.getX() + fragment.playbackControlsFragment.binding.playerPlayPauseFab.getWidth() / 2 + fragment.playbackControlsFragment.getView().getX());
|
||||
int y = (int) (fragment.playbackControlsFragment.binding.playerPlayPauseFab.getY() + fragment.playbackControlsFragment.binding.playerPlayPauseFab.getHeight() / 2 + fragment.playbackControlsFragment.getView().getY() + fragment.playbackControlsFragment.binding.playerProgressSlider.getHeight());
|
||||
float startRadius = Math.max(fragment.playbackControlsFragment.binding.playerPlayPauseFab.getWidth() / 2, fragment.playbackControlsFragment.binding.playerPlayPauseFab.getHeight() / 2);
|
||||
float endRadius = Math.max(binding.colorBackground.getWidth(), binding.colorBackground.getHeight());
|
||||
binding.colorBackground.setBackgroundColor(newColor);
|
||||
backgroundAnimator = ViewAnimationUtils.createCircularReveal(binding.colorBackground, x, y, startRadius, endRadius);
|
||||
} else {
|
||||
backgroundAnimator = ViewUtil.createBackgroundColorTransition(binding.colorBackground, fragment.lastColor, newColor);
|
||||
}
|
||||
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
|
||||
animatorSet.play(backgroundAnimator);
|
||||
|
||||
if (!ATHUtil.isWindowBackgroundDark(fragment.getActivity())) {
|
||||
int adjustedLastColor = ColorUtil.isColorLight(fragment.lastColor) ? ColorUtil.darkenColor(fragment.lastColor) : fragment.lastColor;
|
||||
int adjustedNewColor = ColorUtil.isColorLight(newColor) ? ColorUtil.darkenColor(newColor) : newColor;
|
||||
Animator subHeaderAnimator = ViewUtil.createTextColorTransition(binding.playerQueueSubHeader, adjustedLastColor, adjustedNewColor);
|
||||
animatorSet.play(subHeaderAnimator);
|
||||
}
|
||||
|
||||
animatorSet.setDuration(ViewUtil.PHONOGRAPH_ANIM_TIME);
|
||||
return animatorSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void animateColorChange(int newColor) {
|
||||
if (ATHUtil.isWindowBackgroundDark(fragment.getActivity())) {
|
||||
binding.playerQueueSubHeader.setTextColor(ThemeStore.textColorSecondary(fragment.getActivity()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private static class PortraitImpl extends BaseImpl {
|
||||
MediaEntryViewHolder currentSongViewHolder;
|
||||
Song currentSong = Song.EMPTY;
|
||||
|
||||
public PortraitImpl(CardPlayerFragment fragment, FragmentCardPlayerBinding binding) {
|
||||
super(fragment, binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
currentSongViewHolder = new MediaEntryViewHolder(fragment.getView().findViewById(R.id.current_song));
|
||||
|
||||
currentSongViewHolder.separator.setVisibility(View.VISIBLE);
|
||||
currentSongViewHolder.shortSeparator.setVisibility(View.GONE);
|
||||
currentSongViewHolder.image.setScaleType(ImageView.ScaleType.CENTER);
|
||||
currentSongViewHolder.image.setColorFilter(ATHUtil.resolveColor(fragment.getActivity(), R.attr.iconColor, ThemeStore.textColorSecondary(fragment.getActivity())), PorterDuff.Mode.SRC_IN);
|
||||
currentSongViewHolder.image.setImageResource(R.drawable.ic_volume_up_white_24dp);
|
||||
currentSongViewHolder.itemView.setOnClickListener(v -> {
|
||||
// toggle the panel
|
||||
if (binding.playerSlidingLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
|
||||
binding.playerSlidingLayout.setPanelState(SlidingUpPanelLayout.PanelState.EXPANDED);
|
||||
} else if (binding.playerSlidingLayout.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) {
|
||||
binding.playerSlidingLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
|
||||
}
|
||||
});
|
||||
|
||||
currentSongViewHolder.menu.setOnClickListener(new SongMenuHelper.OnClickSongMenu((AppCompatActivity) fragment.getActivity()) {
|
||||
@Override
|
||||
public Song getSong() {
|
||||
return currentSong;
|
||||
}
|
||||
|
||||
public int getMenuRes() {
|
||||
return R.menu.menu_item_playing_queue_song;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_remove_from_queue:
|
||||
MusicPlayerRemote.removeFromQueue(MusicPlayerRemote.getPosition());
|
||||
return true;
|
||||
case R.id.action_share:
|
||||
SongShareDialog.create(getSong()).show(fragment.getFragmentManager(), "SONG_SHARE_DIALOG");
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onMenuItemClick(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUpPanelAndAlbumCoverHeight() {
|
||||
WidthFitSquareLayout albumCoverContainer = fragment.getView().findViewById(R.id.album_cover_container);
|
||||
|
||||
final int availablePanelHeight = binding.playerSlidingLayout.getHeight() - fragment.getView().findViewById(R.id.player_content).getHeight() + (int) ViewUtil.convertDpToPixel(8, fragment.getResources());
|
||||
final int minPanelHeight = (int) ViewUtil.convertDpToPixel(72 + 24, fragment.getResources());
|
||||
if (availablePanelHeight < minPanelHeight) {
|
||||
albumCoverContainer.getLayoutParams().height = albumCoverContainer.getHeight() - (minPanelHeight - availablePanelHeight);
|
||||
albumCoverContainer.forceSquare(false);
|
||||
}
|
||||
|
||||
binding.playerSlidingLayout.setPanelHeight(Math.max(minPanelHeight, availablePanelHeight));
|
||||
((AbsSlidingMusicPanelActivity) fragment.getActivity()).setAntiDragView(binding.playerSlidingLayout.findViewById(R.id.player_panel));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCurrentSong(Song song) {
|
||||
currentSong = song;
|
||||
currentSongViewHolder.title.setText(song.title);
|
||||
currentSongViewHolder.text.setText(MusicUtil.getSongInfoString(song));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void animateColorChange(int newColor) {
|
||||
super.animateColorChange(newColor);
|
||||
|
||||
binding.playerSlidingLayout.setBackgroundColor(fragment.lastColor);
|
||||
createDefaultColorChangeAnimatorSet(newColor).start();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private static class LandscapeImpl extends BaseImpl {
|
||||
public LandscapeImpl(CardPlayerFragment fragment, FragmentCardPlayerBinding binding) {
|
||||
super(fragment, binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUpPanelAndAlbumCoverHeight() {
|
||||
int panelHeight = binding.playerSlidingLayout.getHeight() - fragment.playbackControlsFragment.getView().getHeight();
|
||||
binding.playerSlidingLayout.setPanelHeight(panelHeight);
|
||||
|
||||
((AbsSlidingMusicPanelActivity) fragment.getActivity()).setAntiDragView(binding.playerSlidingLayout.findViewById(R.id.player_panel));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCurrentSong(Song song) {
|
||||
binding.playerToolbar.setTitle(song.title);
|
||||
binding.playerToolbar.setSubtitle(MusicUtil.getSongInfoString(song));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void animateColorChange(int newColor) {
|
||||
super.animateColorChange(newColor);
|
||||
|
||||
binding.playerSlidingLayout.setBackgroundColor(fragment.lastColor);
|
||||
|
||||
AnimatorSet animatorSet = createDefaultColorChangeAnimatorSet(newColor);
|
||||
animatorSet.play(ViewUtil.createBackgroundColorTransition(binding.playerToolbar, fragment.lastColor, newColor))
|
||||
.with(ViewUtil.createBackgroundColorTransition(fragment.getView().findViewById(R.id.status_bar), ColorUtil.darkenColor(fragment.lastColor), ColorUtil.darkenColor(newColor)));
|
||||
|
||||
animatorSet.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
package com.dkanada.gramophone.fragments.player.card;
|
||||
|
||||
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.DecelerateInterpolator;
|
||||
import android.widget.SeekBar;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.kabouzeid.appthemehelper.util.ColorUtil;
|
||||
import com.kabouzeid.appthemehelper.util.MaterialValueHelper;
|
||||
import com.kabouzeid.appthemehelper.util.TintHelper;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.helper.MusicPlayerRemote;
|
||||
import com.dkanada.gramophone.databinding.FragmentCardPlayerPlaybackControlsBinding;
|
||||
import com.dkanada.gramophone.helper.MusicProgressViewUpdateHelper;
|
||||
import com.dkanada.gramophone.helper.PlayPauseButtonOnClickHandler;
|
||||
import com.dkanada.gramophone.misc.SimpleOnSeekbarChangeListener;
|
||||
import com.dkanada.gramophone.service.MusicService;
|
||||
import com.dkanada.gramophone.fragments.AbsMusicServiceFragment;
|
||||
import com.dkanada.gramophone.util.MusicUtil;
|
||||
import com.dkanada.gramophone.views.PlayPauseDrawable;
|
||||
|
||||
public class CardPlayerPlaybackControlsFragment extends AbsMusicServiceFragment implements MusicProgressViewUpdateHelper.Callback {
|
||||
|
||||
public FragmentCardPlayerPlaybackControlsBinding binding;
|
||||
|
||||
private PlayPauseDrawable playerFabPlayPauseDrawable;
|
||||
|
||||
private int lastPlaybackControlsColor;
|
||||
private int lastDisabledPlaybackControlsColor;
|
||||
|
||||
private MusicProgressViewUpdateHelper progressViewUpdateHelper;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentCardPlayerPlaybackControlsBinding.inflate(inflater);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setUpMusicControllers();
|
||||
updateProgressTextColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
progressViewUpdateHelper.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
progressViewUpdateHelper.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
updatePlayPauseDrawableState(false);
|
||||
updateRepeatState();
|
||||
updateShuffleState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayStateChanged() {
|
||||
updatePlayPauseDrawableState(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepeatModeChanged() {
|
||||
updateRepeatState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShuffleModeChanged() {
|
||||
updateShuffleState();
|
||||
}
|
||||
|
||||
public void setDark(boolean dark) {
|
||||
if (dark) {
|
||||
lastPlaybackControlsColor = MaterialValueHelper.getSecondaryTextColor(getActivity(), true);
|
||||
lastDisabledPlaybackControlsColor = MaterialValueHelper.getSecondaryDisabledTextColor(getActivity(), true);
|
||||
} else {
|
||||
lastPlaybackControlsColor = MaterialValueHelper.getPrimaryTextColor(getActivity(), false);
|
||||
lastDisabledPlaybackControlsColor = MaterialValueHelper.getPrimaryDisabledTextColor(getActivity(), false);
|
||||
}
|
||||
|
||||
updateRepeatState();
|
||||
updateShuffleState();
|
||||
updatePrevNextColor();
|
||||
updateProgressTextColor();
|
||||
}
|
||||
|
||||
private void setUpPlayPauseFab() {
|
||||
final int fabColor = Color.WHITE;
|
||||
TintHelper.setTintAuto(binding.playerPlayPauseFab, fabColor, true);
|
||||
|
||||
playerFabPlayPauseDrawable = new PlayPauseDrawable(getActivity());
|
||||
|
||||
binding.playerPlayPauseFab.setImageDrawable(playerFabPlayPauseDrawable); // Note: set the drawable AFTER TintHelper.setTintAuto() was called
|
||||
binding.playerPlayPauseFab.setColorFilter(MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(fabColor)), PorterDuff.Mode.SRC_IN);
|
||||
binding.playerPlayPauseFab.setOnClickListener(new PlayPauseButtonOnClickHandler());
|
||||
binding.playerPlayPauseFab.post(() -> {
|
||||
if (binding.playerPlayPauseFab != null) {
|
||||
binding.playerPlayPauseFab.setPivotX(binding.playerPlayPauseFab.getWidth() / 2);
|
||||
binding.playerPlayPauseFab.setPivotY(binding.playerPlayPauseFab.getHeight() / 2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void updatePlayPauseDrawableState(boolean animate) {
|
||||
if (MusicPlayerRemote.isPlaying()) {
|
||||
playerFabPlayPauseDrawable.setPause(animate);
|
||||
} else {
|
||||
playerFabPlayPauseDrawable.setPlay(animate);
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpMusicControllers() {
|
||||
setUpPlayPauseFab();
|
||||
setUpPrevNext();
|
||||
setUpRepeatButton();
|
||||
setUpShuffleButton();
|
||||
setUpProgressSlider();
|
||||
}
|
||||
|
||||
private void setUpPrevNext() {
|
||||
updatePrevNextColor();
|
||||
binding.playerNextButton.setOnClickListener(v -> MusicPlayerRemote.playNextSong());
|
||||
binding.playerPrevButton.setOnClickListener(v -> MusicPlayerRemote.back());
|
||||
}
|
||||
|
||||
private void updateProgressTextColor() {
|
||||
int color = MaterialValueHelper.getPrimaryTextColor(getContext(), false);
|
||||
binding.playerSongTotalTime.setTextColor(color);
|
||||
binding.playerSongCurrentProgress.setTextColor(color);
|
||||
}
|
||||
|
||||
private void updatePrevNextColor() {
|
||||
binding.playerNextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
binding.playerPrevButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
private void setUpShuffleButton() {
|
||||
binding.playerShuffleButton.setOnClickListener(v -> MusicPlayerRemote.toggleShuffleMode());
|
||||
}
|
||||
|
||||
private void updateShuffleState() {
|
||||
switch (MusicPlayerRemote.getShuffleMode()) {
|
||||
case MusicService.SHUFFLE_MODE_SHUFFLE:
|
||||
binding.playerShuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
break;
|
||||
default:
|
||||
binding.playerShuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpRepeatButton() {
|
||||
binding.playerRepeatButton.setOnClickListener(v -> MusicPlayerRemote.cycleRepeatMode());
|
||||
}
|
||||
|
||||
private void updateRepeatState() {
|
||||
switch (MusicPlayerRemote.getRepeatMode()) {
|
||||
case MusicService.REPEAT_MODE_NONE:
|
||||
binding.playerRepeatButton.setImageResource(R.drawable.ic_repeat_white_24dp);
|
||||
binding.playerRepeatButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
break;
|
||||
case MusicService.REPEAT_MODE_ALL:
|
||||
binding.playerRepeatButton.setImageResource(R.drawable.ic_repeat_white_24dp);
|
||||
binding.playerRepeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
break;
|
||||
case MusicService.REPEAT_MODE_THIS:
|
||||
binding.playerRepeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp);
|
||||
binding.playerRepeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void show() {
|
||||
binding.playerPlayPauseFab.animate()
|
||||
.scaleX(1f)
|
||||
.scaleY(1f)
|
||||
.rotation(360f)
|
||||
.setInterpolator(new DecelerateInterpolator())
|
||||
.start();
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
binding.playerPlayPauseFab.setScaleX(0f);
|
||||
binding.playerPlayPauseFab.setScaleY(0f);
|
||||
binding.playerPlayPauseFab.setRotation(0f);
|
||||
}
|
||||
|
||||
private void setUpProgressSlider() {
|
||||
int color = MaterialValueHelper.getPrimaryTextColor(getContext(), false);
|
||||
binding.playerProgressSlider.getThumb().mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
|
||||
binding.playerProgressSlider.getProgressDrawable().mutate().setColorFilter(Color.TRANSPARENT, PorterDuff.Mode.SRC_IN);
|
||||
|
||||
binding.playerProgressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if (fromUser) {
|
||||
MusicPlayerRemote.seekTo(progress);
|
||||
onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), MusicPlayerRemote.getSongDurationMillis());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateProgressViews(int progress, int total) {
|
||||
binding.playerProgressSlider.setMax(total);
|
||||
binding.playerProgressSlider.setProgress(progress);
|
||||
binding.playerSongTotalTime.setText(MusicUtil.getReadableDurationString(total));
|
||||
binding.playerSongCurrentProgress.setText(MusicUtil.getReadableDurationString(progress));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,475 @@
|
|||
package com.dkanada.gramophone.fragments.player.flat;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.dkanada.gramophone.databinding.FragmentFlatPlayerBinding;
|
||||
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.kabouzeid.appthemehelper.ThemeStore;
|
||||
import com.kabouzeid.appthemehelper.util.ATHUtil;
|
||||
import com.kabouzeid.appthemehelper.util.ColorUtil;
|
||||
import com.kabouzeid.appthemehelper.util.ToolbarContentTintHelper;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.adapter.base.MediaEntryViewHolder;
|
||||
import com.dkanada.gramophone.adapter.song.PlayingQueueAdapter;
|
||||
import com.dkanada.gramophone.dialogs.SongShareDialog;
|
||||
import com.dkanada.gramophone.helper.MusicPlayerRemote;
|
||||
import com.dkanada.gramophone.helper.menu.SongMenuHelper;
|
||||
import com.dkanada.gramophone.model.Song;
|
||||
import com.dkanada.gramophone.activities.base.AbsSlidingMusicPanelActivity;
|
||||
import com.dkanada.gramophone.fragments.player.AbsPlayerFragment;
|
||||
import com.dkanada.gramophone.fragments.player.PlayerAlbumCoverFragment;
|
||||
import com.dkanada.gramophone.util.ImageUtil;
|
||||
import com.dkanada.gramophone.util.MusicUtil;
|
||||
import com.dkanada.gramophone.util.Util;
|
||||
import com.dkanada.gramophone.util.ViewUtil;
|
||||
import com.dkanada.gramophone.views.WidthFitSquareLayout;
|
||||
import com.sothree.slidinguppanel.SlidingUpPanelLayout;
|
||||
|
||||
public class FlatPlayerFragment extends AbsPlayerFragment implements PlayerAlbumCoverFragment.Callbacks, SlidingUpPanelLayout.PanelSlideListener {
|
||||
|
||||
private FragmentFlatPlayerBinding binding;
|
||||
|
||||
private int lastColor;
|
||||
|
||||
private FlatPlayerPlaybackControlsFragment playbackControlsFragment;
|
||||
private PlayerAlbumCoverFragment playerAlbumCoverFragment;
|
||||
|
||||
private LinearLayoutManager layoutManager;
|
||||
|
||||
private PlayingQueueAdapter playingQueueAdapter;
|
||||
|
||||
private RecyclerView.Adapter wrappedAdapter;
|
||||
private RecyclerViewDragDropManager recyclerViewDragDropManager;
|
||||
|
||||
private Impl impl;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentFlatPlayerBinding.inflate(inflater);
|
||||
|
||||
if (Util.isLandscape(getResources())) {
|
||||
impl = new LandscapeImpl(this, binding);
|
||||
} else {
|
||||
impl = new PortraitImpl(this, binding);
|
||||
}
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
impl.init();
|
||||
|
||||
setUpPlayerToolbar();
|
||||
setUpSubFragments();
|
||||
|
||||
setUpRecyclerView();
|
||||
|
||||
if (binding.playerSlidingLayout != null) {
|
||||
binding.playerSlidingLayout.addPanelSlideListener(this);
|
||||
binding.playerSlidingLayout.setAntiDragView(view.findViewById(R.id.draggable_area));
|
||||
}
|
||||
|
||||
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
impl.setUpPanelAndAlbumCoverHeight();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
if (binding.playerSlidingLayout != null) {
|
||||
binding.playerSlidingLayout.removePanelSlideListener(this);
|
||||
}
|
||||
|
||||
if (recyclerViewDragDropManager != null) {
|
||||
recyclerViewDragDropManager.release();
|
||||
recyclerViewDragDropManager = null;
|
||||
}
|
||||
|
||||
binding.playerRecyclerView.setItemAnimator(null);
|
||||
binding.playerRecyclerView.setAdapter(null);
|
||||
|
||||
if (wrappedAdapter != null) {
|
||||
WrapperAdapterUtils.releaseAll(wrappedAdapter);
|
||||
wrappedAdapter = null;
|
||||
}
|
||||
|
||||
playingQueueAdapter = null;
|
||||
layoutManager = null;
|
||||
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
if (recyclerViewDragDropManager != null) {
|
||||
recyclerViewDragDropManager.cancelDrag();
|
||||
}
|
||||
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
checkToggleToolbar(binding.toolbarContainer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
updateQueue();
|
||||
updateCurrentSong();
|
||||
updateIsFavorite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayMetadataChanged() {
|
||||
updateCurrentSong();
|
||||
updateIsFavorite();
|
||||
updateQueuePosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueueChanged() {
|
||||
updateQueue();
|
||||
}
|
||||
|
||||
private void updateQueue() {
|
||||
playingQueueAdapter.swapDataSet(MusicPlayerRemote.getPlayingQueue(), MusicPlayerRemote.getPosition());
|
||||
binding.playerQueueSubHeader.setText(getUpNextAndQueueTime());
|
||||
if (binding.playerSlidingLayout == null || binding.playerSlidingLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
|
||||
resetToCurrentPosition();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateQueuePosition() {
|
||||
playingQueueAdapter.setCurrent(MusicPlayerRemote.getPosition());
|
||||
binding.playerQueueSubHeader.setText(getUpNextAndQueueTime());
|
||||
if (binding.playerSlidingLayout == null || binding.playerSlidingLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
|
||||
resetToCurrentPosition();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCurrentSong() {
|
||||
impl.updateCurrentSong(MusicPlayerRemote.getCurrentSong());
|
||||
}
|
||||
|
||||
private void setUpSubFragments() {
|
||||
playbackControlsFragment = (FlatPlayerPlaybackControlsFragment) getChildFragmentManager().findFragmentById(R.id.playback_controls_fragment);
|
||||
playerAlbumCoverFragment = (PlayerAlbumCoverFragment) getChildFragmentManager().findFragmentById(R.id.player_album_cover_fragment);
|
||||
|
||||
playerAlbumCoverFragment.setCallbacks(this);
|
||||
}
|
||||
|
||||
private void setUpPlayerToolbar() {
|
||||
binding.playerToolbar.inflateMenu(R.menu.menu_player);
|
||||
binding.playerToolbar.setNavigationIcon(R.drawable.ic_close_white_24dp);
|
||||
binding.playerToolbar.setNavigationOnClickListener(v -> getActivity().onBackPressed());
|
||||
binding.playerToolbar.setOnMenuItemClickListener(this);
|
||||
}
|
||||
|
||||
private void setUpRecyclerView() {
|
||||
recyclerViewDragDropManager = new RecyclerViewDragDropManager();
|
||||
final GeneralItemAnimator animator = new RefactoredDefaultItemAnimator();
|
||||
|
||||
playingQueueAdapter = new PlayingQueueAdapter(
|
||||
((AppCompatActivity) getActivity()),
|
||||
MusicPlayerRemote.getPlayingQueue(),
|
||||
MusicPlayerRemote.getPosition(),
|
||||
R.layout.item_list,
|
||||
false,
|
||||
null);
|
||||
wrappedAdapter = recyclerViewDragDropManager.createWrappedAdapter(playingQueueAdapter);
|
||||
|
||||
layoutManager = new LinearLayoutManager(getActivity());
|
||||
|
||||
binding.playerRecyclerView.setLayoutManager(layoutManager);
|
||||
binding.playerRecyclerView.setAdapter(wrappedAdapter);
|
||||
binding.playerRecyclerView.setItemAnimator(animator);
|
||||
|
||||
recyclerViewDragDropManager.attachRecyclerView(binding.playerRecyclerView);
|
||||
|
||||
layoutManager.scrollToPositionWithOffset(MusicPlayerRemote.getPosition() + 1, 0);
|
||||
}
|
||||
|
||||
private void updateIsFavorite() {
|
||||
boolean favorite = MusicPlayerRemote.getCurrentSong().favorite;
|
||||
int res = favorite ? R.drawable.ic_favorite_white_24dp : R.drawable.ic_favorite_border_white_24dp;
|
||||
int color = ToolbarContentTintHelper.toolbarContentColor(getActivity(), Color.TRANSPARENT);
|
||||
Drawable drawable = ImageUtil.getTintedVectorDrawable(getActivity(), res, color);
|
||||
binding.playerToolbar.getMenu().findItem(R.id.action_toggle_favorite)
|
||||
.setIcon(drawable)
|
||||
.setTitle(favorite ? getString(R.string.action_remove_from_favorites) : getString(R.string.action_add_to_favorites));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ColorInt
|
||||
public int getPaletteColor() {
|
||||
return lastColor;
|
||||
}
|
||||
|
||||
private void animateColorChange(final int newColor) {
|
||||
impl.animateColorChange(newColor);
|
||||
lastColor = newColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toggleFavorite(Song song) {
|
||||
super.toggleFavorite(song);
|
||||
if (song.id.equals(MusicPlayerRemote.getCurrentSong().id)) {
|
||||
if (song.favorite) {
|
||||
playerAlbumCoverFragment.showHeartAnimation();
|
||||
}
|
||||
|
||||
updateIsFavorite();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShow() {
|
||||
playbackControlsFragment.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHide() {
|
||||
playbackControlsFragment.hide();
|
||||
onBackPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBackPressed() {
|
||||
boolean wasExpanded = false;
|
||||
if (binding.playerSlidingLayout != null) {
|
||||
wasExpanded = binding.playerSlidingLayout.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED;
|
||||
binding.playerSlidingLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
|
||||
}
|
||||
|
||||
return wasExpanded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onColorChanged(int color) {
|
||||
animateColorChange(color);
|
||||
playbackControlsFragment.setDark(ColorUtil.isColorLight(color));
|
||||
getCallbacks().onPaletteColorChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFavoriteToggled() {
|
||||
toggleFavorite(MusicPlayerRemote.getCurrentSong());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onToolbarToggled() {
|
||||
toggleToolbar(binding.toolbarContainer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelSlide(View view, float slide) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelStateChanged(View panel, SlidingUpPanelLayout.PanelState previousState, SlidingUpPanelLayout.PanelState newState) {
|
||||
switch (newState) {
|
||||
case COLLAPSED:
|
||||
onPanelCollapsed(panel);
|
||||
break;
|
||||
case ANCHORED:
|
||||
// this fixes a bug where the panel would get stuck for some reason
|
||||
binding.playerSlidingLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void onPanelCollapsed(View panel) {
|
||||
resetToCurrentPosition();
|
||||
}
|
||||
|
||||
private void resetToCurrentPosition() {
|
||||
binding.playerRecyclerView.stopScroll();
|
||||
layoutManager.scrollToPositionWithOffset(MusicPlayerRemote.getPosition() + 1, 0);
|
||||
}
|
||||
|
||||
interface Impl {
|
||||
void init();
|
||||
|
||||
void updateCurrentSong(Song song);
|
||||
|
||||
void animateColorChange(final int newColor);
|
||||
|
||||
void setUpPanelAndAlbumCoverHeight();
|
||||
}
|
||||
|
||||
private static abstract class BaseImpl implements Impl {
|
||||
protected FlatPlayerFragment fragment;
|
||||
protected FragmentFlatPlayerBinding binding;
|
||||
|
||||
public BaseImpl(FlatPlayerFragment fragment, FragmentFlatPlayerBinding binding) {
|
||||
this.fragment = fragment;
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public AnimatorSet createDefaultColorChangeAnimatorSet(int newColor) {
|
||||
Animator backgroundAnimator = ViewUtil.createBackgroundColorTransition(fragment.playbackControlsFragment.getView(), fragment.lastColor, newColor);
|
||||
Animator statusBarAnimator = ViewUtil.createBackgroundColorTransition(binding.playerStatusBar, fragment.lastColor, newColor);
|
||||
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
animatorSet.playTogether(backgroundAnimator, statusBarAnimator);
|
||||
|
||||
if (!ATHUtil.isWindowBackgroundDark(fragment.getActivity())) {
|
||||
int adjustedLastColor = ColorUtil.isColorLight(fragment.lastColor) ? ColorUtil.darkenColor(fragment.lastColor) : fragment.lastColor;
|
||||
int adjustedNewColor = ColorUtil.isColorLight(newColor) ? ColorUtil.darkenColor(newColor) : newColor;
|
||||
Animator subHeaderAnimator = ViewUtil.createTextColorTransition(binding.playerQueueSubHeader, adjustedLastColor, adjustedNewColor);
|
||||
animatorSet.play(subHeaderAnimator);
|
||||
}
|
||||
|
||||
animatorSet.setDuration(ViewUtil.PHONOGRAPH_ANIM_TIME);
|
||||
return animatorSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void animateColorChange(int newColor) {
|
||||
if (ATHUtil.isWindowBackgroundDark(fragment.getActivity())) {
|
||||
binding.playerQueueSubHeader.setTextColor(ThemeStore.textColorSecondary(fragment.getActivity()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private static class PortraitImpl extends BaseImpl {
|
||||
MediaEntryViewHolder currentSongViewHolder;
|
||||
Song currentSong = Song.EMPTY;
|
||||
|
||||
public PortraitImpl(FlatPlayerFragment fragment, FragmentFlatPlayerBinding binding) {
|
||||
super(fragment, binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
currentSongViewHolder = new MediaEntryViewHolder(fragment.getView().findViewById(R.id.current_song));
|
||||
|
||||
currentSongViewHolder.separator.setVisibility(View.VISIBLE);
|
||||
currentSongViewHolder.shortSeparator.setVisibility(View.GONE);
|
||||
currentSongViewHolder.image.setScaleType(ImageView.ScaleType.CENTER);
|
||||
currentSongViewHolder.image.setColorFilter(ATHUtil.resolveColor(fragment.getActivity(), R.attr.iconColor, ThemeStore.textColorSecondary(fragment.getActivity())), PorterDuff.Mode.SRC_IN);
|
||||
currentSongViewHolder.image.setImageResource(R.drawable.ic_volume_up_white_24dp);
|
||||
currentSongViewHolder.itemView.setOnClickListener(v -> {
|
||||
// toggle the panel
|
||||
if (binding.playerSlidingLayout.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
|
||||
binding.playerSlidingLayout.setPanelState(SlidingUpPanelLayout.PanelState.EXPANDED);
|
||||
} else if (binding.playerSlidingLayout.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) {
|
||||
binding.playerSlidingLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
|
||||
}
|
||||
});
|
||||
currentSongViewHolder.menu.setOnClickListener(new SongMenuHelper.OnClickSongMenu((AppCompatActivity) fragment.getActivity()) {
|
||||
@Override
|
||||
public Song getSong() {
|
||||
return currentSong;
|
||||
}
|
||||
|
||||
public int getMenuRes() {
|
||||
return R.menu.menu_item_playing_queue_song;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_remove_from_queue:
|
||||
MusicPlayerRemote.removeFromQueue(MusicPlayerRemote.getPosition());
|
||||
return true;
|
||||
case R.id.action_share:
|
||||
SongShareDialog.create(getSong()).show(fragment.getFragmentManager(), "SONG_SHARE_DIALOG");
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onMenuItemClick(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUpPanelAndAlbumCoverHeight() {
|
||||
WidthFitSquareLayout albumCoverContainer = fragment.getView().findViewById(R.id.album_cover_container);
|
||||
|
||||
final int availablePanelHeight = binding.playerSlidingLayout.getHeight() - fragment.getView().findViewById(R.id.player_content).getHeight();
|
||||
final int minPanelHeight = (int) ViewUtil.convertDpToPixel(8 + 72 + 24, fragment.getResources()) + fragment.getResources().getDimensionPixelSize(R.dimen.progress_container_height) + fragment.getResources().getDimensionPixelSize(R.dimen.media_controller_container_height);
|
||||
if (availablePanelHeight < minPanelHeight) {
|
||||
albumCoverContainer.getLayoutParams().height = albumCoverContainer.getHeight() - (minPanelHeight - availablePanelHeight);
|
||||
albumCoverContainer.forceSquare(false);
|
||||
}
|
||||
|
||||
binding.playerSlidingLayout.setPanelHeight(Math.max(minPanelHeight, availablePanelHeight));
|
||||
((AbsSlidingMusicPanelActivity) fragment.getActivity()).setAntiDragView(binding.playerSlidingLayout.findViewById(R.id.player_panel));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCurrentSong(Song song) {
|
||||
currentSong = song;
|
||||
currentSongViewHolder.title.setText(song.title);
|
||||
currentSongViewHolder.text.setText(MusicUtil.getSongInfoString(song));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void animateColorChange(int newColor) {
|
||||
super.animateColorChange(newColor);
|
||||
createDefaultColorChangeAnimatorSet(newColor).start();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private static class LandscapeImpl extends BaseImpl {
|
||||
public LandscapeImpl(FlatPlayerFragment fragment, FragmentFlatPlayerBinding binding) {
|
||||
super(fragment, binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUpPanelAndAlbumCoverHeight() {
|
||||
((AbsSlidingMusicPanelActivity) fragment.getActivity()).setAntiDragView(fragment.getView().findViewById(R.id.player_panel));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCurrentSong(Song song) {
|
||||
binding.playerToolbar.setTitle(song.title);
|
||||
binding.playerToolbar.setSubtitle(MusicUtil.getSongInfoString(song));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void animateColorChange(int newColor) {
|
||||
super.animateColorChange(newColor);
|
||||
|
||||
AnimatorSet animatorSet = createDefaultColorChangeAnimatorSet(newColor);
|
||||
animatorSet.play(ViewUtil.createBackgroundColorTransition(binding.playerToolbar, fragment.lastColor, newColor));
|
||||
animatorSet.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
package com.dkanada.gramophone.fragments.player.flat;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.TimeInterpolator;
|
||||
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.widget.SeekBar;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
|
||||
|
||||
import com.dkanada.gramophone.databinding.FragmentFlatPlayerPlaybackControlsBinding;
|
||||
import com.kabouzeid.appthemehelper.util.MaterialValueHelper;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.helper.MusicPlayerRemote;
|
||||
import com.dkanada.gramophone.helper.MusicProgressViewUpdateHelper;
|
||||
import com.dkanada.gramophone.helper.PlayPauseButtonOnClickHandler;
|
||||
import com.dkanada.gramophone.misc.SimpleOnSeekbarChangeListener;
|
||||
import com.dkanada.gramophone.service.MusicService;
|
||||
import com.dkanada.gramophone.fragments.AbsMusicServiceFragment;
|
||||
import com.dkanada.gramophone.util.MusicUtil;
|
||||
import com.dkanada.gramophone.views.PlayPauseDrawable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class FlatPlayerPlaybackControlsFragment extends AbsMusicServiceFragment implements MusicProgressViewUpdateHelper.Callback {
|
||||
public FragmentFlatPlayerPlaybackControlsBinding binding;
|
||||
|
||||
private PlayPauseDrawable playPauseDrawable;
|
||||
|
||||
private int lastPlaybackControlsColor;
|
||||
private int lastDisabledPlaybackControlsColor;
|
||||
|
||||
private MusicProgressViewUpdateHelper progressViewUpdateHelper;
|
||||
|
||||
private AnimatorSet musicControllerAnimationSet;
|
||||
|
||||
private boolean hidden = false;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
progressViewUpdateHelper = new MusicProgressViewUpdateHelper(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentFlatPlayerPlaybackControlsBinding.inflate(inflater);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setUpMusicControllers();
|
||||
updateProgressTextColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
progressViewUpdateHelper.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
progressViewUpdateHelper.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
updatePlayPauseDrawableState(false);
|
||||
updateRepeatState();
|
||||
updateShuffleState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayStateChanged() {
|
||||
updatePlayPauseDrawableState(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepeatModeChanged() {
|
||||
updateRepeatState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShuffleModeChanged() {
|
||||
updateShuffleState();
|
||||
}
|
||||
|
||||
public void setDark(boolean dark) {
|
||||
if (dark) {
|
||||
lastPlaybackControlsColor = MaterialValueHelper.getSecondaryTextColor(getActivity(), true);
|
||||
lastDisabledPlaybackControlsColor = MaterialValueHelper.getSecondaryDisabledTextColor(getActivity(), true);
|
||||
} else {
|
||||
lastPlaybackControlsColor = MaterialValueHelper.getPrimaryTextColor(getActivity(), false);
|
||||
lastDisabledPlaybackControlsColor = MaterialValueHelper.getPrimaryDisabledTextColor(getActivity(), false);
|
||||
}
|
||||
|
||||
updateRepeatState();
|
||||
updateShuffleState();
|
||||
updatePrevNextColor();
|
||||
updatePlayPauseColor();
|
||||
updateProgressTextColor();
|
||||
}
|
||||
|
||||
private void setUpPlayPauseButton() {
|
||||
playPauseDrawable = new PlayPauseDrawable(getActivity());
|
||||
binding.playerPlayPauseButton.setImageDrawable(playPauseDrawable);
|
||||
updatePlayPauseColor();
|
||||
binding.playerPlayPauseButton.setOnClickListener(new PlayPauseButtonOnClickHandler());
|
||||
binding.playerPlayPauseButton.post(() -> {
|
||||
binding.playerPlayPauseButton.setPivotX(binding.playerPlayPauseButton.getWidth() / 2);
|
||||
binding.playerPlayPauseButton.setPivotY(binding.playerPlayPauseButton.getHeight() / 2);
|
||||
});
|
||||
}
|
||||
|
||||
protected void updatePlayPauseDrawableState(boolean animate) {
|
||||
if (MusicPlayerRemote.isPlaying()) {
|
||||
playPauseDrawable.setPause(animate);
|
||||
} else {
|
||||
playPauseDrawable.setPlay(animate);
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpMusicControllers() {
|
||||
setUpPlayPauseButton();
|
||||
setUpPrevNext();
|
||||
setUpRepeatButton();
|
||||
setUpShuffleButton();
|
||||
setUpProgressSlider();
|
||||
}
|
||||
|
||||
private void setUpPrevNext() {
|
||||
updatePrevNextColor();
|
||||
binding.playerNextButton.setOnClickListener(v -> MusicPlayerRemote.playNextSong());
|
||||
binding.playerPrevButton.setOnClickListener(v -> MusicPlayerRemote.back());
|
||||
}
|
||||
|
||||
private void updateProgressTextColor() {
|
||||
int color = MaterialValueHelper.getPrimaryTextColor(getContext(), false);
|
||||
binding.playerSongTotalTime.setTextColor(color);
|
||||
binding.playerSongCurrentProgress.setTextColor(color);
|
||||
}
|
||||
|
||||
private void updatePrevNextColor() {
|
||||
binding.playerNextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
binding.playerPrevButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
private void updatePlayPauseColor() {
|
||||
binding.playerPlayPauseButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
|
||||
private void setUpShuffleButton() {
|
||||
binding.playerShuffleButton.setOnClickListener(v -> MusicPlayerRemote.toggleShuffleMode());
|
||||
}
|
||||
|
||||
private void updateShuffleState() {
|
||||
switch (MusicPlayerRemote.getShuffleMode()) {
|
||||
case MusicService.SHUFFLE_MODE_SHUFFLE:
|
||||
binding.playerShuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
break;
|
||||
default:
|
||||
binding.playerShuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpRepeatButton() {
|
||||
binding.playerRepeatButton.setOnClickListener(v -> MusicPlayerRemote.cycleRepeatMode());
|
||||
}
|
||||
|
||||
private void updateRepeatState() {
|
||||
switch (MusicPlayerRemote.getRepeatMode()) {
|
||||
case MusicService.REPEAT_MODE_NONE:
|
||||
binding.playerRepeatButton.setImageResource(R.drawable.ic_repeat_white_24dp);
|
||||
binding.playerRepeatButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
break;
|
||||
case MusicService.REPEAT_MODE_ALL:
|
||||
binding.playerRepeatButton.setImageResource(R.drawable.ic_repeat_white_24dp);
|
||||
binding.playerRepeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
break;
|
||||
case MusicService.REPEAT_MODE_THIS:
|
||||
binding.playerRepeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp);
|
||||
binding.playerRepeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (hidden) {
|
||||
if (musicControllerAnimationSet == null) {
|
||||
TimeInterpolator interpolator = new FastOutSlowInInterpolator();
|
||||
final int duration = 300;
|
||||
|
||||
LinkedList<Animator> animators = new LinkedList<>();
|
||||
|
||||
addAnimation(animators, binding.playerPlayPauseButton, interpolator, duration, 0);
|
||||
addAnimation(animators, binding.playerNextButton, interpolator, duration, 100);
|
||||
addAnimation(animators, binding.playerPrevButton, interpolator, duration, 100);
|
||||
addAnimation(animators, binding.playerShuffleButton, interpolator, duration, 200);
|
||||
addAnimation(animators, binding.playerRepeatButton, interpolator, duration, 200);
|
||||
|
||||
musicControllerAnimationSet = new AnimatorSet();
|
||||
musicControllerAnimationSet.playTogether(animators);
|
||||
} else {
|
||||
musicControllerAnimationSet.cancel();
|
||||
}
|
||||
musicControllerAnimationSet.start();
|
||||
}
|
||||
|
||||
hidden = false;
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
if (musicControllerAnimationSet != null) {
|
||||
musicControllerAnimationSet.cancel();
|
||||
}
|
||||
|
||||
prepareForAnimation(binding.playerPlayPauseButton);
|
||||
prepareForAnimation(binding.playerNextButton);
|
||||
prepareForAnimation(binding.playerPrevButton);
|
||||
prepareForAnimation(binding.playerShuffleButton);
|
||||
prepareForAnimation(binding.playerRepeatButton);
|
||||
|
||||
hidden = true;
|
||||
}
|
||||
|
||||
private static void addAnimation(Collection<Animator> animators, View view, TimeInterpolator interpolator, int duration, int delay) {
|
||||
Animator scaleX = ObjectAnimator.ofFloat(view, View.SCALE_X, 0f, 1f);
|
||||
scaleX.setInterpolator(interpolator);
|
||||
scaleX.setDuration(duration);
|
||||
scaleX.setStartDelay(delay);
|
||||
animators.add(scaleX);
|
||||
|
||||
Animator scaleY = ObjectAnimator.ofFloat(view, View.SCALE_Y, 0f, 1f);
|
||||
scaleY.setInterpolator(interpolator);
|
||||
scaleY.setDuration(duration);
|
||||
scaleY.setStartDelay(delay);
|
||||
animators.add(scaleY);
|
||||
}
|
||||
|
||||
private static void prepareForAnimation(View view) {
|
||||
if (view != null) {
|
||||
view.setScaleX(0f);
|
||||
view.setScaleY(0f);
|
||||
}
|
||||
}
|
||||
|
||||
private void setUpProgressSlider() {
|
||||
int color = MaterialValueHelper.getPrimaryTextColor(getContext(), false);
|
||||
binding.playerProgressSlider.getThumb().mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
|
||||
binding.playerProgressSlider.getProgressDrawable().mutate().setColorFilter(Color.TRANSPARENT, PorterDuff.Mode.SRC_IN);
|
||||
|
||||
binding.playerProgressSlider.setOnSeekBarChangeListener(new SimpleOnSeekbarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if (fromUser) {
|
||||
MusicPlayerRemote.seekTo(progress);
|
||||
onUpdateProgressViews(MusicPlayerRemote.getSongProgressMillis(), MusicPlayerRemote.getSongDurationMillis());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateProgressViews(int progress, int total) {
|
||||
binding.playerProgressSlider.setMax(total);
|
||||
binding.playerProgressSlider.setProgress(progress);
|
||||
binding.playerSongTotalTime.setText(MusicUtil.getReadableDurationString(total));
|
||||
binding.playerSongCurrentProgress.setText(MusicUtil.getReadableDurationString(progress));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue