it.angrydroids.epub3reader.EpubReaderMain.java Source code

Java tutorial

Introduction

Here is the source code for it.angrydroids.epub3reader.EpubReaderMain.java

Source

/*
The MIT License (MIT)
    
Copyright (c) 2013, V. Giacometti, M. Giuriato, B. Petrantuono
    
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
    
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
    
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
 */

package it.angrydroids.epub3reader;

import android.app.Activity;
import android.app.DialogFragment;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.MotionEventCompat;
import android.util.DisplayMetrics;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;

public class EpubReaderMain extends Activity {

    EpubNavigator navigator;

    protected static WebView view1;
    protected static WebView view2;
    protected static RelativeLayout layoutView1;
    protected static RelativeLayout layoutView2;
    protected static LinearLayout layout;

    protected static Button iconCloseView1;
    protected static Button iconCloseView2;
    protected int screenWidth;
    protected int screenHeight;

    protected ViewStateEnum stateView1;
    protected ViewStateEnum stateView2;
    protected BookEnum bookSelector;
    protected float swipeOriginX, swipeOriginY;
    protected static float firstViewSize = (float) 0.5;
    protected boolean syncScrollActivated = true;
    protected static String color = "#000000"; // work in progress

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_epub_reader_main);

        // ----- get activity elements
        view1 = (WebView) findViewById(R.id.firstViewport);
        view2 = (WebView) findViewById(R.id.secondViewport);
        layout = (LinearLayout) findViewById(R.id.mainLayout);

        iconCloseView1 = (Button) findViewById(R.id.topRightFirstView);
        iconCloseView2 = (Button) findViewById(R.id.topRightSecondView);

        layoutView1 = (RelativeLayout) findViewById(R.id.firstViewportLayout);
        layoutView2 = (RelativeLayout) findViewById(R.id.secondViewportLayout);
        // -----

        // ----- get activity screen size
        DisplayMetrics metrics = this.getResources().getDisplayMetrics();
        screenWidth = metrics.widthPixels;
        screenHeight = metrics.heightPixels;
        // -----

        navigator = new EpubNavigator(getBaseContext());

        // enable JavaScript for cool things to happen!
        view1.getSettings().setJavaScriptEnabled(true);
        view2.getSettings().setJavaScriptEnabled(true);

        // when the app starts, only one view is shown
        updateView1(ViewStateEnum.books);
        updateView2(ViewStateEnum.invisible);

        // ----- SWIPE PAGE
        view1.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {

                if (stateView1 == ViewStateEnum.books) {
                    swipePage(v, event, BookEnum.first);
                }

                if (syncScrollActivated == true && stateView2 != ViewStateEnum.invisible) {
                    // syncScroll(v, view2, event); work in progress
                }

                WebView view = (WebView) v;
                return view.onTouchEvent(event);
            }
        });

        view2.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (stateView2 == ViewStateEnum.books) {
                    swipePage(v, event, BookEnum.second);
                }
                WebView view = (WebView) v;
                return view.onTouchEvent(event);
            }
        });
        // -----

        // ----- VIEW CLOSING
        iconCloseView1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ViewStateEnum newState = navigator.closeView1();
                ViewStateEnum oldState = stateView1;
                updateView1(newState);
                if (oldState == ViewStateEnum.books) {
                    updateView2(ViewStateEnum.invisible);
                }
            }
        });

        iconCloseView2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                updateView2(navigator.closeView2());
            }
        });
        // -----

        // ----- NOTE & LINK
        view1.setOnLongClickListener(new OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if (stateView1 == ViewStateEnum.books || stateView1 == ViewStateEnum.notes) {
                    Message msg = new Message();
                    msg.setTarget(new Handler() {
                        @Override
                        public void handleMessage(Message msg) {
                            super.handleMessage(msg);
                            String url = msg.getData().getString(getString(R.string.url));
                            if (url != null)
                                if (stateView1 == ViewStateEnum.books || stateView1 == ViewStateEnum.notes) {
                                    updateView2(ViewStateEnum.notes);
                                    navigator.setView2(url);
                                } else {
                                    navigator.setView1(url);
                                }
                        }
                    });
                    view1.requestFocusNodeHref(msg);
                }
                return false;
            }
        });

        view1.setWebViewClient(new WebViewClient() {
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                try {
                    updateView1(navigator.setView1(url));
                } catch (Exception e) {
                    errorMessage(getString(R.string.error_LoadPage));
                }
                return true;
            }
        });

        view2.setOnLongClickListener(new OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                Message msg = new Message();
                msg.setTarget(new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                        String url = msg.getData().getString(getString(R.string.url));
                        if (url != null) {
                            try {
                                if (stateView2 == ViewStateEnum.books || stateView2 == ViewStateEnum.notes) {
                                    updateView1(ViewStateEnum.notes);
                                    navigator.setView1(url);
                                } else {
                                    navigator.setView2(url);
                                }
                            } catch (Exception e) {
                                errorMessage(getString(R.string.error_LoadPage));
                            }
                        }

                    }
                });
                view2.requestFocusNodeHref(msg);
                return false;
            }
        });

        view2.setWebViewClient(new WebViewClient() {
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                try {
                    updateView2(navigator.setView2(url));
                } catch (Exception e) {
                    errorMessage(getString(R.string.error_LoadPage));
                }
                return true;
            }
        });
        // -----

        // ----- LOAD STATE
        SharedPreferences preferences = getPreferences(MODE_PRIVATE);
        if (preferences.getBoolean(getString(R.string.bookOpen), false)) {
            loadState(preferences);
        } else {
            bookSelector = BookEnum.first;
            Intent goToChooser = new Intent(this, FileChooser.class);
            startActivityForResult(goToChooser, 0);
        }
        // -----
    }

    // load the selected book
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (resultCode == Activity.RESULT_OK) {
            String path = data.getStringExtra(getString(R.string.bpath));

            if (bookSelector == BookEnum.first) {
                if (navigator.openBook1(path)) {
                    updateView1(ViewStateEnum.books);
                } else {
                    errorMessage(getString(R.string.error_LoadBook));
                }
            } else if (navigator.openBook2(path)) {
                updateView2(ViewStateEnum.books);
            } else {
                errorMessage(getString(R.string.error_LoadBook));
            }
        } else if (!navigator.isAtLeastOneBookOpen()) {
            finish();
        }
    }

    // UI Controller
    protected void updateView1(ViewStateEnum state) {
        stateView1 = state;
        if (stateView1 == ViewStateEnum.invisible) {
            stateView1 = ViewStateEnum.books;
            finish();
        }
    }

    protected void updateView2(ViewStateEnum state) {
        stateView2 = state;
        switch (stateView2) {
        case books:
        case notes:
            showSecondView();
            break;
        case invisible:
            hideSecondView();
            break;
        }
    }

    protected void hideSecondView() {
        layoutView2.setVisibility(RelativeLayout.GONE);
    }

    protected void showSecondView() {
        layoutView2.setVisibility(RelativeLayout.VISIBLE);
        iconCloseView2.setVisibility(RelativeLayout.VISIBLE);
    }

    // Menu
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.epub_reader_main, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {

        if (navigator.isParallelTextOn() == false && navigator.isExactlyOneBookOpen() == false) {

            menu.findItem(R.id.meta1).setVisible(true);

            menu.findItem(R.id.meta2).setVisible(true);

            menu.findItem(R.id.toc1).setVisible(true);

            menu.findItem(R.id.toc2).setVisible(true);

            menu.findItem(R.id.FirstFront).setVisible(true);

            menu.findItem(R.id.SecondFront).setVisible(true);
        }

        if (navigator.isExactlyOneBookOpen() == false) {

            menu.findItem(R.id.Synchronize).setVisible(true);

            menu.findItem(R.id.Align).setVisible(true);
        }

        if (navigator.isExactlyOneBookOpen() == true || navigator.isParallelTextOn() == true) {

            menu.findItem(R.id.meta1).setVisible(false);

            menu.findItem(R.id.meta2).setVisible(false);

            menu.findItem(R.id.toc1).setVisible(false);

            menu.findItem(R.id.toc2).setVisible(false);

            menu.findItem(R.id.FirstFront).setVisible(false);

            menu.findItem(R.id.SecondFront).setVisible(false);

        }
        if (navigator.isExactlyOneBookOpen() == true) {
            menu.findItem(R.id.Synchronize).setVisible(false);

            menu.findItem(R.id.Align).setVisible(false);

        }

        // if there is only one view, option "changeSizes" is not visualized
        if (stateView2.name().equalsIgnoreCase(getString(R.string.invisible)))
            menu.findItem(R.id.changeSize).setVisible(false);
        else
            menu.findItem(R.id.changeSize).setVisible(true);

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
        case R.id.FirstEPUB:
            bookSelector = BookEnum.first;
            Intent goToChooser1 = new Intent(this, FileChooser.class);
            goToChooser1.putExtra(getString(R.string.second), getString(R.string.time));
            startActivityForResult(goToChooser1, 0);
            return true;

        case R.id.SecondEPUB:
            bookSelector = BookEnum.second;
            Intent goToChooser2 = new Intent(this, FileChooser.class);
            goToChooser2.putExtra(getString(R.string.second), getString(R.string.time));
            startActivityForResult(goToChooser2, 0);
            // invalidateOptionsMenu();
            return true;

        case R.id.Front:
            if (navigator.isExactlyOneBookOpen() == true || navigator.isParallelTextOn() == true)
                chooseLanguage(BookEnum.first);
            return true;

        case R.id.FirstFront:
            chooseLanguage(BookEnum.first);
            return true;

        case R.id.SecondFront:
            if (navigator.isExactlyOneBookOpen() == false)
                chooseLanguage(BookEnum.second);
            else
                errorMessage(getString(R.string.error_onlyOneBookOpen));
            return true;

        case R.id.PconS:
            try {
                boolean yes = navigator.synchronizeView1WithView2();
                if (!yes) {
                    errorMessage(getString(R.string.error_onlyOneBookOpen));
                }
            } catch (Exception e) {
                errorMessage(getString(R.string.error_cannotSynchronize));
            }
            return true;

        case R.id.SconP:
            try {
                boolean ok = navigator.synchronizeView2WithView1();
                if (!ok) {
                    errorMessage(getString(R.string.error_onlyOneBookOpen));
                }
            } catch (Exception e) {
                errorMessage(getString(R.string.error_cannotSynchronize));
            }
            return true;

        case R.id.Synchronize:

            boolean sync = navigator.flipSynchronizedReadingActive();
            if (!sync) {
                errorMessage(getString(R.string.error_onlyOneBookOpen));
            }
            return true;

        case R.id.Metadata:
            if (navigator.isExactlyOneBookOpen() == true || navigator.isParallelTextOn() == true) {
                navigator.displayMetadata(BookEnum.first);
                updateView1(ViewStateEnum.notes);
            } else {
            }
            return true;

        case R.id.meta1:
            if (navigator.displayMetadata(BookEnum.first))
                updateView1(ViewStateEnum.notes);
            else
                errorMessage(getString(R.string.error_metadataNotFound));
            return true;

        case R.id.meta2:
            if (navigator.displayMetadata(BookEnum.second))
                updateView2(ViewStateEnum.notes);
            else
                errorMessage(getString(R.string.error_metadataNotFound));
            return true;

        case R.id.tableOfContents:
            if (navigator.isExactlyOneBookOpen() == true || navigator.isParallelTextOn() == true) {
                navigator.displayTOC(BookEnum.first);
                updateView1(ViewStateEnum.notes);
            } else {
            }
            return true;

        case R.id.toc1:
            if (navigator.displayTOC(BookEnum.first))
                updateView1(ViewStateEnum.notes);
            else
                errorMessage(getString(R.string.error_tocNotFound));
            return true;
        case R.id.toc2:
            if (navigator.displayTOC(BookEnum.second))
                updateView1(ViewStateEnum.notes);
            else
                errorMessage(getString(R.string.error_tocNotFound));
            return true;
        case R.id.changeSize:
            try {
                DialogFragment newFragment = new SetPanelSize();
                newFragment.show(getFragmentManager(), "");
            } catch (Exception e) {
                errorMessage(getString(R.string.error_cannotChangeSizes));
            }
            return true;
        case R.id.Style: // work in progress...
            try {
                DialogFragment newFragment = new ChangeCSSMenu();
                newFragment.show(getFragmentManager(), "");
            } catch (Exception e) {
                errorMessage(getString(R.string.error_CannotChangeStyle));
            }
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    // Change page
    protected void swipePage(View v, MotionEvent event, BookEnum which) {
        int action = MotionEventCompat.getActionMasked(event);

        switch (action) {
        case (MotionEvent.ACTION_DOWN):
            swipeOriginX = event.getX();
            swipeOriginY = event.getY();
            break;

        case (MotionEvent.ACTION_UP):
            int quarterWidth = (int) (screenWidth * 0.25);
            float diffX = swipeOriginX - event.getX();
            float diffY = swipeOriginY - event.getY();
            float absDiffX = Math.abs(diffX);
            float absDiffY = Math.abs(diffY);

            if ((diffX > quarterWidth) && (absDiffX > absDiffY)) {
                try {
                    navigator.goToNextChapter(which);
                } catch (Exception e) {
                    errorMessage(getString(R.string.error_cannotTurnPage));
                }
            } else if ((diffX < -quarterWidth) && (absDiffX > absDiffY)) {
                try {
                    navigator.goToPrevChapter(which);
                } catch (Exception e) {
                    errorMessage(getString(R.string.error_cannotTurnPage));
                }
            }
            break;
        }

    }

    // TODO work in progress, navigator?
    /*
     * protected void syncScroll(View v1, View v2, MotionEvent event) { int
     * action = MotionEventCompat.getActionMasked(event);
     * 
     * switch (action) { case (MotionEvent.ACTION_DOWN): swipeOriginY =
     * event.getY(); swipeOriginX = event.getX(); break;
     * 
     * case (MotionEvent.ACTION_UP): float endY = event.getY(); float endX =
     * event.getX(); float diffY = swipeOriginY - endY; float diffX =
     * swipeOriginX - endX; if (Math.abs(diffY) < Math.abs(diffX) ||
     * Math.abs(diffY) > 300) // solo // per // piccoli // scroll { }
     * 
     * else { v2.scrollBy(0, (int) diffY); }
     * 
     * break; } }
     */

    // Language Selection
    public void chooseLanguage(BookEnum which) {

        String[] languages;
        if (which == BookEnum.first) {
            languages = navigator.getLanguagesBook1();
        } else {
            languages = navigator.getLanguagesBook2();
        }
        if (languages.length > 0) {
            Bundle bundle = new Bundle();
            bundle.putString(getString(R.string.tome), which.toString());
            bundle.putStringArray(getString(R.string.lang), languages);

            LanguageChooser langChooser = new LanguageChooser();
            langChooser.setArguments(bundle);
            langChooser.show(getFragmentManager(), "");
        } else {
            errorMessage(getString(R.string.error_noOtherLanguages));
        }
    }

    public void refreshLanguages(BookEnum which, int first, int second, int numberOfLanguages) {
        if (which == BookEnum.second) {
            int tmp = first;
            first = second;
            second = tmp;
        }
        navigator.parallelText(which, first, second);
        if ((which == BookEnum.first) || (numberOfLanguages > 1)) {
            updateView1(ViewStateEnum.books);
        }
        if ((which == BookEnum.second) || (numberOfLanguages > 1)) {
            updateView2(ViewStateEnum.books);
        }
    }

    // change the views size, changing the weight
    protected void changeViewsSize(float weight1) {

        firstViewSize = weight1;

        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
            weight1 = weight1 + (float) 0.01;

            LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT,
                    weight1);
            layoutView1.setLayoutParams(params1);

            LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT,
                    (1 - weight1));
            layoutView2.setLayoutParams(params2);
        } else {
            LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 0,
                    weight1);
            layoutView1.setLayoutParams(params1);

            LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 0,
                    (1 - weight1));
            layoutView2.setLayoutParams(params2);
        }
    }

    // Save/Load State
    protected void saveState(Editor editor) {
        editor.putString(getString(R.string.firstState), stateView1.name());
        editor.putString(getString(R.string.secondState), stateView2.name());

        editor.putFloat(getString(R.string.firstViewSize), getFirstViewWeight());

        navigator.saveState(editor);
    }

    protected void loadState(SharedPreferences preferences) {
        updateView1(ViewStateEnum
                .valueOf(preferences.getString(getString(R.string.firstState), ViewStateEnum.books.name())));
        updateView2(ViewStateEnum
                .valueOf(preferences.getString(getString(R.string.secondState), ViewStateEnum.invisible.name())));

        float viewSize = preferences.getFloat(getString(R.string.firstViewSize), getFirstViewWeight());
        changeViewsSize(viewSize);

        if (!navigator.loadState(preferences))
            errorMessage(getString(R.string.error_cannotLoadState));
    }

    @Override
    protected void onPause() {
        super.onPause();
        SharedPreferences preferences = getPreferences(MODE_PRIVATE);
        Editor editor = preferences.edit();
        saveState(editor);
        editor.commit();
    }

    public static WebView getView1() {
        return view1;
    }

    public static WebView getView2() {
        return view2;
    }

    public static String getColor() { // work in progress
        return color;
    }

    public static void setColor(String my_color) { // work in progress
        color = my_color;
    }

    public static float getFirstViewWeight() {
        return firstViewSize;
    }

    public void errorMessage(String message) {
        Context context = getApplicationContext();
        Toast toast = Toast.makeText(context, message, Toast.LENGTH_SHORT);
        toast.show();
    }

}