move activities to root directory
This commit is contained in:
parent
cc1182e2eb
commit
53657919af
30 changed files with 54 additions and 54 deletions
|
|
@ -0,0 +1,175 @@
|
|||
package com.dkanada.gramophone.activities;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.kabouzeid.appthemehelper.ThemeStore;
|
||||
import com.dkanada.gramophone.databinding.ActivityAboutBinding;
|
||||
import com.dkanada.gramophone.databinding.CardAboutAppBinding;
|
||||
import com.dkanada.gramophone.databinding.CardAuthorBinding;
|
||||
import com.dkanada.gramophone.databinding.CardSpecialThanksBinding;
|
||||
import com.dkanada.gramophone.databinding.CardSupportDevelopmentBinding;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.activities.base.AbsBaseActivity;
|
||||
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
public class AboutActivity extends AbsBaseActivity implements View.OnClickListener {
|
||||
ActivityAboutBinding binding;
|
||||
|
||||
CardAboutAppBinding aboutBinding;
|
||||
CardAuthorBinding authorBinding;
|
||||
CardSupportDevelopmentBinding supportBinding;
|
||||
CardSpecialThanksBinding thanksBinding;
|
||||
|
||||
private static String GITHUB = "https://github.com/dkanada/gelli";
|
||||
|
||||
private static String TWITTER = "https://twitter.com/karimjabouzeid";
|
||||
private static String WEBSITE = "https://github.com/dkanada";
|
||||
|
||||
private static String TRANSLATE = "https://phonograph.oneskyapp.com/collaboration/project?id=26521";
|
||||
private static String RATE_ON_GOOGLE_PLAY = "https://play.google.com/store/apps/details?id=com.kabouzeid.gramophone";
|
||||
|
||||
private static String AIDAN_FOLLESTAD_GOOGLE_PLUS = "https://google.com/+AidanFollestad";
|
||||
private static String AIDAN_FOLLESTAD_GITHUB = "https://github.com/afollestad";
|
||||
|
||||
private static String MAARTEN_CORPEL_GOOGLE_PLUS = "https://google.com/+MaartenCorpel";
|
||||
|
||||
private static String ALEKSANDAR_TESIC_GOOGLE_PLUS = "https://google.com/+aleksandartešić";
|
||||
|
||||
private static String EUGENE_CHEUNG_GITHUB = "https://github.com/arkon";
|
||||
private static String EUGENE_CHEUNG_WEBSITE = "https://echeung.me/";
|
||||
|
||||
private static String ADRIAN_TWITTER = "https://twitter.com/froschgames";
|
||||
private static String ADRIAN_WEBSITE = "https://froschgames.com/";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivityAboutBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
aboutBinding = CardAboutAppBinding.bind(findViewById(R.id.about_layout));
|
||||
authorBinding = CardAuthorBinding.bind(findViewById(R.id.author_layout));
|
||||
supportBinding = CardSupportDevelopmentBinding.bind(findViewById(R.id.support_layout));
|
||||
thanksBinding = CardSpecialThanksBinding.bind(findViewById(R.id.thanks_layout));
|
||||
|
||||
setDrawUnderStatusbar();
|
||||
setStatusbarColorAuto();
|
||||
|
||||
setNavigationbarColorAuto();
|
||||
setTaskDescriptionColorAuto();
|
||||
|
||||
setUpViews();
|
||||
}
|
||||
|
||||
private void setUpViews() {
|
||||
setUpToolbar();
|
||||
setUpAppVersion();
|
||||
setUpOnClickListeners();
|
||||
}
|
||||
|
||||
private void setUpToolbar() {
|
||||
binding.toolbar.setBackgroundColor(ThemeStore.primaryColor(this));
|
||||
setSupportActionBar(binding.toolbar);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
private void setUpAppVersion() {
|
||||
aboutBinding.appVersion.setText(getCurrentVersionName(this));
|
||||
}
|
||||
|
||||
private void setUpOnClickListeners() {
|
||||
authorBinding.followOnTwitter.setOnClickListener(this);
|
||||
aboutBinding.appSource.setOnClickListener(this);
|
||||
authorBinding.visitWebsite.setOnClickListener(this);
|
||||
supportBinding.reportBugs.setOnClickListener(this);
|
||||
authorBinding.writeAnEmail.setOnClickListener(this);
|
||||
supportBinding.translate.setOnClickListener(this);
|
||||
supportBinding.rateOnGooglePlay.setOnClickListener(this);
|
||||
supportBinding.donate.setOnClickListener(this);
|
||||
thanksBinding.aidanFollestadGooglePlus.setOnClickListener(this);
|
||||
thanksBinding.aidanFollestadGitHub.setOnClickListener(this);
|
||||
thanksBinding.maartenCorpelGooglePlus.setOnClickListener(this);
|
||||
thanksBinding.aleksandarTesicGooglePlus.setOnClickListener(this);
|
||||
thanksBinding.eugeneCheungGitHub.setOnClickListener(this);
|
||||
thanksBinding.eugeneCheungWebsite.setOnClickListener(this);
|
||||
thanksBinding.adrianTwitter.setOnClickListener(this);
|
||||
thanksBinding.adrianWebsite.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private static String getCurrentVersionName(@NonNull final Context context) {
|
||||
try {
|
||||
return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (v == authorBinding.followOnTwitter) {
|
||||
openUrl(TWITTER);
|
||||
} else if (v == aboutBinding.appSource) {
|
||||
openUrl(GITHUB);
|
||||
} else if (v == authorBinding.visitWebsite) {
|
||||
openUrl(WEBSITE);
|
||||
} else if (v == supportBinding.reportBugs) {
|
||||
openUrl(GITHUB);
|
||||
} else if (v == authorBinding.writeAnEmail) {
|
||||
Intent intent = new Intent(Intent.ACTION_SENDTO);
|
||||
intent.setData(Uri.parse("mailto:contact@kabouzeid.com"));
|
||||
intent.putExtra(Intent.EXTRA_EMAIL, "contact@kabouzeid.com");
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, "Phonograph");
|
||||
startActivity(Intent.createChooser(intent, "E-Mail"));
|
||||
} else if (v == supportBinding.translate) {
|
||||
openUrl(TRANSLATE);
|
||||
} else if (v == supportBinding.rateOnGooglePlay) {
|
||||
openUrl(RATE_ON_GOOGLE_PLAY);
|
||||
} else if (v == supportBinding.donate) {
|
||||
openUrl(RATE_ON_GOOGLE_PLAY);
|
||||
} else if (v == thanksBinding.aidanFollestadGooglePlus) {
|
||||
openUrl(AIDAN_FOLLESTAD_GOOGLE_PLUS);
|
||||
} else if (v == thanksBinding.aidanFollestadGitHub) {
|
||||
openUrl(AIDAN_FOLLESTAD_GITHUB);
|
||||
} else if (v == thanksBinding.maartenCorpelGooglePlus) {
|
||||
openUrl(MAARTEN_CORPEL_GOOGLE_PLUS);
|
||||
} else if (v == thanksBinding.aleksandarTesicGooglePlus) {
|
||||
openUrl(ALEKSANDAR_TESIC_GOOGLE_PLUS);
|
||||
} else if (v == thanksBinding.eugeneCheungGitHub) {
|
||||
openUrl(EUGENE_CHEUNG_GITHUB);
|
||||
} else if (v == thanksBinding.eugeneCheungWebsite) {
|
||||
openUrl(EUGENE_CHEUNG_WEBSITE);
|
||||
} else if (v == thanksBinding.adrianTwitter) {
|
||||
openUrl(ADRIAN_TWITTER);
|
||||
} else if (v == thanksBinding.adrianWebsite) {
|
||||
openUrl(ADRIAN_WEBSITE);
|
||||
}
|
||||
}
|
||||
|
||||
private void openUrl(String url) {
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
i.setData(Uri.parse(url));
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(i);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
package com.dkanada.gramophone.activities;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.dkanada.gramophone.App;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.databinding.ActivityLoginBinding;
|
||||
import com.dkanada.gramophone.activities.base.AbsBaseActivity;
|
||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
import com.kabouzeid.appthemehelper.ThemeStore;
|
||||
|
||||
import org.jellyfin.apiclient.interaction.Response;
|
||||
import org.jellyfin.apiclient.model.system.SystemInfo;
|
||||
import org.jellyfin.apiclient.model.users.AuthenticationResult;
|
||||
|
||||
public class LoginActivity extends AbsBaseActivity implements View.OnClickListener {
|
||||
private ActivityLoginBinding binding;
|
||||
private int primaryColor;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivityLoginBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
setDrawUnderStatusbar();
|
||||
setStatusbarColorAuto();
|
||||
|
||||
setNavigationbarColorAuto();
|
||||
setTaskDescriptionColorAuto();
|
||||
|
||||
setUpViews();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
overridePendingTransition(0, R.anim.fade_quick);
|
||||
}
|
||||
|
||||
private void setUpViews() {
|
||||
primaryColor = ThemeStore.primaryColor(this);
|
||||
|
||||
setUpToolbar();
|
||||
setUpOnClickListeners();
|
||||
|
||||
binding.login.setBackgroundColor(primaryColor);
|
||||
}
|
||||
|
||||
private void setUpToolbar() {
|
||||
binding.toolbar.setBackgroundColor(primaryColor);
|
||||
setSupportActionBar(binding.toolbar);
|
||||
}
|
||||
|
||||
private void setUpOnClickListeners() {
|
||||
binding.login.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String username = binding.username.getText().toString().trim();
|
||||
String password = binding.password.getText().toString().trim();
|
||||
String server = binding.server.getText().toString().trim();
|
||||
Context context = this;
|
||||
|
||||
if (TextUtils.isEmpty(username)) {
|
||||
Toast.makeText(this, getResources().getString(R.string.error_empty_username), Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(server)) {
|
||||
Toast.makeText(this, getResources().getString(R.string.error_empty_server), Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
binding.login.setEnabled(false);
|
||||
binding.login.setBackgroundColor(getResources().getColor(R.color.md_grey_800));
|
||||
|
||||
App.getApiClient().ChangeServerLocation(server);
|
||||
App.getApiClient().AuthenticateUserAsync(username, password, new Response<AuthenticationResult>() {
|
||||
@Override
|
||||
public void onResponse(AuthenticationResult result) {
|
||||
if (result.getAccessToken() == null) return;
|
||||
check(server, result.getUser().getId(), result.getAccessToken());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
binding.login.setEnabled(true);
|
||||
binding.login.setBackgroundColor(primaryColor);
|
||||
|
||||
if (exception.getMessage().contains("AuthFailureError")) {
|
||||
Toast.makeText(context, context.getResources().getString(R.string.error_login_credentials), Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Toast.makeText(context, context.getResources().getString(R.string.error_unreachable_server), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void check(String server, String user, String token) {
|
||||
App.getApiClient().GetSystemInfoAsync(new Response<SystemInfo>() {
|
||||
@Override
|
||||
public void onResponse(SystemInfo result) {
|
||||
if (result.getVersion().charAt(0) == '1') {
|
||||
PreferenceUtil.getInstance(LoginActivity.this).setServer(server);
|
||||
PreferenceUtil.getInstance(LoginActivity.this).setUser(user);
|
||||
PreferenceUtil.getInstance(LoginActivity.this).setToken(token);
|
||||
|
||||
Intent intent = new Intent(LoginActivity.this, SplashActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
startActivity(intent);
|
||||
} else {
|
||||
binding.login.setEnabled(true);
|
||||
binding.login.setBackgroundColor(primaryColor);
|
||||
|
||||
Toast.makeText(LoginActivity.this, getResources().getString(R.string.error_version), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,255 @@
|
|||
package com.dkanada.gramophone.activities;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
|
||||
import com.kabouzeid.appthemehelper.ThemeStore;
|
||||
import com.kabouzeid.appthemehelper.util.ATHUtil;
|
||||
import com.kabouzeid.appthemehelper.util.NavigationViewUtil;
|
||||
import com.dkanada.gramophone.databinding.ActivityMainContentBinding;
|
||||
import com.dkanada.gramophone.databinding.ActivityMainDrawerLayoutBinding;
|
||||
import com.dkanada.gramophone.databinding.NavigationDrawerHeaderBinding;
|
||||
import com.dkanada.gramophone.dialogs.ConfirmLogoutDialog;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.glide.CustomGlideRequest;
|
||||
import com.dkanada.gramophone.helper.MusicPlayerRemote;
|
||||
import com.dkanada.gramophone.model.Song;
|
||||
import com.dkanada.gramophone.activities.base.AbsSlidingMusicPanelActivity;
|
||||
import com.dkanada.gramophone.ui.fragments.mainactivity.library.LibraryFragment;
|
||||
import com.dkanada.gramophone.util.MusicUtil;
|
||||
import com.dkanada.gramophone.util.QueryUtil;
|
||||
import com.sothree.slidinguppanel.SlidingUpPanelLayout;
|
||||
|
||||
import org.jellyfin.apiclient.model.dto.BaseItemDto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MainActivity extends AbsSlidingMusicPanelActivity {
|
||||
private ActivityMainDrawerLayoutBinding binding;
|
||||
private ActivityMainContentBinding contentBinding;
|
||||
private NavigationDrawerHeaderBinding navigationBinding;
|
||||
private boolean onLogout;
|
||||
|
||||
@Nullable
|
||||
MainActivityFragmentCallbacks currentFragment;
|
||||
|
||||
@Nullable
|
||||
private List<BaseItemDto> libraries;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setDrawUnderStatusbar();
|
||||
|
||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
|
||||
binding.navigationView.setFitsSystemWindows(false);
|
||||
}
|
||||
|
||||
Menu menu = binding.navigationView.getMenu();
|
||||
QueryUtil.getLibraries(media -> {
|
||||
libraries = (List<BaseItemDto>) media;
|
||||
menu.clear();
|
||||
|
||||
for (BaseItemDto itemDto : libraries) {
|
||||
if (menu.size() == 0) {
|
||||
QueryUtil.currentLibrary = itemDto;
|
||||
}
|
||||
|
||||
if (itemDto.getCollectionType() == null || !itemDto.getCollectionType().equals("music")) continue;
|
||||
menu.add(R.id.navigation_drawer_menu_category_sections, itemDto.getId().hashCode(), menu.size(), itemDto.getName());
|
||||
menu.getItem(menu.size() - 1).setIcon(R.drawable.ic_album_white_24dp);
|
||||
}
|
||||
|
||||
menu.add(R.id.navigation_drawer_menu_category_other, R.id.nav_settings, menu.size(), R.string.action_settings);
|
||||
menu.getItem(menu.size() - 1).setIcon(R.drawable.ic_settings_white_24dp);
|
||||
menu.add(R.id.navigation_drawer_menu_category_other, R.id.nav_about, menu.size(), R.string.action_about);
|
||||
menu.getItem(menu.size() - 1).setIcon(R.drawable.ic_info_outline_white_24dp);
|
||||
menu.add(R.id.navigation_drawer_menu_category_other, R.id.nav_logout, menu.size(), R.string.logout);
|
||||
menu.getItem(menu.size() - 1).setIcon(R.drawable.ic_exit_to_app_white_48dp);
|
||||
|
||||
setUpDrawerLayout();
|
||||
|
||||
menu.getItem(0).setChecked(true);
|
||||
if (savedInstanceState == null) {
|
||||
setCurrentFragment(LibraryFragment.newInstance());
|
||||
} else {
|
||||
restoreCurrentFragment();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
// only override when logout selected
|
||||
if (onLogout) {
|
||||
overridePendingTransition(0, R.anim.fade_slow);
|
||||
onLogout = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setCurrentFragment(Fragment fragment) {
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment, null).commit();
|
||||
currentFragment = (MainActivityFragmentCallbacks) fragment;
|
||||
}
|
||||
|
||||
private void restoreCurrentFragment() {
|
||||
currentFragment = (MainActivityFragmentCallbacks) getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View createContentView() {
|
||||
binding = ActivityMainDrawerLayoutBinding.inflate(getLayoutInflater());
|
||||
contentBinding = ActivityMainContentBinding.inflate(getLayoutInflater());
|
||||
|
||||
ViewGroup drawerContent = binding.drawerContentContainer;
|
||||
drawerContent.addView(wrapSlidingMusicPanel(contentBinding.getRoot()));
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private void setUpNavigationView() {
|
||||
int accentColor = ThemeStore.accentColor(this);
|
||||
NavigationViewUtil.setItemIconColors(binding.navigationView, ATHUtil.resolveColor(this, R.attr.iconColor, ThemeStore.textColorSecondary(this)), accentColor);
|
||||
NavigationViewUtil.setItemTextColors(binding.navigationView, ThemeStore.textColorPrimary(this), accentColor);
|
||||
|
||||
binding.navigationView.setNavigationItemSelectedListener(menuItem -> {
|
||||
binding.drawerLayout.closeDrawers();
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.nav_settings:
|
||||
new Handler().postDelayed(() -> startActivity(new Intent(MainActivity.this, SettingsActivity.class)), 200);
|
||||
break;
|
||||
case R.id.nav_about:
|
||||
new Handler().postDelayed(() -> startActivity(new Intent(MainActivity.this, AboutActivity.class)), 200);
|
||||
break;
|
||||
case R.id.nav_logout:
|
||||
onLogout = true;
|
||||
ConfirmLogoutDialog.create().show(getSupportFragmentManager(), "CONFIRM_LOGOUT_DIALOG");
|
||||
break;
|
||||
}
|
||||
|
||||
// only run the following code when a new library has been selected
|
||||
if (menuItem.getItemId() == QueryUtil.currentLibrary.getId().hashCode()) return true;
|
||||
for (BaseItemDto itemDto : libraries) {
|
||||
if (menuItem.getItemId() == itemDto.getId().hashCode()) {
|
||||
QueryUtil.currentLibrary = itemDto;
|
||||
setCurrentFragment(LibraryFragment.newInstance());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// setCheckable must be applied to the items on creation
|
||||
// it also applies a tacky background color for the checked item
|
||||
// this is a hack to check the current item without that
|
||||
if (menuItem.getItemId() == R.id.nav_settings
|
||||
|| menuItem.getItemId() == R.id.nav_about
|
||||
|| menuItem.getItemId() == R.id.nav_logout) return true;
|
||||
|
||||
for (int i = 0; i < binding.navigationView.getMenu().size(); i++) {
|
||||
if (binding.navigationView.getMenu().getItem(i) == menuItem) {
|
||||
binding.navigationView.getMenu().getItem(i).setChecked(true);
|
||||
} else {
|
||||
binding.navigationView.getMenu().getItem(i).setChecked(false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void setUpDrawerLayout() {
|
||||
setUpNavigationView();
|
||||
}
|
||||
|
||||
private void updateNavigationDrawerHeader() {
|
||||
if (!MusicPlayerRemote.getPlayingQueue().isEmpty()) {
|
||||
Song song = MusicPlayerRemote.getCurrentSong();
|
||||
if (navigationBinding == null) {
|
||||
navigationBinding = NavigationDrawerHeaderBinding.inflate(getLayoutInflater());
|
||||
|
||||
binding.navigationView.addHeaderView(navigationBinding.getRoot());
|
||||
navigationBinding.getRoot().setOnClickListener(v -> {
|
||||
binding.drawerLayout.closeDrawers();
|
||||
if (getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
|
||||
expandPanel();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
navigationBinding.title.setText(song.title);
|
||||
navigationBinding.text.setText(MusicUtil.getSongInfoString(song));
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(this, song.primary, song.blurHash)
|
||||
.build().centerInside().into(navigationBinding.image);
|
||||
} else if (binding.navigationView.getHeaderCount() != 0) {
|
||||
binding.navigationView.removeHeaderView(navigationBinding.getRoot());
|
||||
navigationBinding = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayMetadataChanged() {
|
||||
super.onPlayMetadataChanged();
|
||||
updateNavigationDrawerHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
super.onServiceConnected();
|
||||
updateNavigationDrawerHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
if (binding.drawerLayout.isDrawerOpen(binding.navigationView)) {
|
||||
binding.drawerLayout.closeDrawer(binding.navigationView);
|
||||
} else {
|
||||
binding.drawerLayout.openDrawer(binding.navigationView);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleBackPress() {
|
||||
if (binding.drawerLayout.isDrawerOpen(binding.navigationView)) {
|
||||
binding.drawerLayout.closeDrawers();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.handleBackPress() || (currentFragment != null && currentFragment.handleBackPress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelExpanded(View view) {
|
||||
super.onPanelExpanded(view);
|
||||
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelCollapsed(View view) {
|
||||
super.onPanelCollapsed(view);
|
||||
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
|
||||
}
|
||||
|
||||
public interface MainActivityFragmentCallbacks {
|
||||
boolean handleBackPress();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
package com.dkanada.gramophone.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.adapter.SearchAdapter;
|
||||
import com.dkanada.gramophone.databinding.ActivitySearchBinding;
|
||||
import com.dkanada.gramophone.interfaces.MediaCallback;
|
||||
import com.dkanada.gramophone.model.Album;
|
||||
import com.dkanada.gramophone.model.Artist;
|
||||
import com.dkanada.gramophone.model.Song;
|
||||
import com.dkanada.gramophone.activities.base.AbsMusicServiceActivity;
|
||||
import com.dkanada.gramophone.util.QueryUtil;
|
||||
import com.dkanada.gramophone.util.Util;
|
||||
import com.kabouzeid.appthemehelper.ThemeStore;
|
||||
|
||||
import org.jellyfin.apiclient.model.querying.ArtistsQuery;
|
||||
import org.jellyfin.apiclient.model.querying.ItemQuery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SearchActivity extends AbsMusicServiceActivity implements SearchView.OnQueryTextListener {
|
||||
public String QUERY = "query";
|
||||
|
||||
private ActivitySearchBinding binding;
|
||||
|
||||
private SearchView searchView;
|
||||
|
||||
private Handler handler;
|
||||
|
||||
private SearchAdapter adapter;
|
||||
private String query;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivitySearchBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
setDrawUnderStatusbar();
|
||||
setStatusbarColorAuto();
|
||||
|
||||
setNavigationbarColorAuto();
|
||||
setTaskDescriptionColorAuto();
|
||||
|
||||
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
adapter = new SearchAdapter(this, Collections.emptyList());
|
||||
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
binding.empty.setVisibility(adapter.getItemCount() < 1 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
binding.recyclerView.setAdapter(adapter);
|
||||
binding.recyclerView.setOnTouchListener((v, event) -> {
|
||||
hideSoftKeyboard();
|
||||
return false;
|
||||
});
|
||||
|
||||
setUpToolBar();
|
||||
|
||||
handler = new Handler();
|
||||
if (savedInstanceState != null) {
|
||||
query = savedInstanceState.getString(QUERY);
|
||||
search(query);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putString(QUERY, query);
|
||||
}
|
||||
|
||||
private void setUpToolBar() {
|
||||
binding.toolbar.setBackgroundColor(ThemeStore.primaryColor(this));
|
||||
setSupportActionBar(binding.toolbar);
|
||||
// noinspection ConstantConditions
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_search, menu);
|
||||
|
||||
final MenuItem searchItem = menu.findItem(R.id.search);
|
||||
searchView = (SearchView) searchItem.getActionView();
|
||||
searchView.setQueryHint(getString(R.string.action_search));
|
||||
searchView.setMaxWidth(Integer.MAX_VALUE);
|
||||
|
||||
searchItem.expandActionView();
|
||||
searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
|
||||
@Override
|
||||
public boolean onMenuItemActionExpand(MenuItem item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemActionCollapse(MenuItem item) {
|
||||
onBackPressed();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
searchView.setQuery(query, false);
|
||||
searchView.post(() -> searchView.setOnQueryTextListener(SearchActivity.this));
|
||||
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
onBackPressed();
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void search(@NonNull String query) {
|
||||
this.query = query;
|
||||
|
||||
ItemQuery itemQuery = new ItemQuery();
|
||||
itemQuery.setSearchTerm(query);
|
||||
|
||||
ArtistsQuery artistsQuery = new ArtistsQuery();
|
||||
artistsQuery.setSearchTerm(query);
|
||||
|
||||
MediaCallback callback = new MediaCallback() {
|
||||
private final List<Object> data = new ArrayList<>();
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Override
|
||||
public void onLoadMedia(List<?> media) {
|
||||
data.addAll(media);
|
||||
|
||||
Map<Class<?>, List<Object>> byClass = new HashMap<>();
|
||||
byClass.put(Artist.class, new ArrayList<>());
|
||||
byClass.put(Album.class, new ArrayList<>());
|
||||
byClass.put(Song.class, new ArrayList<>());
|
||||
byClass.put(Object.class, new ArrayList<>());
|
||||
|
||||
for (Object datum : data) {
|
||||
if (byClass.containsKey(datum.getClass())) {
|
||||
byClass.get(datum.getClass()).add(datum);
|
||||
} else {
|
||||
byClass.get(Object.class).add(datum);
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(byClass.get(Artist.class),
|
||||
(one, two) -> ((Artist) one).name.compareTo(((Artist) two).name));
|
||||
|
||||
Collections.sort(byClass.get(Album.class),
|
||||
(one, two) -> ((Album) one).title.compareTo(((Album) two).title));
|
||||
|
||||
Collections.sort(byClass.get(Song.class),
|
||||
(one, two) -> ((Song) one).title.compareTo(((Song) two).title));
|
||||
|
||||
|
||||
List<Object> sortedData = byClass.get(Artist.class);
|
||||
sortedData.addAll(byClass.get(Album.class));
|
||||
sortedData.addAll(byClass.get(Song.class));
|
||||
sortedData.addAll(byClass.get(Object.class));
|
||||
|
||||
adapter.swapDataSet(sortedData);
|
||||
}
|
||||
};
|
||||
|
||||
QueryUtil.getArtists(artistsQuery, callback);
|
||||
QueryUtil.getItems(itemQuery, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
hideSoftKeyboard();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
handler.removeCallbacksAndMessages(null);
|
||||
handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
search(newText);
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void hideSoftKeyboard() {
|
||||
Util.hideSoftKeyboard(SearchActivity.this);
|
||||
if (searchView != null) {
|
||||
searchView.clearFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
package com.dkanada.gramophone.activities;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
|
||||
import com.afollestad.materialdialogs.color.ColorChooserDialog;
|
||||
import com.dkanada.gramophone.databinding.ActivitySettingsBinding;
|
||||
import com.dkanada.gramophone.preferences.DirectPlayPreference;
|
||||
import com.dkanada.gramophone.preferences.DirectPlayPreferenceDialog;
|
||||
import com.kabouzeid.appthemehelper.ThemeStore;
|
||||
import com.kabouzeid.appthemehelper.common.prefs.supportv7.ATEColorPreference;
|
||||
import com.kabouzeid.appthemehelper.common.prefs.supportv7.ATEPreferenceFragmentCompat;
|
||||
import com.kabouzeid.appthemehelper.util.ColorUtil;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.shortcuts.DynamicShortcutManager;
|
||||
import com.dkanada.gramophone.preferences.CategoryPreference;
|
||||
import com.dkanada.gramophone.preferences.CategoryPreferenceDialog;
|
||||
import com.dkanada.gramophone.preferences.NowPlayingScreenPreference;
|
||||
import com.dkanada.gramophone.preferences.NowPlayingScreenPreferenceDialog;
|
||||
import com.dkanada.gramophone.activities.base.AbsBaseActivity;
|
||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
|
||||
public class SettingsActivity extends AbsBaseActivity implements ColorChooserDialog.ColorCallback {
|
||||
private ActivitySettingsBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivitySettingsBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
setDrawUnderStatusbar();
|
||||
setStatusbarColorAuto();
|
||||
|
||||
setNavigationbarColorAuto();
|
||||
setTaskDescriptionColorAuto();
|
||||
|
||||
binding.toolbar.setBackgroundColor(ThemeStore.primaryColor(this));
|
||||
setSupportActionBar(binding.toolbar);
|
||||
// noinspection ConstantConditions
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new SettingsFragment()).commit();
|
||||
} else {
|
||||
SettingsFragment frag = (SettingsFragment) getSupportFragmentManager().findFragmentById(R.id.content_frame);
|
||||
if (frag != null) frag.invalidateSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onColorSelection(@NonNull ColorChooserDialog dialog, @ColorInt int selectedColor) {
|
||||
switch (dialog.getTitle()) {
|
||||
case R.string.pref_title_primary_color:
|
||||
ThemeStore.editTheme(this).primaryColor(selectedColor).commit();
|
||||
break;
|
||||
case R.string.pref_title_accent_color:
|
||||
ThemeStore.editTheme(this).accentColor(selectedColor).commit();
|
||||
break;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||
new DynamicShortcutManager(this).updateDynamicShortcuts();
|
||||
}
|
||||
|
||||
recreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onColorChooserDismissed(@NonNull ColorChooserDialog dialog) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends ATEPreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private static void setSummary(@NonNull Preference preference) {
|
||||
setSummary(preference, PreferenceManager
|
||||
.getDefaultSharedPreferences(preference.getContext())
|
||||
.getString(preference.getKey(), ""));
|
||||
}
|
||||
|
||||
private static void setSummary(Preference preference, @NonNull Object value) {
|
||||
String stringValue = value.toString();
|
||||
|
||||
if (preference instanceof ListPreference) {
|
||||
ListPreference listPreference = (ListPreference) preference;
|
||||
int index = listPreference.findIndexOfValue(stringValue);
|
||||
preference.setSummary(index >= 0 ? listPreference.getEntries()[index] : null);
|
||||
} else {
|
||||
preference.setSummary(stringValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle bundle, String s) {
|
||||
addPreferencesFromResource(R.xml.pref_library);
|
||||
addPreferencesFromResource(R.xml.pref_interface);
|
||||
addPreferencesFromResource(R.xml.pref_notification);
|
||||
addPreferencesFromResource(R.xml.pref_now_playing);
|
||||
addPreferencesFromResource(R.xml.pref_lock_screen);
|
||||
addPreferencesFromResource(R.xml.pref_playback);
|
||||
addPreferencesFromResource(R.xml.pref_cache);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DialogFragment onCreatePreferenceDialog(Preference preference) {
|
||||
if (preference instanceof NowPlayingScreenPreference) {
|
||||
return NowPlayingScreenPreferenceDialog.newInstance();
|
||||
} else if (preference instanceof CategoryPreference) {
|
||||
return CategoryPreferenceDialog.newInstance();
|
||||
} else if (preference instanceof DirectPlayPreference) {
|
||||
return DirectPlayPreferenceDialog.newInstance();
|
||||
}
|
||||
|
||||
return super.onCreatePreferenceDialog(preference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
getListView().setPadding(0, 0, 0, 0);
|
||||
invalidateSettings();
|
||||
PreferenceUtil.getInstance(getActivity()).registerOnSharedPreferenceChangedListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
PreferenceUtil.getInstance(getActivity()).unregisterOnSharedPreferenceChangedListener(this);
|
||||
}
|
||||
|
||||
private void invalidateSettings() {
|
||||
final Preference generalTheme = findPreference(PreferenceUtil.GENERAL_THEME);
|
||||
setSummary(generalTheme);
|
||||
generalTheme.setOnPreferenceChangeListener((preference, o) -> {
|
||||
String themeName = (String) o;
|
||||
setSummary(generalTheme, o);
|
||||
|
||||
ThemeStore.markChanged(requireActivity());
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||
// set the new theme so that updateAppShortcuts can pull it
|
||||
requireActivity().setTheme(PreferenceUtil.getThemeResource(themeName));
|
||||
new DynamicShortcutManager(getActivity()).updateDynamicShortcuts();
|
||||
}
|
||||
|
||||
requireActivity().recreate();
|
||||
return true;
|
||||
});
|
||||
|
||||
final ATEColorPreference primaryColorPref = findPreference(PreferenceUtil.PRIMARY_COLOR);
|
||||
final int primaryColor = ThemeStore.primaryColor(requireActivity());
|
||||
primaryColorPref.setColor(primaryColor, ColorUtil.darkenColor(primaryColor));
|
||||
primaryColorPref.setOnPreferenceClickListener(preference -> {
|
||||
new ColorChooserDialog.Builder(requireActivity(), R.string.pref_title_primary_color)
|
||||
.accentMode(false)
|
||||
.allowUserColorInput(true)
|
||||
.allowUserColorInputAlpha(false)
|
||||
.preselect(primaryColor)
|
||||
.show(requireActivity());
|
||||
return true;
|
||||
});
|
||||
|
||||
final ATEColorPreference accentColorPref = findPreference(PreferenceUtil.ACCENT_COLOR);
|
||||
final int accentColor = ThemeStore.accentColor(requireActivity());
|
||||
accentColorPref.setColor(accentColor, ColorUtil.darkenColor(accentColor));
|
||||
accentColorPref.setOnPreferenceClickListener(preference -> {
|
||||
new ColorChooserDialog.Builder(requireActivity(), R.string.pref_title_accent_color)
|
||||
.accentMode(true)
|
||||
.allowUserColorInput(true)
|
||||
.allowUserColorInputAlpha(false)
|
||||
.preselect(accentColor)
|
||||
.show(requireActivity());
|
||||
return true;
|
||||
});
|
||||
|
||||
final TwoStatePreference classicNotification = findPreference(PreferenceUtil.CLASSIC_NOTIFICATION);
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||
classicNotification.setVisible(false);
|
||||
} else {
|
||||
classicNotification.setChecked(PreferenceUtil.getInstance(getActivity()).getClassicNotification());
|
||||
classicNotification.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
PreferenceUtil.getInstance(getActivity()).setClassicNotification((Boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
final TwoStatePreference coloredNotification = findPreference(PreferenceUtil.COLORED_NOTIFICATION);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
coloredNotification.setEnabled(PreferenceUtil.getInstance(getActivity()).getClassicNotification());
|
||||
} else {
|
||||
coloredNotification.setChecked(PreferenceUtil.getInstance(getActivity()).getColoredNotification());
|
||||
coloredNotification.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
PreferenceUtil.getInstance(getActivity()).setColoredNotification((Boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
final TwoStatePreference colorAppShortcuts = findPreference(PreferenceUtil.COLORED_SHORTCUTS);
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) {
|
||||
colorAppShortcuts.setVisible(false);
|
||||
} else {
|
||||
colorAppShortcuts.setChecked(PreferenceUtil.getInstance(getActivity()).getColoredShortcuts());
|
||||
colorAppShortcuts.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
PreferenceUtil.getInstance(getActivity()).setColoredShortcuts((Boolean) newValue);
|
||||
|
||||
// update app shortcuts
|
||||
new DynamicShortcutManager(getActivity()).updateDynamicShortcuts();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
updateNowPlayingScreenSummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
switch (key) {
|
||||
case PreferenceUtil.NOW_PLAYING_SCREEN:
|
||||
updateNowPlayingScreenSummary();
|
||||
break;
|
||||
case PreferenceUtil.CLASSIC_NOTIFICATION:
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
findPreference(PreferenceUtil.COLORED_NOTIFICATION).setEnabled(sharedPreferences.getBoolean(key, false));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateNowPlayingScreenSummary() {
|
||||
findPreference(PreferenceUtil.NOW_PLAYING_SCREEN).setSummary(PreferenceUtil.getInstance(getActivity()).getNowPlayingScreen().titleRes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
package com.dkanada.gramophone.activities;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.dkanada.gramophone.App;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.activities.base.AbsBaseActivity;
|
||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
|
||||
import org.jellyfin.apiclient.interaction.EmptyResponse;
|
||||
import org.jellyfin.apiclient.interaction.Response;
|
||||
import org.jellyfin.apiclient.model.session.ClientCapabilities;
|
||||
import org.jellyfin.apiclient.model.system.SystemInfo;
|
||||
|
||||
public class SplashActivity extends AbsBaseActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_splash);
|
||||
setDrawUnderStatusbar();
|
||||
|
||||
setStatusbarColorAuto();
|
||||
setNavigationbarColorAuto();
|
||||
setTaskDescriptionColorAuto();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
overridePendingTransition(0, R.anim.fade_delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && detectBatteryOptimization()) {
|
||||
showBatteryOptimizationDialog();
|
||||
} else {
|
||||
login();
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private boolean detectBatteryOptimization() {
|
||||
String packageName = getPackageName();
|
||||
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
|
||||
return !pm.isIgnoringBatteryOptimizations(packageName);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private void showBatteryOptimizationDialog() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(SplashActivity.this);
|
||||
builder.setMessage(R.string.battery_optimizations_message)
|
||||
.setTitle(R.string.battery_optimizations_title)
|
||||
.setNegativeButton(R.string.ignore, (dialog, id) -> login())
|
||||
.setPositiveButton(R.string.disable, (dialog, id) -> openPowerSettings())
|
||||
.show();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private void openPowerSettings() {
|
||||
Intent intent = new Intent();
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
public void login() {
|
||||
if (PreferenceUtil.getInstance(this).getToken() == null) {
|
||||
launchLoginActivity();
|
||||
} else {
|
||||
final Context context = this;
|
||||
|
||||
App.getApiClient().ChangeServerLocation(PreferenceUtil.getInstance(this).getServer());
|
||||
App.getApiClient().SetAuthenticationInfo(PreferenceUtil.getInstance(this).getToken(), PreferenceUtil.getInstance(this).getUser());
|
||||
App.getApiClient().GetSystemInfoAsync(new Response<SystemInfo>() {
|
||||
@Override
|
||||
public void onResponse(SystemInfo result) {
|
||||
ClientCapabilities clientCapabilities = new ClientCapabilities();
|
||||
clientCapabilities.setSupportsMediaControl(true);
|
||||
clientCapabilities.setSupportsPersistentIdentifier(true);
|
||||
|
||||
App.getApiClient().ensureWebSocket();
|
||||
App.getApiClient().ReportCapabilities(clientCapabilities, new EmptyResponse());
|
||||
|
||||
Intent intent = new Intent(context, MainActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
launchLoginActivity();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void launchLoginActivity() {
|
||||
Intent intent = new Intent(this, LoginActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
package com.dkanada.gramophone.activities.base;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
|
||||
import com.kabouzeid.appthemehelper.ThemeStore;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
public abstract class AbsBaseActivity extends AbsThemeActivity {
|
||||
public static final int PERMISSION_REQUEST = 100;
|
||||
|
||||
private boolean hadPermissions;
|
||||
private String[] permissions;
|
||||
private String permissionDeniedMessage;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||
|
||||
permissions = getPermissionsToRequest();
|
||||
hadPermissions = hasPermissions();
|
||||
|
||||
setPermissionDeniedMessage(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
if (!hasPermissions()) {
|
||||
requestPermissions();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
final boolean hasPermissions = hasPermissions();
|
||||
if (hasPermissions != hadPermissions) {
|
||||
hadPermissions = hasPermissions;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
onHasPermissionsChanged(hasPermissions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onHasPermissionsChanged(boolean hasPermissions) {
|
||||
// implemented by sub classes
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(@NonNull KeyEvent event) {
|
||||
if (event.getKeyCode() == KeyEvent.KEYCODE_MENU && event.getAction() == KeyEvent.ACTION_UP) {
|
||||
showOverflowMenu();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
protected void showOverflowMenu() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected String[] getPermissionsToRequest() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected View getSnackBarContainer() {
|
||||
return getWindow().getDecorView();
|
||||
}
|
||||
|
||||
protected void setPermissionDeniedMessage(String message) {
|
||||
permissionDeniedMessage = message;
|
||||
}
|
||||
|
||||
private String getPermissionDeniedMessage() {
|
||||
return permissionDeniedMessage == null ? getString(R.string.permissions_denied) : permissionDeniedMessage;
|
||||
}
|
||||
|
||||
protected void requestPermissions() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && permissions != null) {
|
||||
requestPermissions(permissions, PERMISSION_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean hasPermissions() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && permissions != null) {
|
||||
for (String permission : permissions) {
|
||||
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == PERMISSION_REQUEST) {
|
||||
for (int grantResult : grantResults) {
|
||||
if (grantResult != PackageManager.PERMISSION_GRANTED) {
|
||||
if (ActivityCompat.shouldShowRequestPermissionRationale(AbsBaseActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
// user has deny from permission dialog
|
||||
Snackbar.make(getSnackBarContainer(), getPermissionDeniedMessage(),
|
||||
Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(R.string.action_grant, view -> requestPermissions())
|
||||
.setActionTextColor(ThemeStore.accentColor(this))
|
||||
.show();
|
||||
} else {
|
||||
// user has deny permission and checked never show permission dialog so you can redirect to application settings page
|
||||
Snackbar.make(getSnackBarContainer(), getPermissionDeniedMessage(),
|
||||
Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(R.string.action_settings, view -> {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
Uri uri = Uri.fromParts("package", AbsBaseActivity.this.getPackageName(), null);
|
||||
intent.setData(uri);
|
||||
startActivity(intent);
|
||||
})
|
||||
.setActionTextColor(ThemeStore.accentColor(this))
|
||||
.show();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
hadPermissions = true;
|
||||
onHasPermissionsChanged(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
package com.dkanada.gramophone.activities.base;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.helper.MusicPlayerRemote;
|
||||
import com.dkanada.gramophone.interfaces.MusicServiceEventListener;
|
||||
import com.dkanada.gramophone.service.MusicService;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class AbsMusicServiceActivity extends AbsBaseActivity implements MusicServiceEventListener {
|
||||
private final List<MusicServiceEventListener> mMusicServiceEventListeners = new ArrayList<>();
|
||||
|
||||
private MusicPlayerRemote.ServiceToken serviceToken;
|
||||
private MusicStateReceiver musicStateReceiver;
|
||||
|
||||
private boolean receiverRegistered;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
serviceToken = MusicPlayerRemote.bindToService(this, new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
AbsMusicServiceActivity.this.onServiceConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
AbsMusicServiceActivity.this.onServiceDisconnected();
|
||||
}
|
||||
});
|
||||
|
||||
setPermissionDeniedMessage(getString(R.string.permission_external_storage_denied));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
MusicPlayerRemote.unbindFromService(serviceToken);
|
||||
if (receiverRegistered) {
|
||||
unregisterReceiver(musicStateReceiver);
|
||||
receiverRegistered = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void addMusicServiceEventListener(final MusicServiceEventListener listener) {
|
||||
if (listener != null) {
|
||||
mMusicServiceEventListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeMusicServiceEventListener(final MusicServiceEventListener listener) {
|
||||
if (listener != null) {
|
||||
mMusicServiceEventListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
if (!receiverRegistered) {
|
||||
musicStateReceiver = new MusicStateReceiver(this);
|
||||
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(MusicService.STATE_CHANGED);
|
||||
filter.addAction(MusicService.SHUFFLE_MODE_CHANGED);
|
||||
filter.addAction(MusicService.REPEAT_MODE_CHANGED);
|
||||
filter.addAction(MusicService.META_CHANGED);
|
||||
filter.addAction(MusicService.QUEUE_CHANGED);
|
||||
|
||||
registerReceiver(musicStateReceiver, filter);
|
||||
|
||||
receiverRegistered = true;
|
||||
}
|
||||
|
||||
for (MusicServiceEventListener listener : mMusicServiceEventListeners) {
|
||||
if (listener != null) {
|
||||
listener.onServiceConnected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected() {
|
||||
if (receiverRegistered) {
|
||||
unregisterReceiver(musicStateReceiver);
|
||||
receiverRegistered = false;
|
||||
}
|
||||
|
||||
for (MusicServiceEventListener listener : mMusicServiceEventListeners) {
|
||||
if (listener != null) {
|
||||
listener.onServiceDisconnected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayMetadataChanged() {
|
||||
for (MusicServiceEventListener listener : mMusicServiceEventListeners) {
|
||||
if (listener != null) {
|
||||
listener.onPlayMetadataChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueueChanged() {
|
||||
for (MusicServiceEventListener listener : mMusicServiceEventListeners) {
|
||||
if (listener != null) {
|
||||
listener.onQueueChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayStateChanged() {
|
||||
for (MusicServiceEventListener listener : mMusicServiceEventListeners) {
|
||||
if (listener != null) {
|
||||
listener.onPlayStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepeatModeChanged() {
|
||||
for (MusicServiceEventListener listener : mMusicServiceEventListeners) {
|
||||
if (listener != null) {
|
||||
listener.onRepeatModeChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShuffleModeChanged() {
|
||||
for (MusicServiceEventListener listener : mMusicServiceEventListeners) {
|
||||
if (listener != null) {
|
||||
listener.onShuffleModeChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MusicStateReceiver extends BroadcastReceiver {
|
||||
|
||||
private final WeakReference<AbsMusicServiceActivity> reference;
|
||||
|
||||
public MusicStateReceiver(final AbsMusicServiceActivity activity) {
|
||||
reference = new WeakReference<>(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, @NonNull final Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
AbsMusicServiceActivity activity = reference.get();
|
||||
if (activity != null && action != null) {
|
||||
switch (action) {
|
||||
case MusicService.META_CHANGED:
|
||||
activity.onPlayMetadataChanged();
|
||||
break;
|
||||
case MusicService.QUEUE_CHANGED:
|
||||
activity.onQueueChanged();
|
||||
break;
|
||||
case MusicService.STATE_CHANGED:
|
||||
activity.onPlayStateChanged();
|
||||
break;
|
||||
case MusicService.REPEAT_MODE_CHANGED:
|
||||
activity.onRepeatModeChanged();
|
||||
break;
|
||||
case MusicService.SHUFFLE_MODE_CHANGED:
|
||||
activity.onShuffleModeChanged();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHasPermissionsChanged(boolean hasPermissions) {
|
||||
// TODO is this method even required
|
||||
super.onHasPermissionsChanged(hasPermissions);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected String[] getPermissionsToRequest() {
|
||||
return new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,297 @@
|
|||
package com.dkanada.gramophone.activities.base;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.animation.PathInterpolator;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.FloatRange;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.dkanada.gramophone.App;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.databinding.SlidingMusicPanelLayoutBinding;
|
||||
import com.dkanada.gramophone.helper.MusicPlayerRemote;
|
||||
import com.dkanada.gramophone.activities.SplashActivity;
|
||||
import com.dkanada.gramophone.ui.fragments.player.AbsPlayerFragment;
|
||||
import com.dkanada.gramophone.ui.fragments.player.MiniPlayerFragment;
|
||||
import com.dkanada.gramophone.ui.fragments.player.NowPlayingScreen;
|
||||
import com.dkanada.gramophone.ui.fragments.player.card.CardPlayerFragment;
|
||||
import com.dkanada.gramophone.ui.fragments.player.flat.FlatPlayerFragment;
|
||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
import com.dkanada.gramophone.util.ViewUtil;
|
||||
import com.sothree.slidinguppanel.SlidingUpPanelLayout;
|
||||
|
||||
public abstract class AbsSlidingMusicPanelActivity extends AbsMusicServiceActivity implements SlidingUpPanelLayout.PanelSlideListener, CardPlayerFragment.Callbacks {
|
||||
private SlidingMusicPanelLayoutBinding binding;
|
||||
|
||||
private int navigationbarColor;
|
||||
private int taskColor;
|
||||
private boolean lightStatusbar;
|
||||
|
||||
private NowPlayingScreen currentNowPlayingScreen;
|
||||
private AbsPlayerFragment playerFragment;
|
||||
private MiniPlayerFragment miniPlayerFragment;
|
||||
private ValueAnimator navigationBarColorAnimator;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(createContentView());
|
||||
|
||||
// TODO use a fragment for the splash activity
|
||||
if (App.getApiClient() == null) {
|
||||
Intent intent = new Intent(this, SplashActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
currentNowPlayingScreen = PreferenceUtil.getInstance(this).getNowPlayingScreen();
|
||||
|
||||
// must implement AbsPlayerFragment
|
||||
Fragment fragment;
|
||||
switch (currentNowPlayingScreen) {
|
||||
case FLAT:
|
||||
fragment = new FlatPlayerFragment();
|
||||
break;
|
||||
case CARD:
|
||||
default:
|
||||
fragment = new CardPlayerFragment();
|
||||
break;
|
||||
}
|
||||
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.player_fragment_container, fragment).commit();
|
||||
getSupportFragmentManager().executePendingTransactions();
|
||||
|
||||
playerFragment = (AbsPlayerFragment) getSupportFragmentManager().findFragmentById(R.id.player_fragment_container);
|
||||
miniPlayerFragment = (MiniPlayerFragment) getSupportFragmentManager().findFragmentById(R.id.mini_player_fragment);
|
||||
|
||||
// noinspection ConstantConditions
|
||||
miniPlayerFragment.getView().setOnClickListener(v -> expandPanel());
|
||||
|
||||
binding.slidingLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
binding.slidingLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
|
||||
switch (getPanelState()) {
|
||||
case EXPANDED:
|
||||
onPanelSlide(binding.slidingLayout, 1);
|
||||
onPanelExpanded(binding.slidingLayout);
|
||||
break;
|
||||
case COLLAPSED:
|
||||
onPanelCollapsed(binding.slidingLayout);
|
||||
break;
|
||||
default:
|
||||
playerFragment.onHide();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
binding.slidingLayout.addPanelSlideListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
if (currentNowPlayingScreen != PreferenceUtil.getInstance(this).getNowPlayingScreen()) {
|
||||
postRecreate();
|
||||
}
|
||||
}
|
||||
|
||||
public void setAntiDragView(View antiDragView) {
|
||||
binding.slidingLayout.setAntiDragView(antiDragView);
|
||||
}
|
||||
|
||||
protected abstract View createContentView();
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
super.onServiceConnected();
|
||||
|
||||
// don't call hideBottomBar(true) here as it causes a bug with the SlidingUpPanelLayout
|
||||
if (!MusicPlayerRemote.getPlayingQueue().isEmpty()) {
|
||||
binding.slidingLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
binding.slidingLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
hideBottomBar(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueueChanged() {
|
||||
super.onQueueChanged();
|
||||
hideBottomBar(MusicPlayerRemote.getPlayingQueue().isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelSlide(View panel, @FloatRange(from = 0, to = 1) float slideOffset) {
|
||||
setMiniPlayerAlphaProgress(slideOffset);
|
||||
if (navigationBarColorAnimator != null) navigationBarColorAnimator.cancel();
|
||||
super.setNavigationbarColor(ColorUtils.blendARGB(navigationbarColor, playerFragment.getPaletteColor(), slideOffset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelStateChanged(View panel, SlidingUpPanelLayout.PanelState previousState, SlidingUpPanelLayout.PanelState newState) {
|
||||
switch (newState) {
|
||||
case COLLAPSED:
|
||||
onPanelCollapsed(panel);
|
||||
break;
|
||||
case EXPANDED:
|
||||
onPanelExpanded(panel);
|
||||
break;
|
||||
case ANCHORED:
|
||||
// this fixes a bug where the panel would get stuck for some reason
|
||||
collapsePanel();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void onPanelCollapsed(View panel) {
|
||||
// restore values
|
||||
super.setLightStatusbar(lightStatusbar);
|
||||
super.setTaskDescriptionColor(taskColor);
|
||||
super.setNavigationbarColor(navigationbarColor);
|
||||
|
||||
playerFragment.setMenuVisibility(false);
|
||||
playerFragment.setUserVisibleHint(false);
|
||||
playerFragment.onHide();
|
||||
}
|
||||
|
||||
public void onPanelExpanded(View panel) {
|
||||
// setting fragments values
|
||||
int playerFragmentColor = playerFragment.getPaletteColor();
|
||||
super.setLightStatusbar(false);
|
||||
super.setTaskDescriptionColor(playerFragmentColor);
|
||||
super.setNavigationbarColor(playerFragmentColor);
|
||||
|
||||
playerFragment.setMenuVisibility(true);
|
||||
playerFragment.setUserVisibleHint(true);
|
||||
playerFragment.onShow();
|
||||
}
|
||||
|
||||
private void setMiniPlayerAlphaProgress(@FloatRange(from = 0, to = 1) float progress) {
|
||||
if (miniPlayerFragment.getView() == null) return;
|
||||
float alpha = 1 - progress;
|
||||
miniPlayerFragment.getView().setAlpha(alpha);
|
||||
// necessary to make the views below clickable
|
||||
miniPlayerFragment.getView().setVisibility(alpha == 0 ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
|
||||
public SlidingUpPanelLayout.PanelState getPanelState() {
|
||||
return binding.slidingLayout.getPanelState();
|
||||
}
|
||||
|
||||
public void collapsePanel() {
|
||||
binding.slidingLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
|
||||
}
|
||||
|
||||
public void expandPanel() {
|
||||
binding.slidingLayout.setPanelState(SlidingUpPanelLayout.PanelState.EXPANDED);
|
||||
}
|
||||
|
||||
public void hideBottomBar(final boolean hide) {
|
||||
if (hide) {
|
||||
binding.slidingLayout.setPanelHeight(0);
|
||||
collapsePanel();
|
||||
} else {
|
||||
binding.slidingLayout.setPanelHeight(getResources().getDimensionPixelSize(R.dimen.mini_player_height));
|
||||
}
|
||||
}
|
||||
|
||||
protected View wrapSlidingMusicPanel(View view) {
|
||||
binding = SlidingMusicPanelLayoutBinding.inflate(getLayoutInflater());
|
||||
|
||||
ViewGroup contentContainer = binding.contentContainer;
|
||||
contentContainer.addView(view);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (!handleBackPress()) super.onBackPressed();
|
||||
}
|
||||
|
||||
public boolean handleBackPress() {
|
||||
if (binding.slidingLayout.getPanelHeight() != 0 && playerFragment.onBackPressed())
|
||||
return true;
|
||||
if (getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) {
|
||||
collapsePanel();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPaletteColorChanged() {
|
||||
if (getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) {
|
||||
int playerFragmentColor = playerFragment.getPaletteColor();
|
||||
super.setTaskDescriptionColor(playerFragmentColor);
|
||||
animateNavigationBarColor(playerFragmentColor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightStatusbar(boolean enabled) {
|
||||
lightStatusbar = enabled;
|
||||
if (getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
|
||||
super.setLightStatusbar(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNavigationbarColor(int color) {
|
||||
this.navigationbarColor = color;
|
||||
if (getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
|
||||
if (navigationBarColorAnimator != null) navigationBarColorAnimator.cancel();
|
||||
super.setNavigationbarColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
private void animateNavigationBarColor(int color) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (navigationBarColorAnimator != null) navigationBarColorAnimator.cancel();
|
||||
navigationBarColorAnimator = ValueAnimator
|
||||
.ofArgb(getWindow().getNavigationBarColor(), color)
|
||||
.setDuration(ViewUtil.PHONOGRAPH_ANIM_TIME);
|
||||
|
||||
navigationBarColorAnimator.setInterpolator(new PathInterpolator(0.4f, 0f, 1f, 1f));
|
||||
navigationBarColorAnimator.addUpdateListener(animation -> AbsSlidingMusicPanelActivity.super.setNavigationbarColor((Integer) animation.getAnimatedValue()));
|
||||
navigationBarColorAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (navigationBarColorAnimator != null) navigationBarColorAnimator.cancel(); // just in case
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTaskDescriptionColor(@ColorInt int color) {
|
||||
this.taskColor = color;
|
||||
if (getPanelState() == null || getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
|
||||
super.setTaskDescriptionColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View getSnackBarContainer() {
|
||||
return findViewById(R.id.content_container);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package com.dkanada.gramophone.activities.base;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
|
||||
import com.kabouzeid.appthemehelper.ATH;
|
||||
import com.kabouzeid.appthemehelper.ThemeStore;
|
||||
import com.kabouzeid.appthemehelper.common.ATHToolbarActivity;
|
||||
import com.kabouzeid.appthemehelper.util.ColorUtil;
|
||||
import com.kabouzeid.appthemehelper.util.MaterialDialogsUtil;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
import com.dkanada.gramophone.util.Util;
|
||||
|
||||
public abstract class AbsThemeActivity extends ATHToolbarActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(PreferenceUtil.getInstance(this).getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
MaterialDialogsUtil.updateMaterialDialogsThemeSingleton(this);
|
||||
|
||||
if (!ThemeStore.coloredNavigationBar(this)) {
|
||||
ThemeStore.editTheme(this).coloredNavigationBar(true).commit();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setDrawUnderStatusbar() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Util.setAllowDrawUnderStatusBar(getWindow());
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
Util.setStatusBarTranslucent(getWindow());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will set the color of the view with the id "status_bar" on KitKat and Lollipop.
|
||||
* On Lollipop if no such view is found it will set the statusbar color using the native method.
|
||||
*
|
||||
* @param color the new statusbar color (will be shifted down on Lollipop and above)
|
||||
*/
|
||||
public void setStatusbarColor(int color) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
final View statusBar = getWindow().getDecorView().getRootView().findViewById(R.id.status_bar);
|
||||
if (statusBar != null) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
statusBar.setBackgroundColor(ColorUtil.darkenColor(color));
|
||||
setLightStatusbarAuto(color);
|
||||
} else {
|
||||
statusBar.setBackgroundColor(color);
|
||||
}
|
||||
} else if (Build.VERSION.SDK_INT >= 21) {
|
||||
getWindow().setStatusBarColor(ColorUtil.darkenColor(color));
|
||||
setLightStatusbarAuto(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setStatusbarColorAuto() {
|
||||
// we don't want to use status bar color because we are darkening the color on our own to support KitKat
|
||||
setStatusbarColor(ThemeStore.primaryColor(this));
|
||||
}
|
||||
|
||||
public void setTaskDescriptionColor(@ColorInt int color) {
|
||||
ATH.setTaskDescriptionColor(this, color);
|
||||
}
|
||||
|
||||
public void setTaskDescriptionColorAuto() {
|
||||
setTaskDescriptionColor(ThemeStore.primaryColor(this));
|
||||
}
|
||||
|
||||
public void setNavigationbarColor(int color) {
|
||||
ATH.setNavigationbarColor(this, color);
|
||||
}
|
||||
|
||||
public void setNavigationbarColorAuto() {
|
||||
setNavigationbarColor(ThemeStore.navigationBarColor(this));
|
||||
}
|
||||
|
||||
public void setLightStatusbar(boolean enabled) {
|
||||
ATH.setLightStatusbar(this, enabled);
|
||||
}
|
||||
|
||||
public void setLightStatusbarAuto(int bgColor) {
|
||||
setLightStatusbar(ColorUtil.isColorLight(bgColor));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,270 @@
|
|||
package com.dkanada.gramophone.activities.details;
|
||||
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.afollestad.materialcab.MaterialCab;
|
||||
import com.afollestad.materialdialogs.util.DialogUtils;
|
||||
import com.dkanada.gramophone.databinding.ActivityAlbumDetailBinding;
|
||||
import com.google.android.material.appbar.AppBarLayout;
|
||||
import com.kabouzeid.appthemehelper.util.ColorUtil;
|
||||
import com.kabouzeid.appthemehelper.util.MaterialValueHelper;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.adapter.song.AlbumSongAdapter;
|
||||
import com.dkanada.gramophone.dialogs.AddToPlaylistDialog;
|
||||
import com.dkanada.gramophone.dialogs.SleepTimerDialog;
|
||||
import com.dkanada.gramophone.glide.CustomGlideRequest;
|
||||
import com.dkanada.gramophone.glide.CustomPaletteTarget;
|
||||
import com.dkanada.gramophone.helper.MusicPlayerRemote;
|
||||
import com.dkanada.gramophone.interfaces.CabHolder;
|
||||
import com.dkanada.gramophone.interfaces.MediaCallback;
|
||||
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.activities.base.AbsSlidingMusicPanelActivity;
|
||||
import com.dkanada.gramophone.util.MusicUtil;
|
||||
import com.dkanada.gramophone.util.NavigationUtil;
|
||||
import com.dkanada.gramophone.util.ThemeUtil;
|
||||
import com.dkanada.gramophone.util.QueryUtil;
|
||||
|
||||
import org.jellyfin.apiclient.model.querying.ItemQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AlbumDetailActivity extends AbsSlidingMusicPanelActivity implements PaletteColorHolder, CabHolder, AppBarLayout.OnOffsetChangedListener {
|
||||
public static final String EXTRA_ALBUM = "extra_album";
|
||||
|
||||
private ActivityAlbumDetailBinding binding;
|
||||
|
||||
private MaterialCab cab;
|
||||
private int headerViewHeight;
|
||||
private int toolbarColor;
|
||||
|
||||
private Album album;
|
||||
private AlbumSongAdapter adapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setDrawUnderStatusbar();
|
||||
setUpObservableListViewParams();
|
||||
setUpToolbar();
|
||||
setUpViews();
|
||||
|
||||
Album album = getIntent().getExtras().getParcelable(EXTRA_ALBUM);
|
||||
loadAlbumCover(album);
|
||||
setAlbum(album);
|
||||
|
||||
ItemQuery query = new ItemQuery();
|
||||
query.setParentId(album.id);
|
||||
query.setSortBy(new String[]{"ParentIndexNumber", "IndexNumber"});
|
||||
|
||||
QueryUtil.getSongs(query, new MediaCallback() {
|
||||
@Override
|
||||
public void onLoadMedia(List<?> media) {
|
||||
album.songs = (List<Song>) media;
|
||||
setAlbum(album);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOffsetChanged (AppBarLayout appBarLayout, int verticalOffset) {
|
||||
float headerAlpha = Math.max(0, Math.min(1, 1 + (2 * (float) verticalOffset / headerViewHeight)));
|
||||
binding.header.setAlpha(headerAlpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View createContentView() {
|
||||
binding = ActivityAlbumDetailBinding.inflate(getLayoutInflater());
|
||||
|
||||
return wrapSlidingMusicPanel(binding.getRoot());
|
||||
}
|
||||
|
||||
private void setUpObservableListViewParams() {
|
||||
headerViewHeight = getResources().getDimensionPixelSize(R.dimen.detail_header_height);
|
||||
}
|
||||
|
||||
private void setUpViews() {
|
||||
setUpRecyclerView();
|
||||
setUpSongsAdapter();
|
||||
binding.artistText.setOnClickListener(v -> {
|
||||
if (album != null) {
|
||||
NavigationUtil.goToArtist(AlbumDetailActivity.this, new Artist(album));
|
||||
}
|
||||
});
|
||||
|
||||
setColors(DialogUtils.resolveColor(this, R.attr.defaultFooterColor));
|
||||
}
|
||||
|
||||
private void loadAlbumCover(Album album) {
|
||||
CustomGlideRequest.Builder
|
||||
.from(this, album.primary, album.blurHash)
|
||||
.palette().build().dontAnimate()
|
||||
.into(new CustomPaletteTarget(binding.image) {
|
||||
@Override
|
||||
public void onColorReady(int color) {
|
||||
setColors(color);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setColors(int color) {
|
||||
toolbarColor = color;
|
||||
binding.appBarLayout.setBackgroundColor(color);
|
||||
|
||||
setNavigationbarColor(color);
|
||||
setTaskDescriptionColor(color);
|
||||
|
||||
binding.toolbar.setBackgroundColor(color);
|
||||
// needed to auto readjust the toolbar content color
|
||||
setSupportActionBar(binding.toolbar);
|
||||
setStatusbarColor(color);
|
||||
|
||||
int secondaryTextColor = MaterialValueHelper.getSecondaryTextColor(this, ColorUtil.isColorLight(color));
|
||||
binding.artistIcon.setColorFilter(secondaryTextColor, PorterDuff.Mode.SRC_IN);
|
||||
binding.durationIcon.setColorFilter(secondaryTextColor, PorterDuff.Mode.SRC_IN);
|
||||
binding.songCountIcon.setColorFilter(secondaryTextColor, PorterDuff.Mode.SRC_IN);
|
||||
binding.albumYearIcon.setColorFilter(secondaryTextColor, PorterDuff.Mode.SRC_IN);
|
||||
|
||||
binding.artistText.setTextColor(MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(color)));
|
||||
binding.durationText.setTextColor(secondaryTextColor);
|
||||
binding.songCountText.setTextColor(secondaryTextColor);
|
||||
binding.albumYearText.setTextColor(secondaryTextColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPaletteColor() {
|
||||
return toolbarColor;
|
||||
}
|
||||
|
||||
private void setUpRecyclerView() {
|
||||
binding.appBarLayout.addOnOffsetChangedListener(this);
|
||||
}
|
||||
|
||||
private void setUpToolbar() {
|
||||
setSupportActionBar(binding.toolbar);
|
||||
// noinspection ConstantConditions
|
||||
getSupportActionBar().setTitle(null);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
private void setUpSongsAdapter() {
|
||||
adapter = new AlbumSongAdapter(this, getAlbum().songs, R.layout.item_list, false, this);
|
||||
binding.list.setLayoutManager(new GridLayoutManager(this, 1));
|
||||
binding.list.setAdapter(adapter);
|
||||
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
if (adapter.getItemCount() == 0) finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_album_detail, menu);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
final List<Song> songs = adapter.getDataSet();
|
||||
switch (id) {
|
||||
case R.id.action_sleep_timer:
|
||||
new SleepTimerDialog().show(getSupportFragmentManager(), "SET_SLEEP_TIMER");
|
||||
return true;
|
||||
case R.id.action_shuffle_album:
|
||||
MusicPlayerRemote.openAndShuffleQueue(songs, true);
|
||||
return true;
|
||||
case R.id.action_play_next:
|
||||
MusicPlayerRemote.playNext(songs);
|
||||
return true;
|
||||
case R.id.action_add_to_queue:
|
||||
MusicPlayerRemote.enqueue(songs);
|
||||
return true;
|
||||
case R.id.action_add_to_playlist:
|
||||
AddToPlaylistDialog.create(songs).show(getSupportFragmentManager(), "ADD_PLAYLIST");
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
super.onBackPressed();
|
||||
return true;
|
||||
case R.id.action_go_to_artist:
|
||||
NavigationUtil.goToArtist(this, new Artist(album));
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MaterialCab openCab(int menuRes, @NonNull final MaterialCab.Callback callback) {
|
||||
if (cab != null && cab.isActive()) cab.finish();
|
||||
cab = new MaterialCab(this, R.id.cab_stub)
|
||||
.setMenu(menuRes)
|
||||
.setCloseDrawableRes(R.drawable.ic_close_white_24dp)
|
||||
.setBackgroundColor(ThemeUtil.shiftBackgroundColorForLightText(getPaletteColor()))
|
||||
.start(new MaterialCab.Callback() {
|
||||
@Override
|
||||
public boolean onCabCreated(MaterialCab materialCab, Menu menu) {
|
||||
return callback.onCabCreated(materialCab, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCabItemClicked(MenuItem menuItem) {
|
||||
return callback.onCabItemClicked(menuItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCabFinished(MaterialCab materialCab) {
|
||||
return callback.onCabFinished(materialCab);
|
||||
}
|
||||
});
|
||||
return cab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (cab != null && cab.isActive()) {
|
||||
cab.finish();
|
||||
} else {
|
||||
binding.list.stopScroll();
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatusbarColor(int color) {
|
||||
super.setStatusbarColor(color);
|
||||
setLightStatusbar(false);
|
||||
}
|
||||
|
||||
private void setAlbum(Album album) {
|
||||
this.album = album;
|
||||
|
||||
getSupportActionBar().setTitle(album.title);
|
||||
binding.artistText.setText(album.artistName);
|
||||
binding.songCountText.setText(MusicUtil.getSongCountString(this, album.songs.size()));
|
||||
binding.durationText.setText(MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(this, album.songs)));
|
||||
binding.albumYearText.setText(MusicUtil.getYearString(album.year));
|
||||
|
||||
if (album.songs.size() != 0) adapter.swapDataSet(album.songs);
|
||||
}
|
||||
|
||||
private Album getAlbum() {
|
||||
if (album == null) album = new Album();
|
||||
return album;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,297 @@
|
|||
package com.dkanada.gramophone.activities.details;
|
||||
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.afollestad.materialcab.MaterialCab;
|
||||
import com.afollestad.materialdialogs.util.DialogUtils;
|
||||
import com.dkanada.gramophone.adapter.song.SongAdapter;
|
||||
import com.dkanada.gramophone.databinding.ActivityArtistDetailBinding;
|
||||
import com.google.android.material.appbar.AppBarLayout;
|
||||
import com.kabouzeid.appthemehelper.util.ColorUtil;
|
||||
import com.kabouzeid.appthemehelper.util.MaterialValueHelper;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.adapter.album.HorizontalAlbumAdapter;
|
||||
import com.dkanada.gramophone.dialogs.AddToPlaylistDialog;
|
||||
import com.dkanada.gramophone.dialogs.SleepTimerDialog;
|
||||
import com.dkanada.gramophone.glide.CustomGlideRequest;
|
||||
import com.dkanada.gramophone.glide.CustomPaletteTarget;
|
||||
import com.dkanada.gramophone.helper.MusicPlayerRemote;
|
||||
import com.dkanada.gramophone.interfaces.CabHolder;
|
||||
import com.dkanada.gramophone.interfaces.MediaCallback;
|
||||
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.activities.base.AbsSlidingMusicPanelActivity;
|
||||
import com.dkanada.gramophone.util.MusicUtil;
|
||||
import com.dkanada.gramophone.util.ThemeUtil;
|
||||
import com.dkanada.gramophone.util.PreferenceUtil;
|
||||
import com.dkanada.gramophone.util.QueryUtil;
|
||||
|
||||
import org.jellyfin.apiclient.model.querying.ItemQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ArtistDetailActivity extends AbsSlidingMusicPanelActivity implements PaletteColorHolder, CabHolder, AppBarLayout.OnOffsetChangedListener {
|
||||
public static final String EXTRA_ARTIST = "extra_artist";
|
||||
|
||||
private ActivityArtistDetailBinding binding;
|
||||
|
||||
private MaterialCab cab;
|
||||
private int headerViewHeight;
|
||||
private int toolbarColor;
|
||||
|
||||
private Artist artist;
|
||||
private HorizontalAlbumAdapter albumAdapter;
|
||||
private SongAdapter songAdapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// must be loaded before album adapter
|
||||
usePalette = PreferenceUtil.getInstance(this).getAlbumArtistColoredFooters();
|
||||
|
||||
setDrawUnderStatusbar();
|
||||
setUpObservableListViewParams();
|
||||
setUpToolbar();
|
||||
setUpViews();
|
||||
|
||||
Artist artist = getIntent().getExtras().getParcelable(EXTRA_ARTIST);
|
||||
loadArtistImage(artist);
|
||||
setArtist(artist);
|
||||
|
||||
ItemQuery albums = new ItemQuery();
|
||||
albums.setArtistIds(new String[]{artist.id});
|
||||
QueryUtil.getAlbums(albums, new MediaCallback() {
|
||||
@Override
|
||||
public void onLoadMedia(List<?> media) {
|
||||
artist.albums = (List<Album>) media;
|
||||
setArtist(artist);
|
||||
}
|
||||
});
|
||||
|
||||
ItemQuery songs = new ItemQuery();
|
||||
songs.setArtistIds(new String[]{artist.id});
|
||||
QueryUtil.getSongs(songs, new MediaCallback() {
|
||||
@Override
|
||||
public void onLoadMedia(List<?> media) {
|
||||
artist.songs = (List<Song>) media;
|
||||
setArtist(artist);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
|
||||
float headerAlpha = Math.max(0, Math.min(1, 1 + (2 * (float) verticalOffset / headerViewHeight)));
|
||||
binding.header.setAlpha(headerAlpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View createContentView() {
|
||||
binding = ActivityArtistDetailBinding.inflate(getLayoutInflater());
|
||||
|
||||
return wrapSlidingMusicPanel(binding.getRoot());
|
||||
}
|
||||
|
||||
private boolean usePalette;
|
||||
|
||||
private void setUpObservableListViewParams() {
|
||||
headerViewHeight = getResources().getDimensionPixelSize(R.dimen.detail_header_height);
|
||||
}
|
||||
|
||||
private void setUpViews() {
|
||||
setUpSongListView();
|
||||
setUpAlbumRecyclerView();
|
||||
setColors(DialogUtils.resolveColor(this, R.attr.defaultFooterColor));
|
||||
}
|
||||
|
||||
private void setUpSongListView() {
|
||||
binding.appBarLayout.addOnOffsetChangedListener(this);
|
||||
|
||||
songAdapter = new SongAdapter(this, getArtist().songs, R.layout.item_list, false, this);
|
||||
|
||||
binding.songs.setLayoutManager(new GridLayoutManager(this, 1));
|
||||
binding.songs.setAdapter(songAdapter);
|
||||
|
||||
binding.scrollView.setRecyclerView(binding.songs);
|
||||
}
|
||||
|
||||
private void setUpAlbumRecyclerView() {
|
||||
binding.albums.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
|
||||
albumAdapter = new HorizontalAlbumAdapter(this, getArtist().albums, usePalette, this);
|
||||
binding.albums.setAdapter(albumAdapter);
|
||||
|
||||
// NestedScrollView will ignore horizontal RecyclerView without this line
|
||||
binding.albums.setNestedScrollingEnabled(false);
|
||||
|
||||
albumAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
if (albumAdapter.getItemCount() == 0) finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void setUsePalette(boolean usePalette) {
|
||||
albumAdapter.usePalette(usePalette);
|
||||
PreferenceUtil.getInstance(this).setAlbumArtistColoredFooters(usePalette);
|
||||
this.usePalette = usePalette;
|
||||
}
|
||||
|
||||
private void loadArtistImage(Artist artist) {
|
||||
CustomGlideRequest.Builder
|
||||
.from(this, artist.primary, artist.blurHash)
|
||||
.palette().build().dontAnimate()
|
||||
.into(new CustomPaletteTarget(binding.image) {
|
||||
@Override
|
||||
public void onColorReady(int color) {
|
||||
setColors(color);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPaletteColor() {
|
||||
return toolbarColor;
|
||||
}
|
||||
|
||||
private void setColors(int color) {
|
||||
toolbarColor = color;
|
||||
binding.appBarLayout.setBackgroundColor(color);
|
||||
|
||||
setNavigationbarColor(color);
|
||||
setTaskDescriptionColor(color);
|
||||
|
||||
binding.toolbar.setBackgroundColor(color);
|
||||
// needed to auto readjust the toolbar content color
|
||||
setSupportActionBar(binding.toolbar);
|
||||
setStatusbarColor(color);
|
||||
|
||||
int secondaryTextColor = MaterialValueHelper.getSecondaryTextColor(this, ColorUtil.isColorLight(color));
|
||||
binding.durationIcon.setColorFilter(secondaryTextColor, PorterDuff.Mode.SRC_IN);
|
||||
binding.songCountIcon.setColorFilter(secondaryTextColor, PorterDuff.Mode.SRC_IN);
|
||||
binding.albumCountIcon.setColorFilter(secondaryTextColor, PorterDuff.Mode.SRC_IN);
|
||||
|
||||
binding.durationText.setTextColor(secondaryTextColor);
|
||||
binding.songCountText.setTextColor(secondaryTextColor);
|
||||
binding.albumCountText.setTextColor(secondaryTextColor);
|
||||
}
|
||||
|
||||
private void setUpToolbar() {
|
||||
setSupportActionBar(binding.toolbar);
|
||||
// noinspection ConstantConditions
|
||||
getSupportActionBar().setTitle(null);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_artist_detail, menu);
|
||||
menu.findItem(R.id.action_colored_footers).setChecked(usePalette);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
final List<Song> songs = songAdapter.getDataSet();
|
||||
switch (id) {
|
||||
case R.id.action_sleep_timer:
|
||||
new SleepTimerDialog().show(getSupportFragmentManager(), "SET_SLEEP_TIMER");
|
||||
return true;
|
||||
case R.id.action_shuffle_artist:
|
||||
MusicPlayerRemote.openAndShuffleQueue(songs, true);
|
||||
return true;
|
||||
case R.id.action_play_next:
|
||||
MusicPlayerRemote.playNext(songs);
|
||||
return true;
|
||||
case R.id.action_add_to_queue:
|
||||
MusicPlayerRemote.enqueue(songs);
|
||||
return true;
|
||||
case R.id.action_add_to_playlist:
|
||||
AddToPlaylistDialog.create(songs).show(getSupportFragmentManager(), "ADD_PLAYLIST");
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
super.onBackPressed();
|
||||
return true;
|
||||
case R.id.action_colored_footers:
|
||||
item.setChecked(!item.isChecked());
|
||||
setUsePalette(item.isChecked());
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MaterialCab openCab(int menuRes, @NonNull final MaterialCab.Callback callback) {
|
||||
if (cab != null && cab.isActive()) cab.finish();
|
||||
cab = new MaterialCab(this, R.id.cab_stub)
|
||||
.setMenu(menuRes)
|
||||
.setCloseDrawableRes(R.drawable.ic_close_white_24dp)
|
||||
.setBackgroundColor(ThemeUtil.shiftBackgroundColorForLightText(getPaletteColor()))
|
||||
.start(new MaterialCab.Callback() {
|
||||
@Override
|
||||
public boolean onCabCreated(MaterialCab materialCab, Menu menu) {
|
||||
return callback.onCabCreated(materialCab, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCabItemClicked(MenuItem menuItem) {
|
||||
return callback.onCabItemClicked(menuItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCabFinished(MaterialCab materialCab) {
|
||||
return callback.onCabFinished(materialCab);
|
||||
}
|
||||
});
|
||||
return cab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (cab != null && cab.isActive()) {
|
||||
cab.finish();
|
||||
} else {
|
||||
binding.albums.stopScroll();
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatusbarColor(int color) {
|
||||
super.setStatusbarColor(color);
|
||||
setLightStatusbar(false);
|
||||
}
|
||||
|
||||
private void setArtist(Artist artist) {
|
||||
this.artist = artist;
|
||||
|
||||
getSupportActionBar().setTitle(artist.name);
|
||||
binding.songCountText.setText(MusicUtil.getSongCountString(this, artist.songs.size()));
|
||||
binding.albumCountText.setText(MusicUtil.getAlbumCountString(this, artist.albums.size()));
|
||||
binding.durationText.setText(MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(this, artist.songs)));
|
||||
|
||||
if (artist.songs.size() != 0) songAdapter.swapDataSet(artist.songs);
|
||||
if (artist.albums.size() != 0) albumAdapter.swapDataSet(artist.albums);
|
||||
}
|
||||
|
||||
private Artist getArtist() {
|
||||
if (artist == null) artist = new Artist();
|
||||
return artist;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
package com.dkanada.gramophone.activities.details;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.afollestad.materialcab.MaterialCab;
|
||||
import com.dkanada.gramophone.databinding.ActivityGenreDetailBinding;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils;
|
||||
import com.kabouzeid.appthemehelper.ThemeStore;
|
||||
import com.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.adapter.song.SongAdapter;
|
||||
import com.dkanada.gramophone.helper.MusicPlayerRemote;
|
||||
import com.dkanada.gramophone.interfaces.CabHolder;
|
||||
import com.dkanada.gramophone.interfaces.MediaCallback;
|
||||
import com.dkanada.gramophone.model.Genre;
|
||||
import com.dkanada.gramophone.model.Song;
|
||||
import com.dkanada.gramophone.activities.base.AbsSlidingMusicPanelActivity;
|
||||
import com.dkanada.gramophone.util.ThemeUtil;
|
||||
import com.dkanada.gramophone.util.QueryUtil;
|
||||
import com.dkanada.gramophone.util.ViewUtil;
|
||||
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
|
||||
|
||||
import org.jellyfin.apiclient.model.querying.ItemQuery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GenreDetailActivity extends AbsSlidingMusicPanelActivity implements CabHolder {
|
||||
public static final String EXTRA_GENRE = "extra_genre";
|
||||
|
||||
private ActivityGenreDetailBinding binding;
|
||||
|
||||
private Genre genre;
|
||||
|
||||
private MaterialCab cab;
|
||||
private SongAdapter adapter;
|
||||
|
||||
private RecyclerView.Adapter wrappedAdapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setDrawUnderStatusbar();
|
||||
setStatusbarColorAuto();
|
||||
|
||||
setNavigationbarColorAuto();
|
||||
setTaskDescriptionColorAuto();
|
||||
|
||||
genre = getIntent().getExtras().getParcelable(EXTRA_GENRE);
|
||||
|
||||
setUpRecyclerView();
|
||||
setUpToolBar();
|
||||
|
||||
ItemQuery query = new ItemQuery();
|
||||
query.setGenreIds(new String[]{genre.id});
|
||||
QueryUtil.getSongs(query, new MediaCallback() {
|
||||
@Override
|
||||
public void onLoadMedia(List<?> media) {
|
||||
adapter.getDataSet().addAll((List<Song>) media);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View createContentView() {
|
||||
binding = ActivityGenreDetailBinding.inflate(getLayoutInflater());
|
||||
|
||||
return wrapSlidingMusicPanel(binding.getRoot());
|
||||
}
|
||||
|
||||
private void setUpRecyclerView() {
|
||||
ViewUtil.setUpFastScrollRecyclerViewColor(this, ((FastScrollRecyclerView) binding.recyclerView), ThemeStore.accentColor(this));
|
||||
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
|
||||
adapter = new SongAdapter(this, new ArrayList<>(), R.layout.item_list, false, this);
|
||||
binding.recyclerView.setAdapter(adapter);
|
||||
|
||||
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
checkIsEmpty();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setUpToolBar() {
|
||||
binding.toolbar.setBackgroundColor(ThemeStore.primaryColor(this));
|
||||
setSupportActionBar(binding.toolbar);
|
||||
// noinspection ConstantConditions
|
||||
getSupportActionBar().setTitle(genre.name);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_genre_detail, menu);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
switch (id) {
|
||||
case R.id.action_shuffle_genre:
|
||||
MusicPlayerRemote.openAndShuffleQueue(adapter.getDataSet(), true);
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MaterialCab openCab(final int menu, final MaterialCab.Callback callback) {
|
||||
if (cab != null && cab.isActive()) cab.finish();
|
||||
cab = new MaterialCab(this, R.id.cab_stub)
|
||||
.setMenu(menu)
|
||||
.setCloseDrawableRes(R.drawable.ic_close_white_24dp)
|
||||
.setBackgroundColor(ThemeUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor(this)))
|
||||
.start(callback);
|
||||
|
||||
return cab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (cab != null && cab.isActive()) cab.finish();
|
||||
else {
|
||||
binding.recyclerView.stopScroll();
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIsEmpty() {
|
||||
binding.empty.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
binding.recyclerView.setAdapter(null);
|
||||
|
||||
if (wrappedAdapter != null) {
|
||||
WrapperAdapterUtils.releaseAll(wrappedAdapter);
|
||||
wrappedAdapter = null;
|
||||
}
|
||||
|
||||
adapter = null;
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
package com.dkanada.gramophone.activities.details;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.afollestad.materialcab.MaterialCab;
|
||||
import com.dkanada.gramophone.databinding.ActivityPlaylistDetailBinding;
|
||||
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.dkanada.gramophone.R;
|
||||
import com.dkanada.gramophone.adapter.song.OrderablePlaylistSongAdapter;
|
||||
import com.dkanada.gramophone.adapter.song.SongAdapter;
|
||||
import com.dkanada.gramophone.helper.MusicPlayerRemote;
|
||||
import com.dkanada.gramophone.helper.menu.PlaylistMenuHelper;
|
||||
import com.dkanada.gramophone.interfaces.CabHolder;
|
||||
import com.dkanada.gramophone.interfaces.MediaCallback;
|
||||
import com.dkanada.gramophone.model.Playlist;
|
||||
import com.dkanada.gramophone.model.PlaylistSong;
|
||||
import com.dkanada.gramophone.model.Song;
|
||||
import com.dkanada.gramophone.activities.base.AbsSlidingMusicPanelActivity;
|
||||
import com.dkanada.gramophone.util.ThemeUtil;
|
||||
import com.dkanada.gramophone.util.PlaylistUtil;
|
||||
import com.dkanada.gramophone.util.ViewUtil;
|
||||
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
|
||||
|
||||
import org.jellyfin.apiclient.model.playlists.PlaylistItemQuery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PlaylistDetailActivity extends AbsSlidingMusicPanelActivity implements CabHolder {
|
||||
public static String EXTRA_PLAYLIST = "extra_playlist";
|
||||
|
||||
private ActivityPlaylistDetailBinding binding;
|
||||
|
||||
private Playlist playlist;
|
||||
|
||||
private MaterialCab cab;
|
||||
private SongAdapter adapter;
|
||||
|
||||
private RecyclerView.Adapter wrappedAdapter;
|
||||
private RecyclerViewDragDropManager recyclerViewDragDropManager;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setDrawUnderStatusbar();
|
||||
setStatusbarColorAuto();
|
||||
|
||||
setNavigationbarColorAuto();
|
||||
setTaskDescriptionColorAuto();
|
||||
|
||||
playlist = getIntent().getExtras().getParcelable(EXTRA_PLAYLIST);
|
||||
|
||||
setUpRecyclerView();
|
||||
setUpToolbar();
|
||||
|
||||
PlaylistItemQuery query = new PlaylistItemQuery();
|
||||
query.setId(playlist.id);
|
||||
PlaylistUtil.getPlaylist(query, new MediaCallback() {
|
||||
@Override
|
||||
public void onLoadMedia(List<?> media) {
|
||||
adapter.getDataSet().addAll((List<PlaylistSong>) media);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View createContentView() {
|
||||
binding = ActivityPlaylistDetailBinding.inflate(getLayoutInflater());
|
||||
|
||||
return wrapSlidingMusicPanel(binding.getRoot());
|
||||
}
|
||||
|
||||
private void setUpRecyclerView() {
|
||||
ViewUtil.setUpFastScrollRecyclerViewColor(this, ((FastScrollRecyclerView) binding.recyclerView), ThemeStore.accentColor(this));
|
||||
binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
|
||||
recyclerViewDragDropManager = new RecyclerViewDragDropManager();
|
||||
final GeneralItemAnimator animator = new RefactoredDefaultItemAnimator();
|
||||
adapter = new OrderablePlaylistSongAdapter(this, new ArrayList<>(), R.layout.item_list, false, this, (fromPosition, toPosition) -> {
|
||||
PlaylistUtil.moveItem(playlist.id, (PlaylistSong) adapter.getDataSet().get(fromPosition), toPosition);
|
||||
Song song = adapter.getDataSet().remove(fromPosition);
|
||||
adapter.getDataSet().add(toPosition, song);
|
||||
adapter.notifyItemMoved(fromPosition, toPosition);
|
||||
});
|
||||
|
||||
wrappedAdapter = recyclerViewDragDropManager.createWrappedAdapter(adapter);
|
||||
|
||||
binding.recyclerView.setAdapter(wrappedAdapter);
|
||||
binding.recyclerView.setItemAnimator(animator);
|
||||
|
||||
recyclerViewDragDropManager.attachRecyclerView(binding.recyclerView);
|
||||
|
||||
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
checkIsEmpty();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setUpToolbar() {
|
||||
binding.toolbar.setBackgroundColor(ThemeStore.primaryColor(this));
|
||||
setSupportActionBar(binding.toolbar);
|
||||
// noinspection ConstantConditions
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setToolbarTitle(playlist.name);
|
||||
}
|
||||
|
||||
private void setToolbarTitle(String title) {
|
||||
// noinspection ConstantConditions
|
||||
getSupportActionBar().setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_playlist_detail, menu);
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
switch (id) {
|
||||
case R.id.action_shuffle_playlist:
|
||||
MusicPlayerRemote.openAndShuffleQueue(adapter.getDataSet(), true);
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
|
||||
return PlaylistMenuHelper.handleMenuClick(this, playlist, item);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MaterialCab openCab(final int menu, final MaterialCab.Callback callback) {
|
||||
if (cab != null && cab.isActive()) cab.finish();
|
||||
cab = new MaterialCab(this, R.id.cab_stub)
|
||||
.setMenu(menu)
|
||||
.setCloseDrawableRes(R.drawable.ic_close_white_24dp)
|
||||
.setBackgroundColor(ThemeUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor(this)))
|
||||
.start(callback);
|
||||
|
||||
return cab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (cab != null && cab.isActive()) {
|
||||
cab.finish();
|
||||
} else {
|
||||
binding.recyclerView.stopScroll();
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIsEmpty() {
|
||||
binding.empty.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
if (recyclerViewDragDropManager != null) {
|
||||
recyclerViewDragDropManager.cancelDrag();
|
||||
}
|
||||
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (recyclerViewDragDropManager != null) {
|
||||
recyclerViewDragDropManager.release();
|
||||
recyclerViewDragDropManager = null;
|
||||
}
|
||||
|
||||
binding.recyclerView.setItemAnimator(null);
|
||||
binding.recyclerView.setAdapter(null);
|
||||
|
||||
if (wrappedAdapter != null) {
|
||||
WrapperAdapterUtils.releaseAll(wrappedAdapter);
|
||||
wrappedAdapter = null;
|
||||
}
|
||||
|
||||
adapter = null;
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue