package com.openfarmanager.android.fragments; import android.annotation.TargetApi; import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.annotation.NonNull; import android.support.v7.widget.LinearLayoutManager; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.webkit.MimeTypeMap; import android.widget.*; import com.openfarmanager.android.App; import com.openfarmanager.android.R; //import com.openfarmanager.android.adapters.FlatFileSystemAdapter; import com.openfarmanager.android.adapters.FileSystemAdapter; import com.openfarmanager.android.controllers.FileSystemController; import com.openfarmanager.android.core.archive.ArchiveUtils; import com.openfarmanager.android.core.archive.MimeTypes; import com.openfarmanager.android.core.bus.RxBus; import com.openfarmanager.android.core.bus.TaskCancelledEvent; import com.openfarmanager.android.core.bus.TaskErrorEvent; import com.openfarmanager.android.core.bus.TaskOkAndPostEvent; import com.openfarmanager.android.core.bus.TaskOkEvent; import com.openfarmanager.android.dialogs.*; import com.openfarmanager.android.dialogs.CreateArchiveDialog; import com.openfarmanager.android.dialogs.SearchActionDialog; import com.openfarmanager.android.filesystem.DropboxFile; import com.openfarmanager.android.filesystem.FileProxy; import com.openfarmanager.android.filesystem.FileSystemFile; import com.openfarmanager.android.filesystem.FileSystemScanner; import com.openfarmanager.android.filesystem.commands.CommandsFactory; import com.openfarmanager.android.filesystem.commands.CreateBookmarkCommand; import com.openfarmanager.android.filesystem.commands.DropboxCommand; import com.openfarmanager.android.filesystem.commands.ExportAsCommand; import com.openfarmanager.android.filesystem.commands.GoogleDriveUpdateCommand; import com.openfarmanager.android.model.Bookmark; import com.openfarmanager.android.model.FileActionEnum; import com.openfarmanager.android.model.OpenDirectoryActionListener; import com.openfarmanager.android.model.SelectParams; import com.openfarmanager.android.model.TaskStatusEnum; import com.openfarmanager.android.model.exeptions.SdcardPermissionException; import com.openfarmanager.android.utils.CustomFormatter; import com.openfarmanager.android.utils.FileUtilsExt; import com.openfarmanager.android.utils.StorageUtils; import com.openfarmanager.android.view.ActionBar; import com.openfarmanager.android.view.FileSystemListView; import com.openfarmanager.android.view.ToastNotification; import org.apache.commons.io.filefilter.WildcardFileFilter; import java.io.File; import java.io.FileFilter; import java.util.*; import rx.android.schedulers.AndroidSchedulers; import rx.subscriptions.CompositeSubscription; import static com.openfarmanager.android.controllers.FileSystemController.*; import static com.openfarmanager.android.model.FileActionEnum.*; public class MainPanel extends BaseFileSystemPanel { public static final int LEFT_PANEL = 0; public static final int RIGHT_PANEL = 1; public static final int SELECT_ACTION = 100; public static final int SEARCH_ACTION = 101; public static final int FILE_CREATE = 1000; public static final int FILE_DELETE = 1001; public static final int FILE_COPY = 1002; public static final int FILE_MOVE = 1003; public static final int FILE_CREATE_BOOKMARK = 1004; public static final int FILE_EXTRACT_ARCHIVE = 1005; public static final int FILE_CREATE_ARCHIVE = 1006; private File mBaseDir; protected FileSystemListView mFileSystemList; protected ProgressBar mProgress; protected boolean mIsMultiSelectMode = false; protected boolean mIsDataLoading; protected List<FileProxy> mSelectedFiles = new ArrayList<>(); private int mLastListPosition; protected TextView mSelectedFilesSize; protected QuickPopupDialog mQuickActionPopup; protected ActionBar mActionBar; private CompositeSubscription mSubscriptions; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { setupHandler(); View view = inflater.inflate(R.layout.main_panel, container, false); mFileSystemList = (FileSystemListView) view.findViewById(android.R.id.list); mProgress = (ProgressBar) view.findViewById(R.id.loading); mSelectedFilesSize = (TextView) view.findViewById(R.id.selected_files_size); mActionBar = createActionBar(); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); layoutParams.gravity = Gravity.CENTER_HORIZONTAL; mActionBar.setPanelLocation(getPanelLocation()); ((ViewGroup) view.findViewById(R.id.root_view)).addView(mActionBar, layoutParams); mFileSystemList.setOnItemClickListener(new FileSystemAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int i) { FileSystemAdapter adapterView = getAdapter(); LinearLayoutManager layoutManager = (LinearLayoutManager) mFileSystemList.getLayoutManager(); if (mIsMultiSelectMode) { File file = (File) adapterView.getItem(i); updateLongClickSelection(adapterView, file, false); return; } mSelectedFiles.clear(); File item = null; FileSystemFile file = null; Integer previousState = null; if (!isRootDirectory()) { if (i == 0) { item = mBaseDir.getParentFile(); if (item != null) { previousState = mDirectorySelection.get(item.getAbsolutePath()); } } } if (item == null) { item = (FileSystemFile) adapterView.getItem(i); } if (item instanceof FileSystemFile) { file = (FileSystemFile) item; } if (file != null && file.isBookmark()) { Bookmark bookmark = file.getBookmark(); if (bookmark.isNetworkLink()) { mHandler.sendMessage(mHandler.obtainMessage(FileSystemController.OPEN_NETWORK, bookmark)); } else { openDirectory(new File(bookmark.getBookmarkPath())); } return; } if (item.isDirectory()) { openDirectory(item, previousState); if (previousState == null) { mDirectorySelection.put(item.getParent(), layoutManager.findFirstVisibleItemPosition()); } } else if (item.isFile()) { String mime = ArchiveUtils.getMimeType(item); if (ArchiveUtils.isArchiveSupported(mime)) { mHandler.sendMessage(mHandler.obtainMessage(OPEN_ARCHIVE, item)); FileSystemAdapter adapter = getAdapter(); if (adapter != null) { adapter.clearSelectedFiles(); } } else if (ArchiveUtils.isCompressionSupported(mime)) { mHandler.sendMessage(mHandler.obtainMessage(OPEN_COMPRESSED_ARCHIVE, item)); FileSystemAdapter adapter = getAdapter(); if (adapter != null) { adapter.clearSelectedFiles(); } } else { openFile(item); } } else if (!isFileExists(item)) { ToastNotification.makeText(App.sInstance.getApplicationContext(), getSafeString(R.string.error_non_existsed_directory), Toast.LENGTH_SHORT).show(); gainFocus(); openHomeFolder(); } } @Override public void onItemLongClick(View view, int position) { onLongClick(view, position); } }); setupGestures(mFileSystemList); mQuickActionPopup = new QuickPopupDialog(getActivity(), view, R.layout.quick_action_popup); mQuickActionPopup.setPosition((getPanelLocation() == LEFT_PANEL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, (int) (50 * getResources().getDisplayMetrics().density)); View layout = mQuickActionPopup.getContentView(); layout.findViewById(R.id.quick_action_copy).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { gainFocus(); mHandler.sendMessage(mHandler.obtainMessage(FILE_ACTION, FileActionEnum.COPY)); } }); layout.findViewById(R.id.quick_action_delete).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { gainFocus(); mHandler.sendMessage(mHandler.obtainMessage(FILE_ACTION, FileActionEnum.DELETE)); } }); layout.findViewById(R.id.quick_action_select).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { selectAll(); invalidate(false); } }); layout.findViewById(R.id.quick_action_deselect).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { unselectAll(); invalidate(false); } }); postInitialization(); setNavigationButtonsVisibility(); return view; } @NonNull protected ActionBar createActionBar() { return new ActionBar(getContext()); } public void openHomeFolder() { try { openDirectory(new File(App.sInstance.getSettings().getHomeFolder())); } catch (Exception e) { e.printStackTrace(); } } public void selectAll() { mSelectedFiles.clear(); for (File file : mBaseDir.listFiles()) { mSelectedFiles.add(new FileSystemFile(file.getAbsolutePath())); } } public void unselectAll() { mSelectedFiles.clear(); } @Override public void openDirectory(String path) { File f = new File(path); if (isFileExists(f)) { openDirectory(f); } } @Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); } protected boolean onLongClick(View view, int i) { FileSystemAdapter adapter = getAdapter(); FileSystemFile file = (FileSystemFile) adapter.getItem(i); if (!file.isUpNavigator()) { mLastSelectedFile = file; updateLongClickSelection(adapter, file, true); if (!file.isVirtualDirectory()) { openFileActionMenu(); } } return true; } protected FileSystemAdapter getAdapter() { return (FileSystemAdapter) mFileSystemList.getAdapter(); } @Override public void onStart() { super.onStart(); if (isFileSystemPanel()) { openDirectory(mBaseDir != null ? mBaseDir : FileSystemScanner.sInstance.getRoot(), mLastListPosition); } } public void onResume() { super.onResume(); FileSystemAdapter adapter = getAdapter(); if (adapter != null) { adapter.setSelectedFiles(mSelectedFiles); adapter.notifyDataSetChanged(); setSelectedFilesSizeVisibility(); showQuickActionPanel(); } setIsActivePanel(mIsActivePanel); setNavigationButtonsVisibility(); mActionBar.updateBackground(); mSelectedFilesSize.setBackgroundColor(App.sInstance.getSettings().getSecondaryColor()); mSelectedFilesSize.setTextColor(App.sInstance.getSettings().getSelectedColor()); } @Override public void onStop() { super.onStop(); // Save ListView state if (isFileSystemPanel()) { mLastListPosition = ((LinearLayoutManager) mFileSystemList.getLayoutManager()).findFirstVisibleItemPosition(); } } @Override public void onAttach(Context context) { super.onAttach(context); // if (isFileSystemPanel()) { mSubscriptions = new CompositeSubscription(); mSubscriptions.add(RxBus.getInstance().observerFor(TaskCancelledEvent.class, getPanelLocation()). observeOn(AndroidSchedulers.mainThread()).subscribe(event -> { try { ErrorDialog.newInstance(TaskStatusEnum.getErrorString(TaskStatusEnum.CANCELED)).show(fragmentManager(), "errorDialog"); } catch (Exception e) { e.printStackTrace(); } })); mSubscriptions.add(RxBus.getInstance().observerFor(TaskErrorEvent.class, getPanelLocation()). observeOn(AndroidSchedulers.mainThread()).subscribe(event -> { if (event.status() == TaskStatusEnum.ERROR_STORAGE_PERMISSION_REQUIRED) { requestSdcardPermission(); } else if (event.status() == TaskStatusEnum.ERROR_EXTRACTING_ARCHIVE_FILES_ENCRYPTION_PASSWORD_REQUIRED) { try { RequestPasswordDialog.newInstance(mRequestPasswordCommand).show(fragmentManager(), "confirmDialog"); } catch (Exception e) { e.printStackTrace(); } } else if (event.status() == TaskStatusEnum.ERROR_FTP_DELETE_DIRECTORY) { // special case for s/ftp if (!App.sInstance.getSettings().isFtpAllowRecursiveDelete() && App.sInstance.getSettings().allowedToAskRecursiveDelete()) { new YesNoDontAskAgainDialog(getActivity()).show(); } } else { TaskStatusEnum status = event.status(); String error = status == TaskStatusEnum.ERROR_CREATE_DIRECTORY ? getSafeString(R.string.error_cannot_create_file, (String) event.extra()) : TaskStatusEnum.getErrorString(status, (String) event.extra()); if (status == TaskStatusEnum.ERROR_NETWORK && status.getNetworkErrorException() != null) { error = status.getNetworkErrorException().getLocalizedError(); } try { ErrorDialog.newInstance(error).show(fragmentManager(), "errorDialog"); } catch (Exception e) { e.printStackTrace(); } } })); mSubscriptions.add(RxBus.getInstance().observerFor(TaskOkEvent.class, getPanelLocation()). observeOn(AndroidSchedulers.mainThread()).subscribe(event -> { mSelectedFiles.clear(); mHandler.sendEmptyMessage(INVALIDATE); })); mSubscriptions.add(RxBus.getInstance().observerFor(TaskOkAndPostEvent.class, getPanelLocation()). observeOn(AndroidSchedulers.mainThread()).subscribe(event -> { mSelectedFiles.clear(); mHandler.sendEmptyMessage(INVALIDATE); event.getPostAction().run(); })); // } } @Override public void onDetach () { super.onDetach(); if (mQuickActionPopup != null) { getSelectedFiles().clear(); mQuickActionPopup.dismiss(); } if (mSubscriptions != null) { mSubscriptions.unsubscribe(); } } // @Override // public void onDestroy() { // if (mSubscriptions != null) { // mSubscriptions.unsubscribe(); // } // super.onDestroy(); // } @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_REQUEST_PERMISSION && Build.VERSION.SDK_INT >= 21 && data != null) { getActivity().getContentResolver().takePersistableUriPermission(data.getData(), Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); } } protected void updateLongClickSelection(FileSystemAdapter adapter, File file, boolean longClick) { FileSystemFile systemFile = (FileSystemFile) file; if (systemFile.isVirtualDirectory()) { ToastNotification.makeText(App.sInstance.getApplicationContext(), getSafeString(R.string.error_virtual_directories_not_permitted), Toast.LENGTH_SHORT).show(); return; } if(systemFile.isUpNavigator()) { return; } if (mSelectedFiles.contains(file) && !longClick) { mSelectedFiles.remove(file); } else { if (mSelectedFiles.contains(file)) { return; } mSelectedFiles.add(0, systemFile); } adapter.setSelectedFiles(mSelectedFiles); adapter.notifyDataSetChanged(); setSelectedFilesSizeVisibility(); calculateSelectedFilesSize(); showQuickActionPanel(); } protected void calculateSelectedFilesSize() { if (!App.sInstance.getSettings().isShowSelectedFilesSize()) { return; } long size = 0; for (FileProxy f : mSelectedFiles) { size += f.isDirectory() ? 0 : f.getSize(); } mSelectedFilesSize.setText(getString(R.string.selected_files, CustomFormatter.formatBytes(size), mSelectedFiles.size())); } public void showQuickActionPanel() { if (mQuickActionPopup == null) { return; } boolean showPanel = (isFileSystemPanel() || this instanceof NetworkPanel) && App.sInstance.getSettings().isShowQuickActionPanel() && getSelectedFilesCount() > 0; try { if (showPanel) { mQuickActionPopup.show(); } else { mQuickActionPopup.dismiss(); } } catch (Exception e) { e.printStackTrace(); } } public void openFileActionMenu() { showDialog(new com.openfarmanager.android.dialogs.FileActionDialog(getActivity(), getAvailableActions(), mFileActionHandler)); } protected FileActionEnum[] getAvailableActions() { return FileActionEnum.getAvailableActions(getSelectedFiles(), mLastSelectedFile); } public void executeAction(FileActionEnum action, final MainPanel inactivePanel) { boolean twoPanelAction = action == MOVE || action == COPY || action == ARCHIVE_EXTRACT; if (twoPanelAction) { if (inactivePanel == null) { ToastNotification.makeText(App.sInstance.getApplicationContext(), getSafeString(R.string.error_quick_view_operation_not_supported), Toast.LENGTH_SHORT).show(); return; } else if (inactivePanel instanceof ArchivePanel) { ToastNotification.makeText(App.sInstance.getApplicationContext(), getSafeString(R.string.error_archive_operation_not_supported), Toast.LENGTH_SHORT).show(); return; } else if (!(inactivePanel instanceof NetworkPanel) && !isFileExists(inactivePanel.getCurrentDir())) { ToastNotification.makeText(App.sInstance.getApplicationContext(), getSafeString(R.string.error_virtual_directories_not_permitted), Toast.LENGTH_SHORT).show(); return; } else if (this instanceof NetworkPanel && inactivePanel instanceof NetworkPanel) { ToastNotification.makeText(App.sInstance.getApplicationContext(), getSafeString(R.string.error_network_operation_not_supported), Toast.LENGTH_SHORT).show(); return; } else if (inactivePanel.isDataLoading()) { ToastNotification.makeText(App.sInstance.getApplicationContext(), getSafeString(R.string.error_inactive_panel_is_busy), Toast.LENGTH_SHORT).show(); return; } } int count = getSelectedFilesCount(); if (count == 0 && action != SET_AS_HOME) { // no operations can be performed return; } switch (action) { case INFO: info(); break; case SET_AS_HOME: App.sInstance.getSettings().setHomeFolder(mBaseDir.getAbsolutePath()); ToastNotification.makeText(App.sInstance.getApplicationContext(), getString(R.string.home_folder_updated), Toast.LENGTH_LONG).show(); break; case SEND: send(); break; case DELETE: delete(inactivePanel); break; case MOVE: move(inactivePanel, false); break; case COPY: copy(inactivePanel); break; case EDIT: Message message = mHandler.obtainMessage(FILE_OPEN, mLastSelectedFile.getAbsoluteFile()); message.arg1 = ARG_FORCE_OPEN_FILE_IN_EDITOR; mHandler.sendMessage(message); break; case RENAME: move(inactivePanel, true); break; case FILE_OPEN_WITH: openAs(mLastSelectedFile); break; case ARCHIVE_EXTRACT: extractArchive(inactivePanel); break; case CREATE_ARCHIVE: createArchive(inactivePanel); break; case EXPORT_AS: mHandler.sendMessage(mHandler.obtainMessage(FileSystemController.EXPORT_AS, getSelectedFile())); break; case OPEN_WEB: mHandler.sendMessage(mHandler.obtainMessage(FileSystemController.OPEN_WEB, getSelectedFile())); break; case COPY_PATH: if (mSelectedFiles.size() == 1) { android.text.ClipboardManager clipboard = (android.text.ClipboardManager) App.sInstance.getSystemService(Context.CLIPBOARD_SERVICE); clipboard.setText(mSelectedFiles.get(0).getFullPathRaw()); ToastNotification.makeText(App.sInstance.getApplicationContext(), getString(R.string.path_copied), Toast.LENGTH_SHORT).show(); } break; case ADD_STAR: mHandler.sendMessage(mHandler.obtainMessage(FileSystemController.ADD_STAR, getSelectedFile())); break; case REMOVE_STAR: mHandler.sendMessage(mHandler.obtainMessage(FileSystemController.REMOVE_STAR, getSelectedFile())); break; case SHARE: mHandler.sendMessage(mHandler.obtainMessage(FileSystemController.SHARE, getSelectedFile())); break; } } private FileProxy getSelectedFile() { return mSelectedFiles.size() == 1 ? mSelectedFiles.get(0) : null; } private boolean isFileExists(File file) { return file != null && file.exists(); } private void info() { try { InfoDialog.newInstance(mLastSelectedFile.getAbsolutePath()).show(fragmentManager(), "confirmDialog"); } catch (Exception e) { e.printStackTrace(); } } public void send() { Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(mLastSelectedFile)); String extension = MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(mLastSelectedFile).toString()); shareIntent.setType(MimeTypes.lookupMimeType(extension)); startActivity(Intent.createChooser(shareIntent, getSafeString(R.string.action_share_to))); } public void move(final MainPanel inactivePanel, boolean forceRename) { boolean rename = forceRename; if (inactivePanel.isFileSystemPanel() && isFileSystemPanel()) { boolean isTheSameFolders = FileUtilsExt.isTheSameFolders(getSelectedFiles(), inactivePanel.getCurrentDir()); rename = forceRename || isTheSameFolders && getSelectedFiles().size() == 1; } showDialog(new CopyMoveFileDialog(getActivity(), mFileActionHandler, inactivePanel, rename, rename ? getSelectedFileProxies().get(0).getName() : inactivePanel.getCurrentPath())); } public void createBookmark(final MainPanel inactivePanel) { showDialog(new CreateBookmarkDialog(getActivity(), mFileActionHandler, inactivePanel, mBaseDir.getAbsolutePath())); } public void delete(final MainPanel inactivePanel) { showDialog(new DeleteFileDialog(getActivity(), mFileActionHandler, inactivePanel)); } public void createFile(final MainPanel inactivePanel) { showDialog(new CreateFileDialog(getActivity(), mFileActionHandler, inactivePanel, this instanceof NetworkPanel)); } public void showDialog(Dialog dialog) { dialog.show(); adjustDialogSize(dialog); } public void showSelectDialog() { showDialog(new SelectDialog(getActivity(), mSelectFilesCommand)); } public void showSearchDialog() { if (!isSearchSupported()) { ToastNotification.makeText(App.sInstance.getApplicationContext(), getSafeString(R.string.error_search_not_supported, getPanelType()), Toast.LENGTH_SHORT).show(); return; } final boolean isNetworkPanel = this instanceof NetworkPanel; showDialog(new SearchActionDialog(getActivity(), mFileActionHandler, null, isNetworkPanel)); } public void copy(final MainPanel inactivePanel) { showDialog(new CopyMoveFileDialog(getActivity(), mFileActionHandler, inactivePanel)); } public void export(BaseFileSystemPanel panel, String downloadLink, String destination) { new ExportAsCommand(panel, downloadLink, destination).execute(); } public void updateGoogleDriveData(MainPanel panel, String fileId, String data) { new GoogleDriveUpdateCommand(panel, fileId, data).execute(); } public void doDropboxTask(DropboxFile file, int dropboxTask) { new DropboxCommand(this, file, dropboxTask); } public void extractArchive(final MainPanel inactivePanel) { String extractFileName = mLastSelectedFile.getName(); try { extractFileName = mLastSelectedFile.getName().split("\\.")[0]; } catch (Exception ignore) { } String defaultPath = inactivePanel.getCurrentDir().getAbsolutePath(); if (!defaultPath.endsWith(File.separator)) { defaultPath += File.separator; } defaultPath += extractFileName; final boolean isCompressed = ArchiveUtils.isCompressionSupported(mLastSelectedFile); showDialog(new ExtractArchiveDialog(getActivity(), mFileActionHandler, inactivePanel, isCompressed, defaultPath)); } public void createArchive(final MainPanel inactivePanel) { showDialog(new CreateArchiveDialog(getActivity(), mFileActionHandler, inactivePanel, mSelectedFiles.size() > 0 ? mSelectedFiles.get(0).getName() : "")); } @Override public void invalidatePanels(MainPanel inactivePanel) { invalidatePanels(inactivePanel, true); } @Override public void invalidatePanels(MainPanel inactivePanel, boolean force) { getSelectedFiles().clear(); invalidate(); // inactivePanel may be null when 'quick view' is opened. if (inactivePanel != null) { try { if (force || isTheSameFolders(inactivePanel)) { inactivePanel.invalidate(); } } catch (Exception ignore) { } } } public void restoreState(String currentPath, boolean isActive) { File currentFile = new File(currentPath); setCurrentDir(currentFile); openDirectory(currentFile); setIsActivePanel(isActive); } public void invalidate() { invalidate(true); } /** * Reload panel with <code>mSelectedFiles</code>. * * @see MainPanel#mSelectedFiles * @param forceReloadFiles force panel to reload files. */ public void invalidate(boolean forceReloadFiles) { if (mFileSystemList != null) { FileSystemAdapter adapter = getAdapter(); adapter.setBaseDir(mBaseDir); adapter.setSelectedFiles(mSelectedFiles); adapter.notifyDataSetChanged(); setSelectedFilesSizeVisibility(); calculateSelectedFilesSize(); showQuickActionPanel(); } } private void openFile(File item) { mHandler.sendMessage(mHandler.obtainMessage(FILE_OPEN, item.getAbsoluteFile())); } private void openAs(File item) { mHandler.sendMessage(mHandler.obtainMessage(OPEN_WITH, item.getAbsoluteFile())); } public void setIsMultiSelectMode(boolean value) { mIsMultiSelectMode = value; } public boolean switchMultiSelectMode() { return (mIsMultiSelectMode = !mIsMultiSelectMode); } public void setupHandler() { if (App.sInstance.getFileSystemController() != null) { mHandler = App.sInstance.getFileSystemController().getPanelHandler(); } } public void setHandler(Handler handler) { mHandler = handler; } public FileProxy getLastSelectedFile() { return mLastSelectedFile instanceof FileProxy ? (FileProxy) mLastSelectedFile : null; } public List<FileProxy> getSelectedFileProxies() { return mSelectedFiles; } public int getSelectedFilesCount() { return mSelectedFiles.size(); } public List<File> getSelectedFiles() { try { // if (mSelectedFiles.size() == 0 && mFileSystemList != null && mFileSystemList.getSelectedItem() instanceof FileSystemFile) { // mSelectedFiles.add((FileSystemFile) mFileSystemList.getSelectedItem()); // } } catch (Exception ignore) {} //noinspection unchecked return (List) mSelectedFiles; } // TODO: for list of files use always Set instead of List (to avoid duplicated files). public Set<File> getAllFiles() { LinkedHashSet<File> allFiles = new LinkedHashSet<File>(); try { Collections.addAll(allFiles, mBaseDir.listFiles()); } catch (Exception ignore) {} return allFiles; } public String getCurrentPath() { return mBaseDir.getAbsolutePath(); } public File getCurrentDir() { return mBaseDir; } public void setCurrentDir(File dir) { mBaseDir = dir; } public boolean isActive() { return mIsActivePanel; } public void setIsActivePanel(final boolean active) { if (!mIsInitialized) { addToPendingList(() -> setIsActivePanel(active)); return; } mIsActivePanel = active; mActionBar.setActive(active); if (active && mFileSystemList != null) { mFileSystemList.requestFocus(); } } public void setNavigationButtonsVisibility() { setNavigationButtonsVisibility(false); } public void forceHideNavigationButtons() { setNavigationButtonsVisibility(true); } protected void setNavigationButtonsVisibility(final boolean forceHide) { if (!mIsInitialized) { addToPendingList(() -> setNavigationButtonsVisibility(forceHide)); return; } mActionBar.updateNavigationItemsVisibility(forceHide, isCopyFolderSupported(), isBookmarksSupported()); } public boolean isRootDirectory() { if (App.sInstance.getSettings().isSDCardRoot()) { return mBaseDir.getAbsolutePath().equals(StorageUtils.getSdPath()); } return mBaseDir.getAbsolutePath().equals("/"); } /** * Is 'move to folder' supported - buttons near the path to change path of inactive panel. * Must be ovveriden for subclasses. * * @return <code>true</code> */ protected boolean isCopyFolderSupported() { return true; } protected boolean isBookmarksSupported() { return true; } public void openDirectory(final File directory) { openDirectory(directory, null); } /** * Open directory with "selection", i.e. scrolling file system list to certain position. * * @param directory folder to be opened. * @param selection position in list to be selected (scrolled). */ private void openDirectory(final File directory, final Integer selection) { if (!mIsInitialized) { addToPendingList(() -> openDirectory(directory, selection)); return; } setSelectedFilesSizeVisibility(); showQuickActionPanel(); FileSystemAdapter adapter = getAdapter(); if (adapter == null) { mFileSystemList.initAdapter(new FileSystemAdapter(mBaseDir, selection, mAction)); } else { adapter.resetFilter(); adapter.setBaseDir(directory.getAbsoluteFile(), selection); } } protected void setSelectedFilesSizeVisibility() { mSelectedFilesSize.setVisibility((!App.sInstance.getSettings().isShowSelectedFilesSize() || mSelectedFiles.size() == 0) ? View.GONE : View.VISIBLE); } private void sendEmptyMessage(int message) { if (mHandler != null) { mHandler.sendEmptyMessage(message); } } @Override public int select(SelectParams selectParams) { if (mBaseDir == null) { // handle unexpected situation. return 0; } mSelectedFiles.clear(); if (selectParams.getType() == SelectParams.SelectionType.NAME) { String pattern = selectParams.getSelectionString(); boolean inverseSelection = selectParams.isInverseSelection(); App.sInstance.getSharedPreferences("action_dialog", 0).edit(). putString("select_pattern", pattern).apply(); FileFilter select = new WildcardFileFilter(pattern); File[] contents = mBaseDir.listFiles(select); if (contents != null) { if (inverseSelection) { File[] allFiles = mBaseDir.listFiles(); List selection = Arrays.asList(contents); for (File file : allFiles) { if (!selection.contains(file)) { mSelectedFiles.add(new FileSystemFile(file.getAbsolutePath())); } } } else { for (File file : contents) { mSelectedFiles.add(new FileSystemFile(file.getAbsolutePath())); } } } } else { File[] allFiles = mBaseDir.listFiles(); if (selectParams.isTodayDate()) { Calendar today = Calendar.getInstance(); Calendar currentDay = Calendar.getInstance(); for (File file : allFiles) { currentDay.setTime(new Date(file.lastModified())); if (isSameDay(today, currentDay)) { mSelectedFiles.add(new FileSystemFile(file.getAbsolutePath())); } } } else { long startDate = selectParams.getDateFrom().getTime(); long endDate = selectParams.getDateTo().getTime(); for (File file : allFiles) { if (file.lastModified() > startDate && file.lastModified() < endDate) { mSelectedFiles.add(new FileSystemFile(file.getAbsolutePath())); } } } } FileSystemAdapter adapter = getAdapter(); adapter.setSelectedFiles(mSelectedFiles); adapter.notifyDataSetChanged(); setSelectedFilesSizeVisibility(); calculateSelectedFilesSize(); showQuickActionPanel(); return mSelectedFiles.size(); } /** * <p>Checks if two calendars represent the same day ignoring time.</p> * @param cal1 the first calendar, not altered, not null * @param cal2 the second calendar, not altered, not null * @return true if they represent the same day * @throws IllegalArgumentException if either calendar is <code>null</code> */ public static boolean isSameDay(Calendar cal1, Calendar cal2) { if (cal1 == null || cal2 == null) { throw new IllegalArgumentException("The dates must not be null"); } return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)); } public void addSelectedFiles(LinkedHashSet<File> selectedFiles) { for (File file : selectedFiles) { FileSystemFile systemFile = new FileSystemFile(file.getAbsolutePath()); if (!mSelectedFiles.contains(systemFile)) { mSelectedFiles.add(systemFile); } } final FileSystemAdapter adapter = getAdapter(); adapter.setSelectedFiles(mSelectedFiles); getActivity().runOnUiThread(new Runnable() { @Override public void run() { adapter.notifyDataSetChanged(); } }); } public void navigateParent() { if (!isRootDirectory()) { // get parent file File parentFile = mBaseDir.getParentFile(); Integer selection = null; if (parentFile != null) { selection = mDirectorySelection.get(parentFile.getAbsolutePath()); } // in case of parent file is null (for example, mBaseDir is already root. this shouldn't be happened) // use current dir. openDirectory(parentFile == null ? mBaseDir : parentFile, selection); } } /** * Determines when both panels (this and inactive) have the same type (local or network) * and open the same folder. * * @return <code>true</code> when folders are the same ond opened the same folders, <code>false</code> otherwise. */ private boolean isTheSameFolders(MainPanel inactivePanel) { return getClass() == inactivePanel.getClass() && getCurrentPath().equals(inactivePanel.getCurrentPath()); } /** * Post runnable command with handle if fragment is attached to activity. * * @param runnable task to pe executed. */ protected void postIfAttached(Runnable runnable) { //if (isAdded()) { mHandler.post(runnable); //} } public void filter(String obj) { (getAdapter()).filter(obj); } public void selectCurrentFile(int direction) { int position = ((LinearLayoutManager) mFileSystemList.getLayoutManager()).findFirstVisibleItemPosition(); FileSystemAdapter adapter = getAdapter(); FileProxy currentFile; try { currentFile = (FileProxy) adapter.getItem(position); } catch (Exception e) { e.printStackTrace(); return; } if (position > 0) { if (mSelectedFiles.contains(currentFile)) { mSelectedFiles.remove(currentFile); } else { mSelectedFiles.add(currentFile); } adapter.setSelectedFiles(mSelectedFiles); adapter.notifyDataSetChanged(); } ((LinearLayoutManager) mFileSystemList.getLayoutManager()).scrollToPositionWithOffset(position + direction, 0); } protected void setIsLoading(boolean isLoading) { mProgress.setVisibility(isLoading ? View.VISIBLE : View.GONE); mFileSystemList.setVisibility(isLoading ? View.GONE : View.VISIBLE); mActionBar.setVisibility(isLoading ? View.GONE : View.VISIBLE); if (isActive()) { mFileSystemList.requestFocus(); } mIsDataLoading = isLoading; } private OpenDirectoryActionListener mAction = new OpenDirectoryActionListener() { @Override public void onDirectoryOpened(File directory, Integer selection) { mBaseDir = directory.getAbsoluteFile(); mActionBar.updateCurrentPath(mBaseDir.getAbsolutePath()); sendEmptyMessage(DIRECTORY_CHANGED); LinearLayoutManager manager = (LinearLayoutManager) mFileSystemList.getLayoutManager(); manager.scrollToPositionWithOffset(selection != null ? selection : 0, 0); } @Override public void onError() { ToastNotification.makeText(App.sInstance.getApplicationContext(), App.sInstance.getString(R.string.cannot_open_directory), Toast.LENGTH_SHORT).show(); } }; protected Handler mFileActionHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case FILE_CREATE: final CreateFileDialog.NewFileResult newFileResult = (CreateFileDialog.NewFileResult) msg.obj; executeCommand(new Runnable() { @Override public void run() { CommandsFactory.getCreateNewCommand(MainPanel.this).execute(newFileResult.inactivePanel, newFileResult.destination, newFileResult.isFolder); } }); break; case FILE_DELETE: final DeleteFileDialog.DeleteFileResult deleteFileResult = (DeleteFileDialog.DeleteFileResult) msg.obj; executeCommand(new Runnable() { @Override public void run() { CommandsFactory.getDeleteCommand(MainPanel.this).execute(deleteFileResult.inactivePanel, deleteFileResult.destination, getLastSelectedFile()); } } ); break; case FILE_COPY: CopyMoveFileDialog.CopyMoveFileResult copyMoveFileResult = (CopyMoveFileDialog.CopyMoveFileResult) msg.obj; getCopyToCommand(copyMoveFileResult.inactivePanel, new File(copyMoveFileResult.destination)).execute( copyMoveFileResult.inactivePanel, copyMoveFileResult.destination); break; case FILE_MOVE: copyMoveFileResult = (CopyMoveFileDialog.CopyMoveFileResult) msg.obj; getMoveCommand(copyMoveFileResult.inactivePanel, copyMoveFileResult).execute(copyMoveFileResult.inactivePanel, copyMoveFileResult.destination, null, copyMoveFileResult.isRename); break; case FILE_CREATE_BOOKMARK: CreateBookmarkDialog.CreateBookmarkResult createBookmarkResult = (CreateBookmarkDialog.CreateBookmarkResult) msg.obj; new CreateBookmarkCommand(createBookmarkResult.inactivePanel, createBookmarkResult.link, createBookmarkResult.label, createBookmarkResult.networkAccount).execute(); break; case FILE_EXTRACT_ARCHIVE: mExtractArchiveResult = (ExtractArchiveDialog.ExtractArchiveResult) msg.obj; getExtractArchiveCommand(mExtractArchiveResult, getArchivePassword()).execute(mExtractArchiveResult.inactivePanel, mExtractArchiveResult.destination, getArchivePassword(), mExtractArchiveResult.isCompressed); break; case FILE_CREATE_ARCHIVE: CreateArchiveDialog.CreateArchiveResult createArchiveResult = (CreateArchiveDialog.CreateArchiveResult) msg.obj; getCreateArchiveCommand(createArchiveResult).execute(createArchiveResult.inactivePanel, createArchiveResult.archiveName, createArchiveResult.archiveType, createArchiveResult.isCompressionEnabled, createArchiveResult.compression); break; case SELECT_ACTION: mHandler.sendMessage(Message.obtain(mHandler, FILE_ACTION, msg.obj)); break; case SEARCH_ACTION: try { SearchActionDialog.SearchActionResult result = (SearchActionDialog.SearchActionResult) msg.obj; showDialog(new SearchResultDialog(getActivity(), result.isNetworkPanel ? ((NetworkPanel) MainPanel.this).getNetworkType() : null, getCurrentPath(), result, new SearchResultDialog.SearchResultListener() { @Override public void onGotoFile(final FileProxy fileProxy) { if (MainPanel.this instanceof NetworkPanel) { gotoSearchFile(fileProxy); } else { final File file = (FileSystemFile) fileProxy; openDirectory(file.isDirectory() ? file : file.getParentFile()); if (!file.isDirectory()) { addSelectedFiles(new LinkedHashSet<File>() {{ add(file); }}); calculateSelectedFilesSize(); } invalidate(); } } @Override public void onViewFile(FileProxy fileProxy) { File file = (FileSystemFile) fileProxy; if (file.isDirectory()) { setCurrentDir(file); invalidate(); } else { openFile(file); } } @Override public void onResetSearch() { showSearchDialog(); } })); } catch (Exception e) { } break; } } }; public void executeCommand(Runnable runnable) { try { runnable.run(); } catch (SdcardPermissionException e) { requestSdcardPermission(); } } protected void gotoSearchFile(FileProxy file) { } protected boolean isDataLoading() { return mIsDataLoading; } public boolean isFileSystemPanel() { return true; } public boolean isSearchSupported() { return true; } public String getPanelType() { return "File System"; } }