package com.marverenic.music.activity; import android.Manifest; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.design.widget.AppBarLayout; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.widget.SwipeRefreshLayout; import android.view.Menu; import android.view.MenuItem; import android.view.View; import com.marverenic.music.JockeyApplication; import com.marverenic.music.R; import com.marverenic.music.activity.instance.AutoPlaylistEditActivity; import com.marverenic.music.data.store.MediaStoreUtil; import com.marverenic.music.data.store.MusicStore; import com.marverenic.music.data.store.PlaylistStore; import com.marverenic.music.data.store.PreferenceStore; import com.marverenic.music.data.store.ThemeStore; import com.marverenic.music.dialog.CreatePlaylistDialogFragment; import com.marverenic.music.fragments.AlbumFragment; import com.marverenic.music.fragments.ArtistFragment; import com.marverenic.music.fragments.GenreFragment; import com.marverenic.music.fragments.PlaylistFragment; import com.marverenic.music.fragments.SongFragment; import com.marverenic.music.model.Song; import com.marverenic.music.player.PlayerController; import com.marverenic.music.utils.UriUtils; import com.marverenic.music.utils.Util; import com.marverenic.music.view.FABMenu; import java.io.File; import java.util.Collections; import java.util.List; import javax.inject.Inject; import rx.Observable; import timber.log.Timber; public class MainActivity extends BaseLibraryActivity implements View.OnClickListener { private static final String TAG_MAKE_PLAYLIST = "CreatePlaylistDialog"; private static final String ACTION_SHOW_NOW_PLAYING_PAGE = "MainActivity.ShowNowPlayingPage"; @Inject ThemeStore mThemeStore; @Inject MusicStore mMusicStore; @Inject PlayerController mPlayerController; @Inject PlaylistStore mPlaylistStore; @Inject PreferenceStore mPrefStore; private SwipeRefreshLayout mRefreshLayout; public static Intent newNowPlayingIntent(Context context) { Intent intent = new Intent(context, MainActivity.class); intent.setAction(ACTION_SHOW_NOW_PLAYING_PAGE); return intent; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); JockeyApplication.getComponent(this).inject(this); onNewIntent(getIntent()); initRefreshLayout(); mMusicStore.loadAll(); mPlaylistStore.loadPlaylists(); // Setup the FAB FABMenu fab = (FABMenu) findViewById(R.id.fab); fab.addChild(R.drawable.ic_add_24dp, this, R.string.playlist); fab.addChild(R.drawable.ic_add_24dp, this, R.string.playlist_auto); ViewPager pager = (ViewPager) findViewById(R.id.library_pager); AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.library_app_bar_layout); appBarLayout.addOnOffsetChangedListener((layout, verticalOffset) -> pager.setPadding(pager.getPaddingLeft(), pager.getPaddingTop(), pager.getPaddingRight(), layout.getTotalScrollRange() + verticalOffset)); int page = mPrefStore.getDefaultPage(); if (page != 0 || !hasRwPermission()) { fab.setVisibility(View.GONE); } PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager()); adapter.setFloatingActionButton(fab); pager.setAdapter(adapter); pager.addOnPageChangeListener(adapter); ((TabLayout) findViewById(R.id.library_tabs)).setupWithViewPager(pager); pager.setCurrentItem(page); if (getSupportActionBar() != null) { getSupportActionBar().setDisplayHomeAsUpEnabled(false); getSupportActionBar().setHomeButtonEnabled(false); getSupportActionBar().setDisplayShowHomeEnabled(false); } } @Override protected int getContentLayoutResource() { return R.layout.activity_library; } @Override public void onNewIntent(Intent intent) { if (intent.getAction() == null) { return; } if (intent.getAction().equals(ACTION_SHOW_NOW_PLAYING_PAGE)) { expandBottomSheet(); // Don't try to process this intent again setIntent(new Intent(this, MainActivity.class)); return; } // Handle incoming requests to play media from other applications if (intent.getData() == null) { return; } expandBottomSheet(); // If this intent is a music intent, process it if (intent.getAction().equals(Intent.ACTION_VIEW)) { Uri songUri = intent.getData(); String songName = UriUtils.getDisplayName(this, songUri); List<Song> queue = buildQueueFromFileUri(songUri); int position; if (queue == null || queue.isEmpty()) { queue = buildQueueFromUri(intent.getData()); position = findStartingPositionInQueue(songUri, queue); } else { String path = UriUtils.getPathFromUri(this, songUri); //noinspection ConstantConditions This won't be null, because we found data from it Uri fileUri = Uri.fromFile(new File(path)); position = findStartingPositionInQueue(fileUri, queue); } if (queue.isEmpty()) { showSnackbar(getString(R.string.message_play_error_not_found, songName)); } else { startIntentQueue(queue, position); } } // Don't try to process this intent again setIntent(new Intent(this, MainActivity.class)); } private List<Song> buildQueueFromFileUri(Uri fileUri) { // URI is not a file URI String path = UriUtils.getPathFromUri(this, fileUri); if (path == null || path.trim().isEmpty()) { return Collections.emptyList(); } File file = new File(path); String mimeType = getContentResolver().getType(fileUri); return MediaStoreUtil.buildSongListFromFile(this, file, mimeType); } private List<Song> buildQueueFromUri(Uri uri) { return Collections.singletonList(Song.fromUri(this, uri)); } private int findStartingPositionInQueue(Uri originalUri, List<Song> queue) { for (int i = 0; i < queue.size(); i++) { if (queue.get(i).getLocation().equals(originalUri)) { return i; } } return 0; } private void startIntentQueue(List<Song> queue, int position) { mPlayerController.setQueue(queue, position); mPlayerController.play(); } private void initRefreshLayout() { mRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.library_refresh_layout); mRefreshLayout.setSize(SwipeRefreshLayout.DEFAULT); mRefreshLayout.setColorSchemeColors(mThemeStore.getPrimaryColor(), mThemeStore.getAccentColor()); mRefreshLayout.setEnabled(false); Observable.combineLatest(mMusicStore.isLoading(), mPlaylistStore.isLoading(), (musicLoading, playlistLoading) -> { return musicLoading || playlistLoading; }) .compose(bindToLifecycle()) .subscribe( refreshing -> { mRefreshLayout.setEnabled(refreshing); mRefreshLayout.setRefreshing(refreshing); }, throwable -> { Timber.e(throwable, "Failed to update refresh indicator"); }); } @TargetApi(Build.VERSION_CODES.M) private boolean hasRwPermission() { return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Util.hasPermissions(this, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.activity_library, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_library_settings: startActivity(SettingsActivity.newIntent(this)); return true; case R.id.menu_library_search: startActivity(SearchActivity.newIntent(this)); return true; case R.id.menu_library_about: startActivity(AboutActivity.newIntent(this)); return true; default: return super.onOptionsItemSelected(item); } } @Override public void onClick(View v) { if (v.getTag() != null) { if (v.getTag().equals("fab-" + getString(R.string.playlist))) { new CreatePlaylistDialogFragment.Builder(getSupportFragmentManager()) .showSnackbarIn(R.id.library_pager) .show(TAG_MAKE_PLAYLIST); } else if (v.getTag().equals("fab-" + getString(R.string.playlist_auto))) { startActivity(AutoPlaylistEditActivity.newIntent(this)); } } } @Override protected int getSnackbarContainerViewId() { return R.id.library_pager; } public class PagerAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener { private PlaylistFragment playlistFragment; private SongFragment songFragment; private ArtistFragment artistFragment; private AlbumFragment albumFragment; private GenreFragment genreFragment; private FABMenu fab; public PagerAdapter(FragmentManager fm) { super(fm); } public void setFloatingActionButton(FABMenu view) { fab = view; } @Override public Fragment getItem(int position) { switch (position) { case 0: if (playlistFragment == null) { playlistFragment = new PlaylistFragment(); } return playlistFragment; case 1: if (songFragment == null) { songFragment = new SongFragment(); } return songFragment; case 2: if (artistFragment == null) { artistFragment = new ArtistFragment(); } return artistFragment; case 3: if (albumFragment == null) { albumFragment = new AlbumFragment(); } return albumFragment; case 4: if (genreFragment == null) { genreFragment = new GenreFragment(); } return genreFragment; } return new Fragment(); } @Override public int getCount() { return 5; } @Override public CharSequence getPageTitle(int position) { switch (position) { case 0: return getResources().getString(R.string.header_playlists); case 1: return getResources().getString(R.string.header_songs); case 2: return getResources().getString(R.string.header_artists); case 3: return getResources().getString(R.string.header_albums); case 4: return getResources().getString(R.string.header_genres); default: return "Page " + position; } } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { // Hide the fab when outside of the Playlist fragment // Don't show the FAB if we can't write to the library if (!hasRwPermission()) return; // If the fab isn't supposed to change states, don't animate anything if (position != 0 && fab.getVisibility() == View.GONE) return; if (position == 0) { fab.show(); } else { fab.hide(); } } @Override public void onPageScrollStateChanged(int state) { } } }