remove media scan and file views
This commit is contained in:
parent
6c7e5895de
commit
0d6a0929b9
46 changed files with 4 additions and 2026 deletions
|
|
@ -18,7 +18,6 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
|
|
@ -27,7 +26,6 @@ import com.kabouzeid.appthemehelper.util.ATHUtil;
|
|||
import com.kabouzeid.appthemehelper.util.NavigationViewUtil;
|
||||
import com.kabouzeid.gramophone.App;
|
||||
import com.kabouzeid.gramophone.R;
|
||||
import com.kabouzeid.gramophone.dialogs.ScanMediaFolderChooserDialog;
|
||||
import com.kabouzeid.gramophone.glide.SongGlideRequest;
|
||||
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
|
||||
import com.kabouzeid.gramophone.helper.SearchQueryHelper;
|
||||
|
|
@ -37,10 +35,8 @@ import com.kabouzeid.gramophone.loader.PlaylistSongLoader;
|
|||
import com.kabouzeid.gramophone.model.Song;
|
||||
import com.kabouzeid.gramophone.service.MusicService;
|
||||
import com.kabouzeid.gramophone.ui.activities.base.AbsSlidingMusicPanelActivity;
|
||||
import com.kabouzeid.gramophone.ui.fragments.mainactivity.folders.FoldersFragment;
|
||||
import com.kabouzeid.gramophone.ui.fragments.mainactivity.library.LibraryFragment;
|
||||
import com.kabouzeid.gramophone.util.MusicUtil;
|
||||
import com.kabouzeid.gramophone.util.PreferenceUtil;
|
||||
|
||||
import com.sothree.slidinguppanel.SlidingUpPanelLayout;
|
||||
|
||||
|
|
@ -51,12 +47,8 @@ import butterknife.BindView;
|
|||
import butterknife.ButterKnife;
|
||||
|
||||
public class MainActivity extends AbsSlidingMusicPanelActivity {
|
||||
|
||||
public static final String TAG = MainActivity.class.getSimpleName();
|
||||
|
||||
private static final int LIBRARY = 0;
|
||||
private static final int FOLDERS = 1;
|
||||
|
||||
@BindView(R.id.navigation_view)
|
||||
NavigationView navigationView;
|
||||
@BindView(R.id.drawer_layout)
|
||||
|
|
@ -81,31 +73,12 @@ public class MainActivity extends AbsSlidingMusicPanelActivity {
|
|||
setUpDrawerLayout();
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
setMusicChooser(PreferenceUtil.getInstance(this).getLastMusicChooser());
|
||||
setCurrentFragment(LibraryFragment.newInstance());
|
||||
} else {
|
||||
restoreCurrentFragment();
|
||||
}
|
||||
}
|
||||
|
||||
private void setMusicChooser(int key) {
|
||||
if (!App.isProVersion() && key == FOLDERS) {
|
||||
Toast.makeText(this, R.string.folder_view_is_a_pro_feature, Toast.LENGTH_LONG).show();
|
||||
key = LIBRARY;
|
||||
}
|
||||
|
||||
PreferenceUtil.getInstance(this).setLastMusicChooser(key);
|
||||
switch (key) {
|
||||
case LIBRARY:
|
||||
navigationView.setCheckedItem(R.id.nav_library);
|
||||
setCurrentFragment(LibraryFragment.newInstance());
|
||||
break;
|
||||
case FOLDERS:
|
||||
navigationView.setCheckedItem(R.id.nav_folders);
|
||||
setCurrentFragment(FoldersFragment.newInstance(this));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setCurrentFragment(@SuppressWarnings("NullableProblems") Fragment fragment) {
|
||||
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment, null).commit();
|
||||
currentFragment = (MainActivityFragmentCallbacks) fragment;
|
||||
|
|
@ -134,20 +107,12 @@ public class MainActivity extends AbsSlidingMusicPanelActivity {
|
|||
drawerLayout.closeDrawers();
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.nav_library:
|
||||
new Handler().postDelayed(() -> setMusicChooser(LIBRARY), 200);
|
||||
break;
|
||||
case R.id.nav_folders:
|
||||
new Handler().postDelayed(() -> setMusicChooser(FOLDERS), 200);
|
||||
navigationView.setCheckedItem(R.id.nav_library);
|
||||
setCurrentFragment(LibraryFragment.newInstance());
|
||||
break;
|
||||
case R.id.buy_pro:
|
||||
new Handler().postDelayed(() -> startActivity(new Intent(MainActivity.this, PurchaseActivity.class)), 200);
|
||||
break;
|
||||
case R.id.action_scan:
|
||||
new Handler().postDelayed(() -> {
|
||||
ScanMediaFolderChooserDialog dialog = ScanMediaFolderChooserDialog.create();
|
||||
dialog.show(getSupportFragmentManager(), "SCAN_MEDIA_FOLDER_CHOOSER");
|
||||
}, 200);
|
||||
break;
|
||||
case R.id.nav_settings:
|
||||
new Handler().postDelayed(() -> startActivity(new Intent(MainActivity.this, SettingsActivity.class)), 200);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public class SplashActivity extends AbsBaseActivity {
|
|||
connectionManager.Connect(credentialProvider.GetCredentials().getServers().get(0), new Response<ConnectionResult>() {
|
||||
@Override
|
||||
public void onResponse(ConnectionResult result) {
|
||||
if (result.getState() != ConnectionState.SignedIn) return;
|
||||
//if (result.getState() != ConnectionState.SignedIn) return;
|
||||
App.setApiClient(result.getApiClient());
|
||||
context.startActivity(new Intent(context, MainActivity.class));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,691 +0,0 @@
|
|||
package com.kabouzeid.gramophone.ui.fragments.mainactivity.folders;
|
||||
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.afollestad.materialcab.MaterialCab;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.google.android.material.appbar.AppBarLayout;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.kabouzeid.appthemehelper.ThemeStore;
|
||||
import com.kabouzeid.appthemehelper.common.ATHToolbarActivity;
|
||||
import com.kabouzeid.appthemehelper.util.ToolbarContentTintHelper;
|
||||
import com.kabouzeid.gramophone.R;
|
||||
import com.kabouzeid.gramophone.adapter.SongFileAdapter;
|
||||
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
|
||||
import com.kabouzeid.gramophone.helper.menu.SongMenuHelper;
|
||||
import com.kabouzeid.gramophone.helper.menu.SongsMenuHelper;
|
||||
import com.kabouzeid.gramophone.interfaces.CabHolder;
|
||||
import com.kabouzeid.gramophone.interfaces.LoaderIds;
|
||||
import com.kabouzeid.gramophone.misc.DialogAsyncTask;
|
||||
import com.kabouzeid.gramophone.misc.UpdateToastMediaScannerCompletionListener;
|
||||
import com.kabouzeid.gramophone.misc.WrappedAsyncTaskLoader;
|
||||
import com.kabouzeid.gramophone.model.Song;
|
||||
import com.kabouzeid.gramophone.ui.activities.MainActivity;
|
||||
import com.kabouzeid.gramophone.ui.fragments.mainactivity.AbsMainActivityFragment;
|
||||
import com.kabouzeid.gramophone.util.FileUtil;
|
||||
import com.kabouzeid.gramophone.util.PhonographColorUtil;
|
||||
import com.kabouzeid.gramophone.util.PreferenceUtil;
|
||||
import com.kabouzeid.gramophone.util.ViewUtil;
|
||||
import com.kabouzeid.gramophone.views.BreadCrumbLayout;
|
||||
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
public class FoldersFragment extends AbsMainActivityFragment implements MainActivity.MainActivityFragmentCallbacks, CabHolder, BreadCrumbLayout.SelectionCallback, SongFileAdapter.Callbacks, AppBarLayout.OnOffsetChangedListener, LoaderManager.LoaderCallbacks<List<File>> {
|
||||
|
||||
private static final int LOADER_ID = LoaderIds.FOLDERS_FRAGMENT;
|
||||
|
||||
protected static final String PATH = "path";
|
||||
protected static final String CRUMBS = "crumbs";
|
||||
|
||||
private Unbinder unbinder;
|
||||
|
||||
@BindView(R.id.coordinator_layout)
|
||||
CoordinatorLayout coordinatorLayout;
|
||||
@BindView(R.id.container)
|
||||
View container;
|
||||
@BindView(android.R.id.empty)
|
||||
View empty;
|
||||
@BindView(R.id.toolbar)
|
||||
Toolbar toolbar;
|
||||
@BindView(R.id.bread_crumbs)
|
||||
BreadCrumbLayout breadCrumbs;
|
||||
@BindView(R.id.appbar)
|
||||
AppBarLayout appbar;
|
||||
@BindView(R.id.recycler_view)
|
||||
FastScrollRecyclerView recyclerView;
|
||||
|
||||
private SongFileAdapter adapter;
|
||||
private MaterialCab cab;
|
||||
|
||||
public FoldersFragment() {
|
||||
}
|
||||
|
||||
public static FoldersFragment newInstance(Context context) {
|
||||
return newInstance(PreferenceUtil.getInstance(context).getStartDirectory());
|
||||
}
|
||||
|
||||
public static FoldersFragment newInstance(File directory) {
|
||||
FoldersFragment frag = new FoldersFragment();
|
||||
Bundle b = new Bundle();
|
||||
b.putSerializable(PATH, directory);
|
||||
frag.setArguments(b);
|
||||
return frag;
|
||||
}
|
||||
|
||||
public void setCrumb(BreadCrumbLayout.Crumb crumb, boolean addToHistory) {
|
||||
if (crumb == null) return;
|
||||
saveScrollPosition();
|
||||
breadCrumbs.setActiveOrAdd(crumb, false);
|
||||
if (addToHistory) {
|
||||
breadCrumbs.addHistory(crumb);
|
||||
}
|
||||
getLoaderManager().restartLoader(LOADER_ID, null, this);
|
||||
}
|
||||
|
||||
private void saveScrollPosition() {
|
||||
BreadCrumbLayout.Crumb crumb = getActiveCrumb();
|
||||
if (crumb != null) {
|
||||
crumb.setScrollPosition(((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition());
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BreadCrumbLayout.Crumb getActiveCrumb() {
|
||||
return breadCrumbs != null && breadCrumbs.size() > 0 ? breadCrumbs.getCrumb(breadCrumbs.getActiveIndex()) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putParcelable(CRUMBS, breadCrumbs.getStateWrapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
if (savedInstanceState == null) {
|
||||
setCrumb(new BreadCrumbLayout.Crumb(FileUtil.safeGetCanonicalFile((File) getArguments().getSerializable(PATH))), true);
|
||||
} else {
|
||||
breadCrumbs.restoreFromStateWrapper(savedInstanceState.getParcelable(CRUMBS));
|
||||
getLoaderManager().initLoader(LOADER_ID, null, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_folder, container, false);
|
||||
unbinder = ButterKnife.bind(this, view);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
getMainActivity().setStatusbarColorAuto();
|
||||
getMainActivity().setNavigationbarColorAuto();
|
||||
getMainActivity().setTaskDescriptionColorAuto();
|
||||
|
||||
setUpAppbarColor();
|
||||
setUpToolbar();
|
||||
setUpBreadCrumbs();
|
||||
setUpRecyclerView();
|
||||
setUpAdapter();
|
||||
}
|
||||
|
||||
private void setUpAppbarColor() {
|
||||
int primaryColor = ThemeStore.primaryColor(getActivity());
|
||||
appbar.setBackgroundColor(primaryColor);
|
||||
toolbar.setBackgroundColor(primaryColor);
|
||||
breadCrumbs.setBackgroundColor(primaryColor);
|
||||
breadCrumbs.setActivatedContentColor(ToolbarContentTintHelper.toolbarTitleColor(getActivity(), primaryColor));
|
||||
breadCrumbs.setDeactivatedContentColor(ToolbarContentTintHelper.toolbarSubtitleColor(getActivity(), primaryColor));
|
||||
}
|
||||
|
||||
private void setUpToolbar() {
|
||||
toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp);
|
||||
getActivity().setTitle(R.string.app_name);
|
||||
getMainActivity().setSupportActionBar(toolbar);
|
||||
}
|
||||
|
||||
private void setUpBreadCrumbs() {
|
||||
breadCrumbs.setCallback(this);
|
||||
}
|
||||
|
||||
private void setUpRecyclerView() {
|
||||
ViewUtil.setUpFastScrollRecyclerViewColor(getActivity(), recyclerView, ThemeStore.accentColor(getActivity()));
|
||||
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
|
||||
appbar.addOnOffsetChangedListener(this);
|
||||
}
|
||||
|
||||
private void setUpAdapter() {
|
||||
adapter = new SongFileAdapter(getMainActivity(), new LinkedList<>(), R.layout.item_list, this, this);
|
||||
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
checkIsEmpty();
|
||||
}
|
||||
});
|
||||
recyclerView.setAdapter(adapter);
|
||||
checkIsEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
saveScrollPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
appbar.removeOnOffsetChangedListener(this);
|
||||
unbinder.unbind();
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleBackPress() {
|
||||
if (cab != null && cab.isActive()) {
|
||||
cab.finish();
|
||||
return true;
|
||||
}
|
||||
if (breadCrumbs.popHistory()) {
|
||||
setCrumb(breadCrumbs.lastHistory(), false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MaterialCab openCab(int menuRes, MaterialCab.Callback callback) {
|
||||
if (cab != null && cab.isActive()) cab.finish();
|
||||
cab = new MaterialCab(getMainActivity(), R.id.cab_stub)
|
||||
.setMenu(menuRes)
|
||||
.setCloseDrawableRes(R.drawable.ic_close_white_24dp)
|
||||
.setBackgroundColor(PhonographColorUtil.shiftBackgroundColorForLightText(ThemeStore.primaryColor(getActivity())))
|
||||
.start(callback);
|
||||
return cab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
inflater.inflate(R.menu.menu_folders, menu);
|
||||
ToolbarContentTintHelper.handleOnCreateOptionsMenu(getActivity(), toolbar, menu, ATHToolbarActivity.getToolbarBackgroundColor(toolbar));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(getActivity(), toolbar);
|
||||
}
|
||||
|
||||
public static final FileFilter AUDIO_FILE_FILTER = file -> !file.isHidden() && (file.isDirectory() ||
|
||||
FileUtil.fileIsMimeType(file, "audio/*", MimeTypeMap.getSingleton()) ||
|
||||
FileUtil.fileIsMimeType(file, "application/ogg", MimeTypeMap.getSingleton()));
|
||||
|
||||
@Override
|
||||
public void onCrumbSelection(BreadCrumbLayout.Crumb crumb, int index) {
|
||||
setCrumb(crumb, true);
|
||||
}
|
||||
|
||||
public static File getDefaultStartDirectory() {
|
||||
File musicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
|
||||
File startFolder;
|
||||
if (musicDir.exists() && musicDir.isDirectory()) {
|
||||
startFolder = musicDir;
|
||||
} else {
|
||||
File externalStorage = Environment.getExternalStorageDirectory();
|
||||
if (externalStorage.exists() && externalStorage.isDirectory()) {
|
||||
startFolder = externalStorage;
|
||||
} else {
|
||||
startFolder = new File("/"); // root
|
||||
}
|
||||
}
|
||||
return startFolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_go_to_start_directory:
|
||||
setCrumb(new BreadCrumbLayout.Crumb(FileUtil.safeGetCanonicalFile(PreferenceUtil.getInstance(getActivity()).getStartDirectory())), true);
|
||||
return true;
|
||||
case R.id.action_scan:
|
||||
BreadCrumbLayout.Crumb crumb = getActiveCrumb();
|
||||
if (crumb != null) {
|
||||
new ArrayListPathsAsyncTask(getActivity(), this::scanPaths).execute(new ArrayListPathsAsyncTask.LoadingInfo(crumb.getFile(), AUDIO_FILE_FILTER));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileSelected(File file) {
|
||||
final File canonicalFile = FileUtil.safeGetCanonicalFile(file); // important as we compare the path value later
|
||||
if (canonicalFile.isDirectory()) {
|
||||
setCrumb(new BreadCrumbLayout.Crumb(canonicalFile), true);
|
||||
} else {
|
||||
FileFilter fileFilter = pathname -> !pathname.isDirectory() && AUDIO_FILE_FILTER.accept(pathname);
|
||||
new ListSongsAsyncTask(getActivity(), null, (songs, extra) -> {
|
||||
int startIndex = -1;
|
||||
for (int i = 0; i < songs.size(); i++) {
|
||||
if (canonicalFile.getPath().equals(songs.get(i).data)) {
|
||||
startIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (startIndex > -1) {
|
||||
MusicPlayerRemote.openQueue(songs, startIndex, true);
|
||||
} else {
|
||||
Snackbar.make(coordinatorLayout, Html.fromHtml(String.format(getString(R.string.not_listed_in_media_store), canonicalFile.getName())), Snackbar.LENGTH_LONG)
|
||||
.setAction(R.string.action_scan, v -> scanPaths(new String[]{canonicalFile.getPath()}))
|
||||
.setActionTextColor(ThemeStore.accentColor(getActivity()))
|
||||
.show();
|
||||
}
|
||||
}).execute(new ListSongsAsyncTask.LoadingInfo(toList(canonicalFile.getParentFile()), fileFilter, getFileComparator()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMultipleItemAction(MenuItem item, List<File> files) {
|
||||
final int itemId = item.getItemId();
|
||||
new ListSongsAsyncTask(getActivity(), null, (songs, extra) -> {
|
||||
if (!songs.isEmpty()) {
|
||||
SongsMenuHelper.handleMenuClick(getActivity(), songs, itemId);
|
||||
}
|
||||
if (songs.size() != files.size()) {
|
||||
Snackbar.make(coordinatorLayout, R.string.some_files_are_not_listed_in_the_media_store, Snackbar.LENGTH_LONG)
|
||||
.setAction(R.string.action_scan, v -> {
|
||||
String[] paths = new String[files.size()];
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
paths[i] = FileUtil.safeGetCanonicalPath(files.get(i));
|
||||
}
|
||||
scanPaths(paths);
|
||||
})
|
||||
.setActionTextColor(ThemeStore.accentColor(getActivity()))
|
||||
.show();
|
||||
}
|
||||
}).execute(new ListSongsAsyncTask.LoadingInfo(files, AUDIO_FILE_FILTER, getFileComparator()));
|
||||
}
|
||||
|
||||
private List<File> toList(File file) {
|
||||
List<File> files = new ArrayList<>(1);
|
||||
files.add(file);
|
||||
return files;
|
||||
}
|
||||
|
||||
Comparator<File> fileComparator = (lhs, rhs) -> {
|
||||
if (lhs.isDirectory() && !rhs.isDirectory()) {
|
||||
return -1;
|
||||
} else if (!lhs.isDirectory() && rhs.isDirectory()) {
|
||||
return 1;
|
||||
} else {
|
||||
return lhs.getName().compareToIgnoreCase
|
||||
(rhs.getName());
|
||||
}
|
||||
};
|
||||
|
||||
private Comparator<File> getFileComparator() {
|
||||
return fileComparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileMenuClicked(final File file, View view) {
|
||||
PopupMenu popupMenu = new PopupMenu(getActivity(), view);
|
||||
if (file.isDirectory()) {
|
||||
popupMenu.inflate(R.menu.menu_item_directory);
|
||||
popupMenu.setOnMenuItemClickListener(item -> {
|
||||
final int itemId = item.getItemId();
|
||||
switch (itemId) {
|
||||
case R.id.action_play_next:
|
||||
case R.id.action_add_to_current_playing:
|
||||
case R.id.action_add_to_playlist:
|
||||
case R.id.action_delete_from_device:
|
||||
new ListSongsAsyncTask(getActivity(), null, (songs, extra) -> {
|
||||
if (!songs.isEmpty()) {
|
||||
SongsMenuHelper.handleMenuClick(getActivity(), songs, itemId);
|
||||
}
|
||||
}).execute(new ListSongsAsyncTask.LoadingInfo(toList(file), AUDIO_FILE_FILTER, getFileComparator()));
|
||||
return true;
|
||||
case R.id.action_set_as_start_directory:
|
||||
PreferenceUtil.getInstance(getActivity()).setStartDirectory(file);
|
||||
Toast.makeText(getActivity(), String.format(getString(R.string.new_start_directory), file.getPath()), Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
case R.id.action_scan:
|
||||
new ArrayListPathsAsyncTask(getActivity(), this::scanPaths).execute(new ArrayListPathsAsyncTask.LoadingInfo(file, AUDIO_FILE_FILTER));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
} else {
|
||||
popupMenu.inflate(R.menu.menu_item_file);
|
||||
popupMenu.setOnMenuItemClickListener(item -> {
|
||||
final int itemId = item.getItemId();
|
||||
switch (itemId) {
|
||||
case R.id.action_play_next:
|
||||
case R.id.action_add_to_current_playing:
|
||||
case R.id.action_add_to_playlist:
|
||||
case R.id.action_go_to_album:
|
||||
case R.id.action_go_to_artist:
|
||||
case R.id.action_share:
|
||||
case R.id.action_details:
|
||||
case R.id.action_set_as_ringtone:
|
||||
case R.id.action_delete_from_device:
|
||||
new ListSongsAsyncTask(getActivity(), null, (songs, extra) -> {
|
||||
if (!songs.isEmpty()) {
|
||||
SongMenuHelper.handleMenuClick(getActivity(), songs.get(0), itemId);
|
||||
} else {
|
||||
Snackbar.make(coordinatorLayout, Html.fromHtml(String.format(getString(R.string.not_listed_in_media_store), file.getName())), Snackbar.LENGTH_LONG)
|
||||
.setAction(R.string.action_scan, v -> scanPaths(new String[]{FileUtil.safeGetCanonicalPath(file)}))
|
||||
.setActionTextColor(ThemeStore.accentColor(getActivity()))
|
||||
.show();
|
||||
}
|
||||
}).execute(new ListSongsAsyncTask.LoadingInfo(toList(file), AUDIO_FILE_FILTER, getFileComparator()));
|
||||
return true;
|
||||
case R.id.action_scan:
|
||||
scanPaths(new String[]{FileUtil.safeGetCanonicalPath(file)});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
popupMenu.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
|
||||
container.setPadding(container.getPaddingLeft(), container.getPaddingTop(), container.getPaddingRight(), appbar.getTotalScrollRange() + verticalOffset);
|
||||
}
|
||||
|
||||
private void checkIsEmpty() {
|
||||
if (empty != null) {
|
||||
empty.setVisibility(adapter == null || adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void scanPaths(@Nullable String[] toBeScanned) {
|
||||
if (getActivity() == null) return;
|
||||
if (toBeScanned == null || toBeScanned.length < 1) {
|
||||
Toast.makeText(getActivity(), R.string.nothing_to_scan, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
MediaScannerConnection.scanFile(getActivity().getApplicationContext(), toBeScanned, null, new UpdateToastMediaScannerCompletionListener(getActivity(), toBeScanned));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAdapter(@NonNull List<File> files) {
|
||||
adapter.swapDataSet(files);
|
||||
BreadCrumbLayout.Crumb crumb = getActiveCrumb();
|
||||
if (crumb != null && recyclerView != null) {
|
||||
((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(crumb.getScrollPosition(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<List<File>> onCreateLoader(int id, Bundle args) {
|
||||
return new AsyncFileLoader(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(@NonNull Loader<List<File>> loader, List<File> data) {
|
||||
updateAdapter(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(@NonNull Loader<List<File>> loader) {
|
||||
updateAdapter(new LinkedList<>());
|
||||
}
|
||||
|
||||
private static class AsyncFileLoader extends WrappedAsyncTaskLoader<List<File>> {
|
||||
private WeakReference<FoldersFragment> fragmentWeakReference;
|
||||
|
||||
public AsyncFileLoader(FoldersFragment foldersFragment) {
|
||||
super(foldersFragment.getActivity());
|
||||
fragmentWeakReference = new WeakReference<>(foldersFragment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<File> loadInBackground() {
|
||||
FoldersFragment foldersFragment = fragmentWeakReference.get();
|
||||
File directory = null;
|
||||
if (foldersFragment != null) {
|
||||
BreadCrumbLayout.Crumb crumb = foldersFragment.getActiveCrumb();
|
||||
if (crumb != null) {
|
||||
directory = crumb.getFile();
|
||||
}
|
||||
}
|
||||
if (directory != null) {
|
||||
List<File> files = FileUtil.listFiles(directory, AUDIO_FILE_FILTER);
|
||||
Collections.sort(files, foldersFragment.getFileComparator());
|
||||
return files;
|
||||
} else {
|
||||
return new LinkedList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ListSongsAsyncTask extends ListingFilesDialogAsyncTask<ListSongsAsyncTask.LoadingInfo, Void, List<Song>> {
|
||||
private WeakReference<Context> contextWeakReference;
|
||||
private WeakReference<OnSongsListedCallback> callbackWeakReference;
|
||||
private final Object extra;
|
||||
|
||||
public ListSongsAsyncTask(Context context, Object extra, OnSongsListedCallback callback) {
|
||||
super(context, 500);
|
||||
this.extra = extra;
|
||||
contextWeakReference = new WeakReference<>(context);
|
||||
callbackWeakReference = new WeakReference<>(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
checkCallbackReference();
|
||||
checkContextReference();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Song> doInBackground(LoadingInfo... params) {
|
||||
try {
|
||||
LoadingInfo info = params[0];
|
||||
List<File> files = FileUtil.listFilesDeep(info.files, info.fileFilter);
|
||||
|
||||
if (isCancelled() || checkContextReference() == null || checkCallbackReference() == null)
|
||||
return null;
|
||||
|
||||
Collections.sort(files, info.fileComparator);
|
||||
|
||||
Context context = checkContextReference();
|
||||
if (isCancelled() || context == null || checkCallbackReference() == null)
|
||||
return null;
|
||||
|
||||
return FileUtil.matchFilesWithMediaStore(context, files);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
cancel(false);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<Song> songs) {
|
||||
super.onPostExecute(songs);
|
||||
OnSongsListedCallback callback = checkCallbackReference();
|
||||
if (songs != null && callback != null)
|
||||
callback.onSongsListed(songs, extra);
|
||||
}
|
||||
|
||||
private Context checkContextReference() {
|
||||
Context context = contextWeakReference.get();
|
||||
if (context == null) {
|
||||
cancel(false);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
private OnSongsListedCallback checkCallbackReference() {
|
||||
OnSongsListedCallback callback = callbackWeakReference.get();
|
||||
if (callback == null) {
|
||||
cancel(false);
|
||||
}
|
||||
return callback;
|
||||
}
|
||||
|
||||
public static class LoadingInfo {
|
||||
public final Comparator<File> fileComparator;
|
||||
public final FileFilter fileFilter;
|
||||
public final List<File> files;
|
||||
|
||||
public LoadingInfo(@NonNull List<File> files, @NonNull FileFilter fileFilter, @NonNull Comparator<File> fileComparator) {
|
||||
this.fileComparator = fileComparator;
|
||||
this.fileFilter = fileFilter;
|
||||
this.files = files;
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnSongsListedCallback {
|
||||
void onSongsListed(@NonNull List<Song> songs, Object extra);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ArrayListPathsAsyncTask extends ListingFilesDialogAsyncTask<ArrayListPathsAsyncTask.LoadingInfo, String, String[]> {
|
||||
private WeakReference<OnPathsListedCallback> onPathsListedCallbackWeakReference;
|
||||
|
||||
public ArrayListPathsAsyncTask(Context context, OnPathsListedCallback callback) {
|
||||
super(context, 500);
|
||||
onPathsListedCallbackWeakReference = new WeakReference<>(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
checkCallbackReference();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] doInBackground(LoadingInfo... params) {
|
||||
try {
|
||||
if (isCancelled() || checkCallbackReference() == null) return null;
|
||||
|
||||
LoadingInfo info = params[0];
|
||||
|
||||
final String[] paths;
|
||||
|
||||
if (info.file.isDirectory()) {
|
||||
List<File> files = FileUtil.listFilesDeep(info.file, info.fileFilter);
|
||||
|
||||
if (isCancelled() || checkCallbackReference() == null) return null;
|
||||
|
||||
paths = new String[files.size()];
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
File f = files.get(i);
|
||||
paths[i] = FileUtil.safeGetCanonicalPath(f);
|
||||
|
||||
if (isCancelled() || checkCallbackReference() == null) return null;
|
||||
}
|
||||
} else {
|
||||
paths = new String[1];
|
||||
paths[0] = FileUtil.safeGetCanonicalPath(info.file);
|
||||
}
|
||||
|
||||
return paths;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
cancel(false);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String[] paths) {
|
||||
super.onPostExecute(paths);
|
||||
OnPathsListedCallback callback = checkCallbackReference();
|
||||
if (callback != null && paths != null) {
|
||||
callback.onPathsListed(paths);
|
||||
}
|
||||
}
|
||||
|
||||
private OnPathsListedCallback checkCallbackReference() {
|
||||
OnPathsListedCallback callback = onPathsListedCallbackWeakReference.get();
|
||||
if (callback == null) {
|
||||
cancel(false);
|
||||
}
|
||||
return callback;
|
||||
}
|
||||
|
||||
public static class LoadingInfo {
|
||||
public final File file;
|
||||
public final FileFilter fileFilter;
|
||||
|
||||
public LoadingInfo(File file, FileFilter fileFilter) {
|
||||
this.file = file;
|
||||
this.fileFilter = fileFilter;
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnPathsListedCallback {
|
||||
void onPathsListed(@NonNull String[] paths);
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class ListingFilesDialogAsyncTask<Params, Progress, Result> extends DialogAsyncTask<Params, Progress, Result> {
|
||||
public ListingFilesDialogAsyncTask(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ListingFilesDialogAsyncTask(Context context, int showDelay) {
|
||||
super(context, showDelay);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog createDialog(@NonNull Context context) {
|
||||
return new MaterialDialog.Builder(context)
|
||||
.title(R.string.listing_files)
|
||||
.progress(true, 0)
|
||||
.progressIndeterminateStyle(true)
|
||||
.cancelListener(dialog -> cancel(false))
|
||||
.dismissListener(dialog -> cancel(false))
|
||||
.negativeText(android.R.string.cancel)
|
||||
.onNegative((dialog, which) -> cancel(false))
|
||||
.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue