Swati4star/Images-to-PDF

View on GitHub
app/src/main/java/swati4star/createpdf/adapter/ViewFilesAdapter.java

Summary

Maintainability
B
6 hrs
Test Coverage
package swati4star.createpdf.adapter;

import static swati4star.createpdf.util.Constants.SORTING_INDEX;
import static swati4star.createpdf.util.FileInfoUtils.getFormattedDate;

import android.app.Activity;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.RecyclerView;

import com.afollestad.materialdialogs.MaterialDialog;
import com.balysv.materialripple.MaterialRippleLayout;
import com.google.android.material.snackbar.Snackbar;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import butterknife.BindView;
import butterknife.ButterKnife;
import swati4star.createpdf.R;
import swati4star.createpdf.database.DatabaseHelper;
import swati4star.createpdf.interfaces.DataSetChanged;
import swati4star.createpdf.interfaces.EmptyStateChangeListener;
import swati4star.createpdf.interfaces.ItemSelectedListener;
import swati4star.createpdf.model.PDFFile;
import swati4star.createpdf.util.DialogUtils;
import swati4star.createpdf.util.DirectoryUtils;
import swati4star.createpdf.util.FileInfoUtils;
import swati4star.createpdf.util.FileSortUtils;
import swati4star.createpdf.util.FileUtils;
import swati4star.createpdf.util.PDFEncryptionUtility;
import swati4star.createpdf.util.PDFRotationUtils;
import swati4star.createpdf.util.PDFUtils;
import swati4star.createpdf.util.PopulateList;
import swati4star.createpdf.util.StringUtils;
import swati4star.createpdf.util.WatermarkUtils;

/**
 * Created by swati on 9/10/15.
 * <p>
 * An adapter to view the existing PDF files
 */

