org.kiwix.kiwixmobile.zim_manager.fileselect_view.ZimFileSelectFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.kiwix.kiwixmobile.zim_manager.fileselect_view.ZimFileSelectFragment.java

Source

/*
 * Copyright 2013  Rashiq Ahmad <rashiq.z@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU  General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

package org.kiwix.kiwixmobile.zim_manager.fileselect_view;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.kiwix.kiwixmobile.KiwixApplication;
import org.kiwix.kiwixmobile.KiwixMobileActivity;
import org.kiwix.kiwixmobile.R;
import org.kiwix.kiwixmobile.ZimContentProvider;
import org.kiwix.kiwixmobile.database.BookDao;
import org.kiwix.kiwixmobile.database.KiwixDatabase;
import org.kiwix.kiwixmobile.library.LibraryAdapter;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
import org.kiwix.kiwixmobile.utils.BookUtils;
import org.kiwix.kiwixmobile.utils.LanguageUtils;
import org.kiwix.kiwixmobile.utils.TestingUtils;
import org.kiwix.kiwixmobile.utils.files.FileSearch;
import org.kiwix.kiwixmobile.utils.files.FileUtils;
import org.kiwix.kiwixmobile.zim_manager.ZimManageActivity;
import org.kiwix.kiwixmobile.zim_manager.library_view.LibraryFragment;

import javax.inject.Inject;

import static org.kiwix.kiwixmobile.utils.NetworkUtils.parseURL;
import static org.kiwix.kiwixmobile.utils.StyleUtils.dialogStyle;

public class ZimFileSelectFragment extends Fragment
        implements OnItemClickListener, AdapterView.OnItemLongClickListener, ZimFileSelectViewCallback {

    public static final String TAG_KIWIX = "kiwix";
    public static ZimManageActivity context;
    public RelativeLayout llLayout;
    private RescanDataAdapter mRescanAdapter;
    private ArrayList<LibraryNetworkEntity.Book> mFiles;
    private ListView mZimFileList;
    private RelativeLayout progressBar;
    private TextView mFileMessage;

    private BookDao bookDao;

    @Inject
    ZimFileSelectPresenter presenter;
    @Inject
    BookUtils bookUtils;

    private void setupDagger() {
        KiwixApplication.getInstance().getApplicationComponent().inject(this);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        context = (ZimManageActivity) super.getActivity();
        setupDagger();
        presenter.attachView(this);
        // Replace LinearLayout by the type of the root element of the layout you're trying to load
        llLayout = (RelativeLayout) inflater.inflate(R.layout.zim_list, container, false);
        new LanguageUtils(super.getActivity()).changeFont(super.getActivity().getLayoutInflater());

        mFileMessage = (TextView) llLayout.findViewById(R.id.file_management_no_files);
        mZimFileList = (ListView) llLayout.findViewById(R.id.zimfilelist);

        mFiles = new ArrayList<>();
        progressBar = (RelativeLayout) super.getActivity().getLayoutInflater().inflate(R.layout.progress_bar, null);

        mRescanAdapter = new RescanDataAdapter(ZimFileSelectFragment.context, 0, mFiles);

        // Allow temporary use of ZimContentProvider to query books
        ZimContentProvider.canIterate = true;

        presenter.loadLocalZimFileFromDb(context);
        bookDao = new BookDao(KiwixDatabase.getInstance(context));

        return llLayout; // We must return the loaded Layout
    }

    // Set zim file and return
    public static void finishResult(String path) {
        ZimManageActivity zimManageActivity = context;
        if (path != null) {
            File file = new File(path);
            Uri uri = Uri.fromFile(file);
            Log.i(TAG_KIWIX, "Opening " + uri);
            zimManageActivity.setResult(zimManageActivity.RESULT_OK, new Intent().setData(uri));
            zimManageActivity.finish();
        } else {
            zimManageActivity.setResult(zimManageActivity.RESULT_CANCELED);
            zimManageActivity.finish();
        }
    }

    @Override
    public void onResume() {
        presenter.loadLocalZimFileFromDb(context);
        super.onResume();
    }

    // Show files from database
    @Override
    public void showFiles(ArrayList<LibraryNetworkEntity.Book> books) {
        if (mZimFileList == null)
            return;

        mZimFileList.setOnItemClickListener(this);
        mZimFileList.setOnItemLongClickListener(this);
        Collections.sort(books, new FileComparator());
        mFiles.clear();
        mFiles.addAll(books);
        mZimFileList.setAdapter(mRescanAdapter);
        mRescanAdapter.notifyDataSetChanged();
        checkEmpty();
        checkPermissions();
    }

    @Override
    public void updateFilesAdapter() {

    }

    public void refreshFragment() {
        if (mZimFileList == null)
            return;
        presenter.loadLocalZimFileFromDb(context);
    }

    // Add book after download
    public void addBook(String path) {
        LibraryNetworkEntity.Book book = FileSearch.fileToBook(path);
        if (book != null) {
            mFiles.add(book);
            mRescanAdapter.notifyDataSetChanged();
            bookDao.saveBooks(mFiles);
        }
    }

    private class FileComparator implements Comparator<LibraryNetworkEntity.Book> {
        @Override
        public int compare(LibraryNetworkEntity.Book b1, LibraryNetworkEntity.Book b2) {
            return b1.getTitle().compareTo(b2.getTitle());
        }
    }

    public void checkPermissions() {
        if (ContextCompat.checkSelfPermission(super.getActivity(),
                Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
                && Build.VERSION.SDK_INT > 18) {
            Toast.makeText(super.getActivity(), getResources().getString(R.string.request_storage),
                    Toast.LENGTH_LONG).show();
            requestPermissions(new String[] { Manifest.permission.READ_EXTERNAL_STORAGE },
                    KiwixMobileActivity.REQUEST_STORAGE_PERMISSION);
        } else {
            getFiles();
        }
    }

    public void getFiles() {
        if (mZimFileList.getFooterViewsCount() != 0)
            return;

        TestingUtils.bindResource(ZimFileSelectFragment.class);
        mZimFileList.addFooterView(progressBar);
        mZimFileList.setAdapter(mRescanAdapter);

        checkEmpty();

        new FileSearch(context, new FileSearch.ResultListener() {
            @Override
            public void onBookFound(LibraryNetworkEntity.Book book) {
                if (!mFiles.contains(book)) {
                    context.runOnUiThread(() -> {
                        Log.i("Scanner", "Found " + book.title);
                        mFiles.add(book);
                        mRescanAdapter.notifyDataSetChanged();
                        checkEmpty();
                    });
                }
            }

            @Override
            public void onScanCompleted() {
                // Remove non-existent books
                ArrayList<LibraryNetworkEntity.Book> books = new ArrayList<>(mFiles);
                for (LibraryNetworkEntity.Book book : books) {
                    if (book.file == null || !book.file.canRead()) {
                        mFiles.remove(book);
                    }
                }

                boolean cached = mFiles.containsAll(bookDao.getBooks()) && bookDao.getBooks().containsAll(mFiles);

                // If content changed then update the list of downloadable books
                if (!cached && context.mSectionsPagerAdapter.libraryFragment.libraryAdapter != null
                        && context.searchView != null) {
                    context.mSectionsPagerAdapter.libraryFragment.libraryAdapter.getFilter()
                            .filter(context.searchView.getQuery());
                }

                // Save the current list of books
                context.runOnUiThread(() -> {
                    mRescanAdapter.notifyDataSetChanged();
                    bookDao.saveBooks(mFiles);
                    mZimFileList.removeFooterView(progressBar);
                    checkEmpty();
                    TestingUtils.unbindResource(ZimFileSelectFragment.class);
                });
            }
        }).scan();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
        case KiwixMobileActivity.REQUEST_STORAGE_PERMISSION: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                getFiles();
            } else if (grantResults.length != 0) {
                super.getActivity().finish();
            }
        }

        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menu_rescan_fs:
            getFiles();
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        Log.d(TAG_KIWIX, " mZimFileList.onItemClick");
        // Stop file search from accessing content provider potentially opening wrong file
        ZimContentProvider.canIterate = false;

        String file;
        LibraryNetworkEntity.Book data = (LibraryNetworkEntity.Book) mZimFileList.getItemAtPosition(position);
        file = data.file.getPath();

        if (!data.file.canRead()) {
            Toast.makeText(context, getString(R.string.error_filenotfound), Toast.LENGTH_LONG).show();
            return;
        }

        finishResult(file);
    }

    @Override
    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
        deleteSpecificZimDialog(position);
        return true;
    }

    public void deleteSpecificZimDialog(int position) {
        new AlertDialog.Builder(super.getActivity(), dialogStyle())
                .setMessage(getString(R.string.delete_specific_zim))
                .setPositiveButton(getResources().getString(R.string.delete), (dialog, which) -> {
                    if (deleteSpecificZimFile(position)) {
                        Toast.makeText(context, getResources().getString(R.string.delete_specific_zim_toast),
                                Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(context, getResources().getString(R.string.delete_zim_failed),
                                Toast.LENGTH_SHORT).show();
                    }
                }).setNegativeButton(android.R.string.no, (dialog, which) -> {
                    // do nothing
                }).show();
    }

    public boolean deleteSpecificZimFile(int position) {
        File file = mFiles.get(position).file;
        FileUtils.deleteZimFile(file.getPath());
        if (file.exists()) {
            return false;
        }
        bookDao.deleteBook(mFiles.get(position).getId());
        mFiles.remove(position);
        mRescanAdapter.notifyDataSetChanged();
        checkEmpty();
        if (context.mSectionsPagerAdapter.libraryFragment.libraryAdapter != null) {
            context.mSectionsPagerAdapter.libraryFragment.libraryAdapter.getFilter()
                    .filter(context.searchView.getQuery());
        }
        return true;
    }

    public void checkEmpty() {
        if (mZimFileList.getCount() == 0) {
            mFileMessage.setVisibility(View.VISIBLE);
        } else
            mFileMessage.setVisibility(View.GONE);
    }

    // The Adapter for the ListView for when the ListView is populated with the rescanned files
    private class RescanDataAdapter extends ArrayAdapter<LibraryNetworkEntity.Book> {

        public RescanDataAdapter(Context context, int textViewResourceId, List<LibraryNetworkEntity.Book> objects) {
            super(context, textViewResourceId, objects);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            ViewHolder holder;
            LibraryNetworkEntity.Book book = getItem(position);
            if (convertView == null) {
                convertView = View.inflate(context, R.layout.library_item, null);
                holder = new ViewHolder();
                holder.title = (TextView) convertView.findViewById(R.id.title);
                holder.description = (TextView) convertView.findViewById(R.id.description);
                holder.language = (TextView) convertView.findViewById(R.id.language);
                holder.creator = (TextView) convertView.findViewById(R.id.creator);
                holder.publisher = (TextView) convertView.findViewById(R.id.publisher);
                holder.date = (TextView) convertView.findViewById(R.id.date);
                holder.size = (TextView) convertView.findViewById(R.id.size);
                holder.fileName = (TextView) convertView.findViewById(R.id.fileName);
                holder.favicon = (ImageView) convertView.findViewById(R.id.favicon);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }

            if (book == null) {
                return convertView;
            }

            holder.title.setText(book.getTitle());
            holder.description.setText(book.getDescription());
            holder.language.setText(bookUtils.getLanguage(book.getLanguage()));
            holder.creator.setText(book.getCreator());
            holder.publisher.setText(book.getPublisher());
            holder.date.setText(book.getDate());
            holder.size.setText(LibraryAdapter.createGbString(book.getSize()));
            holder.fileName.setText(parseURL(getActivity(), book.file.getPath()));
            holder.favicon.setImageBitmap(LibraryAdapter.createBitmapFromEncodedString(book.getFavicon(), context));

            //// Check if no value is empty. Set the view to View.GONE, if it is. To View.VISIBLE, if not.
            if (book.getTitle() == null || book.getTitle().isEmpty()) {
                holder.title.setVisibility(View.GONE);
            } else {
                holder.title.setVisibility(View.VISIBLE);
            }

            if (book.getDescription() == null || book.getDescription().isEmpty()) {
                holder.description.setVisibility(View.GONE);
            } else {
                holder.description.setVisibility(View.VISIBLE);
            }

            if (book.getCreator() == null || book.getCreator().isEmpty()) {
                holder.creator.setVisibility(View.GONE);
            } else {
                holder.creator.setVisibility(View.VISIBLE);
            }

            if (book.getPublisher() == null || book.getPublisher().isEmpty()) {
                holder.publisher.setVisibility(View.GONE);
            } else {
                holder.publisher.setVisibility(View.VISIBLE);
            }

            if (book.getDate() == null || book.getDate().isEmpty()) {
                holder.date.setVisibility(View.GONE);
            } else {
                holder.date.setVisibility(View.VISIBLE);
            }

            if (book.getSize() == null || book.getSize().isEmpty()) {
                holder.size.setVisibility(View.GONE);
            } else {
                holder.size.setVisibility(View.VISIBLE);
            }

            return convertView;

        }

        private class ViewHolder {
            TextView title;

            TextView description;

            TextView language;

            TextView creator;

            TextView publisher;

            TextView date;

            TextView size;

            TextView fileName;

            ImageView favicon;
        }
    }
}