public class ViewFilesAdapter extends RecyclerView.Adapter<ViewFilesAdapter.ViewFilesHolder>
        implements DataSetChanged, EmptyStateChangeListener {

    private final Activity mActivity;
    private final EmptyStateChangeListener mEmptyStateChangeListener;
    private final ItemSelectedListener mItemSelectedListener;
    private final ArrayList<Integer> mSelectedFiles;
    private final FileUtils mFileUtils;
    private final PDFUtils mPDFUtils;
    private final PDFRotationUtils mPDFRotationUtils;
    private final WatermarkUtils mWatermarkUtils;
    private final PDFEncryptionUtility mPDFEncryptionUtils;
    private final DatabaseHelper mDatabaseHelper;
    private final SharedPreferences mSharedPreferences;

    private List<PDFFile> mFileList;

    /**
     * Returns adapter instance
     *
     * @param activity                 the activity calling this adapter
     * @param feedItems                list containing {@link PDFFile}
     * @param emptyStateChangeListener interface for empty state change
     * @param itemSelectedListener     interface for monitoring the status of file selection
     */
    public ViewFilesAdapter(Activity activity,
                            List<PDFFile> feedItems,
                            EmptyStateChangeListener emptyStateChangeListener,
                            ItemSelectedListener itemSelectedListener) {
        this.mActivity = activity;
        this.mEmptyStateChangeListener = emptyStateChangeListener;
        this.mItemSelectedListener = itemSelectedListener;
        this.mFileList = feedItems;
        mSelectedFiles = new ArrayList<>();
        mFileUtils = new FileUtils(activity);
        mPDFUtils = new PDFUtils(activity);
        mPDFRotationUtils = new PDFRotationUtils(activity);
        mPDFEncryptionUtils = new PDFEncryptionUtility(activity);
        mWatermarkUtils = new WatermarkUtils(activity);
        mDatabaseHelper = new DatabaseHelper(mActivity);
        mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(mActivity);
    }

    @NonNull
    @Override
    public ViewFilesHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_file, parent, false);
        return new ViewFilesHolder(itemView, mItemSelectedListener);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewFilesHolder holder, final int pos) {
        final int position = holder.getAdapterPosition();
        final PDFFile pdfFile = mFileList.get(position);

        holder.fileName.setText(pdfFile.getPdfFile().getName());
        holder.fileSize.setText(FileInfoUtils.getFormattedSize(pdfFile.getPdfFile()));
        holder.fileDate.setText(getFormattedDate(pdfFile.getPdfFile()));
        holder.checkBox.setChecked(mSelectedFiles.contains(position));
        holder.encryptionImage.setVisibility(pdfFile.isEncrypted() ? View.VISIBLE : View.GONE);
        holder.ripple.setOnClickListener(view -> {
            new MaterialDialog.Builder(mActivity)
                    .title(R.string.title)
                    .items(R.array.items)
                    .itemsIds(R.array.itemIds)
                    .itemsCallback((dialog, view1, which, text)
                            -> performOperation(which, position, pdfFile.getPdfFile()))
                    .show();
            notifyDataSetChanged();
        });
    }

    /**
     * Performs the required option on file
     * as per user selection
     *
     * @param index    - index of operation performed
     * @param position - position of item clicked
     * @param file     - file object clicked
     */
    private void performOperation(int index, int position, File file) {
        switch (index) {
            case 0: //Open
                mFileUtils.openFile(file.getPath(), FileUtils.FileType.e_PDF);
                break;

            case 1: //delete
                deleteFile(position);
                break;

            case 2: //rename
                onRenameFileClick(position);
                break;

            case 3: //Print
                mFileUtils.printFile(file);
                break;

            case 4: //Email
                mFileUtils.shareFile(file);
                break;

            case 5: //Details
                mPDFUtils.showDetails(file);
                break;

            case 6://Password Set
                mPDFEncryptionUtils.setPassword(file.getPath(), ViewFilesAdapter.this);
                break;

            case 7://Password Remove
                mPDFEncryptionUtils.removePassword(file.getPath(), ViewFilesAdapter.this);
                break;

            case 8://Rotate Pages
                mPDFRotationUtils.rotatePages(file.getPath(), ViewFilesAdapter.this);
                break;

            case 9: // Add Watermark
                mWatermarkUtils.setWatermark(file.getPath(), ViewFilesAdapter.this);
                break;
        }
    }

    /**
     * Checks all the PDFs list
     */
    public void checkAll() {
        mSelectedFiles.clear();
        for (int i = 0; i < mFileList.size(); i++)
            mSelectedFiles.add(i);
        notifyDataSetChanged();
    }

    /**
     * unchecks every item in the item
     */
    public void unCheckAll() {
        mSelectedFiles.clear();
        notifyDataSetChanged();
        updateActionBarTitle();
    }

    /**
     * Sets the action bar title to app name when all files have been unchecked
     */
    private void updateActionBarTitle() {
        mActivity.setTitle(R.string.app_name);
    }

    /**
     * Returns path of selected files
     *
     * @return paths of files
     */
    public ArrayList<String> getSelectedFilePath() {
        ArrayList<String> filePathList = new ArrayList<>();
        for (int position : mSelectedFiles) {
            if (mFileList.size() > position)
                filePathList.add(mFileList.get(position).getPdfFile().getPath());
        }
        return filePathList;
    }

    @Override
    public int getItemCount() {
        return mFileList == null ? 0 : mFileList.size();
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    /**
     * Sets pdf files
     *
     * @param pdfFiles list containing {@link PDFFile}
     */
    public void setData(List<PDFFile> pdfFiles) {
        mFileList = pdfFiles;
        notifyDataSetChanged();
    }

    /**
     * get {@link PDFUtils} bound with this adapter
     *
     * @return the Pdf Utils
     */
    public PDFUtils getPDFUtils() {
        return mPDFUtils;
    }

    /**
     * Checks if any item is selected
     *
     * @return tru, if at least one item is checked
     */
    public boolean areItemsSelected() {
        return mSelectedFiles.size() > 0;
    }

    /**
     * Deletes all selected files
     */
    public void deleteFile() {
        deleteFiles(mSelectedFiles);
    }

    /**
     * Delete single file
     */
    private void deleteFile(int position) {
        if (position < 0 || position >= mFileList.size())
            return;

        ArrayList<Integer> files = new ArrayList<>();
        files.add(position);
        deleteFiles(files);
    }

    /**
     * Shows an alert to delete files and
     * iterate through filelist and deletes
     * all files on positive response
     */
    private void deleteFiles(ArrayList<Integer> files) {

        int messageAlert, messageSnackbar;
        if (files.size() > 1) {
            messageAlert = R.string.delete_alert_selected;
            messageSnackbar = R.string.snackbar_files_deleted;
        } else {
            messageAlert = R.string.delete_alert_singular;
            messageSnackbar = R.string.snackbar_file_deleted;
        }

        AlertDialog.Builder dialogAlert = new AlertDialog.Builder(mActivity)
                .setCancelable(true)
                .setNegativeButton(R.string.cancel, (dialogInterface, i) -> dialogInterface.dismiss())
                .setTitle(messageAlert)
                .setPositiveButton(R.string.yes, (dialog, which) -> {
                    ArrayList<String> filePath = new ArrayList<>();

                    for (int position : files) {
                        if (position >= mFileList.size())
                            continue;
                        filePath.add(mFileList.get(position).getPdfFile().getPath());
                        mFileList.remove(position);
                    }

                    mSelectedFiles.clear();
                    files.clear();
                    updateActionBarTitle();
                    notifyDataSetChanged();

                    if (mFileList.size() == 0)
                        mEmptyStateChangeListener.setEmptyStateVisible();

                    AtomicInteger undoClicked = new AtomicInteger();
                    StringUtils.getInstance().getSnackbarwithAction(mActivity, messageSnackbar)
                            .setAction(R.string.snackbar_undoAction, v -> {
                                if (mFileList.size() == 0) {
                                    mEmptyStateChangeListener.setEmptyStateInvisible();
                                }
                                updateDataset();
                                undoClicked.set(1);
                            }).addCallback(new Snackbar.Callback() {
                                @Override
                                public void onDismissed(Snackbar snackbar, int event) {
                                    if (undoClicked.get() == 0) {
                                        for (String path : filePath) {
                                            File fdelete = new File(path);
                                            mDatabaseHelper.insertRecord(fdelete.getAbsolutePath(),
                                                    mActivity.getString(R.string.deleted));
                                            if (fdelete.exists() && !fdelete.delete())
                                                StringUtils.getInstance().showSnackbar(mActivity,
                                                        R.string.snackbar_file_not_deleted);
                                        }
                                    }
                                }
                            }).show();
                });
        dialogAlert.create().show();
    }

    /**
     * Opens file sharer for selected files
     */
    public void shareFiles() {
        ArrayList<File> files = new ArrayList<>();
        for (int position : mSelectedFiles) {
            if (mFileList.size() > position)
                files.add(mFileList.get(position).getPdfFile());
        }
        mFileUtils.shareMultipleFiles(files);
    }

    /**
     * Renames the selected file
     *
     * @param position - position of file to be renamed
     */
    private void onRenameFileClick(final int position) {
        new MaterialDialog.Builder(mActivity)
                .title(R.string.creating_pdf)
                .content(R.string.enter_file_name)
                .input(mActivity.getString(R.string.example), null, (dialog, input) -> {
                    if (input == null || input.toString().trim().isEmpty())
                        StringUtils.getInstance().showSnackbar(mActivity, R.string.snackbar_name_not_blank);
                    else {
                        if (!mFileUtils.isFileExist(input + mActivity.getString(R.string.pdf_ext))) {
                            renameFile(position, input.toString());
                        } else {
                            MaterialDialog.Builder builder = DialogUtils.getInstance().createOverwriteDialog(mActivity);
                            builder.onPositive((dialog2, which) -> renameFile(position, input.toString()))
                                    .onNegative((dialog1, which) -> onRenameFileClick(position))
                                    .show();
                        }
                    }
                }).show();
    }

    private void renameFile(int position, String newName) {
        PDFFile pdfFile = mFileList.get(position);
        File oldfile = pdfFile.getPdfFile();
        String oldPath = oldfile.getPath();
        String newfilename = oldPath.substring(0, oldPath.lastIndexOf('/'))
                + "/" + newName + mActivity.getString(R.string.pdf_ext);
        File newfile = new File(newfilename);
        if (oldfile.renameTo(newfile)) {
            StringUtils.getInstance().showSnackbar(mActivity, R.string.snackbar_file_renamed);
            pdfFile.setPdfFile(newfile);
            notifyDataSetChanged();
            mDatabaseHelper.insertRecord(newfilename, mActivity.getString(R.string.renamed));
        } else
            StringUtils.getInstance().showSnackbar(mActivity, R.string.snackbar_file_not_renamed);
    }

    @Override
    public void updateDataset() {
        int index = mSharedPreferences.getInt(SORTING_INDEX, FileSortUtils.getInstance().NAME_INDEX);
        new PopulateList(this, this,
                new DirectoryUtils(mActivity), index, null).execute();
    }

    @Override
    public void setEmptyStateVisible() {

    }

    @Override
    public void setEmptyStateInvisible() {

    }

    @Override
    public void showNoPermissionsView() {

    }

    @Override
    public void hideNoPermissionsView() {

    }

    @Override
    public void filesPopulated() {

    }

    class ViewFilesHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.fileRipple)
        MaterialRippleLayout ripple;
        @BindView(R.id.fileName)
        TextView fileName;
        @BindView(R.id.checkbox)
        CheckBox checkBox;
        @BindView(R.id.fileDate)
        TextView fileDate;
        @BindView(R.id.fileSize)
        TextView fileSize;
        @BindView(R.id.encryptionImage)
        ImageView encryptionImage;

        ViewFilesHolder(View itemView, ItemSelectedListener itemSelectedListener) {
            super(itemView);
            ButterKnife.bind(this, itemView);
            checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
                if (isChecked) {
                    if (!mSelectedFiles.contains(getAdapterPosition())) {
                        mSelectedFiles.add(getAdapterPosition());
                        itemSelectedListener.isSelected(true, mSelectedFiles.size());
                    }
                } else
                    mSelectedFiles.remove(Integer.valueOf(getAdapterPosition()));
                itemSelectedListener.isSelected(false, mSelectedFiles.size());
            });
        }
    }
}