Java tutorial
/**************************************************************************************** * Copyright (c) 2011 Kostas Spyropoulos <inigo.aldana@gmail.com> * * Copyright (c) 2014 Bruno Romero de Azevedo <brunodea@inf.ufsm.br> * * * * 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 (at your option) 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, see <http://www.gnu.org/licenses/>. * ****************************************************************************************/ // TODO: implement own menu? http://www.codeproject.com/Articles/173121/Android-Menus-My-Way package com.ichi2.anki; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.support.v4.view.MenuItemCompat; import android.util.DisplayMetrics; import android.view.Display; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.FrameLayout; import com.ichi2.anim.ActivityTransitionAnimation; import com.ichi2.async.DeckTask; import com.ichi2.compat.CompatHelper; import com.ichi2.libanki.Collection; import com.ichi2.themes.Themes; import com.ichi2.widget.WidgetStatus; import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; import org.json.JSONException; import java.lang.ref.WeakReference; import timber.log.Timber; public class Reviewer extends AbstractFlashcardViewer { private boolean mHasDrawerSwipeConflicts = false; private boolean mShowWhiteboard = true; private boolean mBlackWhiteboard = true; private boolean mPrefFullscreenReview = false; @Override protected void setTitle() { try { String[] title = { "" }; if (colIsOpen()) { title = getCol().getDecks().current().getString("name").split("::"); } else { Timber.e("Could not set title in reviewer because collection closed"); } getSupportActionBar().setTitle(title[title.length - 1]); super.setTitle(title[title.length - 1]); } catch (JSONException e) { throw new RuntimeException(e); } getSupportActionBar().setSubtitle(""); } @Override protected void onCollectionLoaded(Collection col) { super.onCollectionLoaded(col); // Load the first card and start reviewing. Uses the answer card // task to load a card, but since we send null // as the card to answer, no card will be answered. mPrefWhiteboard = MetaDB.getWhiteboardState(this, getParentDid()); if (mPrefWhiteboard) { setWhiteboardEnabledState(true); setWhiteboardVisibility(true); } col.getSched().reset(); // Reset schedule incase card had previous been loaded DeckTask.launchDeckTask(DeckTask.TASK_TYPE_ANSWER_CARD, mAnswerCardHandler, new DeckTask.TaskData(null, 0)); disableDrawerSwipeOnConflicts(); // Add a weak reference to current activity so that scheduler can talk to to Activity mSched.setContext(new WeakReference<Activity>(this)); // Set full screen/immersive mode if needed if (mPrefFullscreenReview) { CompatHelper.getCompat().setFullScreen(this); } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: Timber.i("Reviewer:: Home button pressed"); closeReviewer(RESULT_OK, true); break; case R.id.action_undo: Timber.i("Reviewer:: Undo button pressed"); undo(); break; case R.id.action_mark_card: Timber.i("Reviewer:: Mark button pressed"); onMark(mCurrentCard); refreshActionBar(); break; case R.id.action_replay: Timber.i("Reviewer:: Replay audio button pressed (from menu)"); playSounds(true); break; case R.id.action_edit: Timber.i("Reviewer:: Edit note button pressed"); return editCard(); case R.id.action_bury_card: Timber.i("Reviewer:: Bury card button pressed"); DeckTask.launchDeckTask(DeckTask.TASK_TYPE_DISMISS_NOTE, mDismissCardHandler, new DeckTask.TaskData(mCurrentCard, 4)); break; case R.id.action_bury_note: Timber.i("Reviewer:: Bury note button pressed"); DeckTask.launchDeckTask(DeckTask.TASK_TYPE_DISMISS_NOTE, mDismissCardHandler, new DeckTask.TaskData(mCurrentCard, 0)); break; case R.id.action_suspend_card: Timber.i("Reviewer:: Suspend card button pressed"); DeckTask.launchDeckTask(DeckTask.TASK_TYPE_DISMISS_NOTE, mDismissCardHandler, new DeckTask.TaskData(mCurrentCard, 1)); break; case R.id.action_suspend_note: Timber.i("Reviewer:: Suspend note button pressed"); DeckTask.launchDeckTask(DeckTask.TASK_TYPE_DISMISS_NOTE, mDismissCardHandler, new DeckTask.TaskData(mCurrentCard, 2)); break; case R.id.action_delete: Timber.i("Reviewer:: Delete note button pressed"); showDeleteNoteDialog(); break; case R.id.action_clear_whiteboard: Timber.i("Reviewer:: Clear whiteboard button pressed"); if (mWhiteboard != null) { mWhiteboard.clear(); } break; case R.id.action_hide_whiteboard: // toggle whiteboard visibility Timber.i("Reviewer:: Whiteboard visibility set to %b", !mShowWhiteboard); setWhiteboardVisibility(!mShowWhiteboard); refreshActionBar(); break; case R.id.action_enable_whiteboard: // toggle whiteboard enabled state (and show/hide whiteboard item in action bar) mPrefWhiteboard = !mPrefWhiteboard; Timber.i("Reviewer:: Whiteboard enabled state set to %b", mPrefWhiteboard); setWhiteboardEnabledState(mPrefWhiteboard); setWhiteboardVisibility(mPrefWhiteboard); refreshActionBar(); break; case R.id.action_search_dictionary: Timber.i("Reviewer:: Search dictionary button pressed"); lookUpOrSelectText(); break; case R.id.action_open_deck_options: Intent i = new Intent(this, DeckOptions.class); startActivityForResultWithAnimation(i, DECK_OPTIONS, ActivityTransitionAnimation.FADE); break; default: return super.onOptionsItemSelected(item); } return true; } @SuppressLint("NewApi") @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.reviewer, menu); Resources res = getResources(); if (mCurrentCard != null && mCurrentCard.note().hasTag("marked")) { menu.findItem(R.id.action_mark_card).setTitle(R.string.menu_unmark_note) .setIcon(R.drawable.ic_star_white_24dp); } else { menu.findItem(R.id.action_mark_card).setTitle(R.string.menu_mark_note) .setIcon(R.drawable.ic_star_outline_white_24dp); } if (colIsOpen() && getCol().undoAvailable()) { menu.findItem(R.id.action_undo).setEnabled(true).getIcon().setAlpha(Themes.ALPHA_ICON_ENABLED_LIGHT); } else { menu.findItem(R.id.action_undo).setEnabled(false).getIcon().setAlpha(Themes.ALPHA_ICON_DISABLED_LIGHT); } if (mPrefWhiteboard) { // Don't force showing mark icon when whiteboard enabled // TODO: allow user to customize which icons are force-shown MenuItemCompat.setShowAsAction(menu.findItem(R.id.action_mark_card), MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); // Check if we can forceably squeeze in 3 items into the action bar, if not hide "show whiteboard" if (CompatHelper.getSdkVersion() >= 14 && !ViewConfiguration.get(this).hasPermanentMenuKey()) { // Android 4.x device with overflow menu in the action bar and small screen can't // support forcing 2 extra items into the action bar Display display = getWindowManager().getDefaultDisplay(); DisplayMetrics outMetrics = new DisplayMetrics(); display.getMetrics(outMetrics); float density = getResources().getDisplayMetrics().density; float dpWidth = outMetrics.widthPixels / density; if (dpWidth < 360) { menu.findItem(R.id.action_hide_whiteboard).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } } // Configure the whiteboard related items in the action bar menu.findItem(R.id.action_enable_whiteboard).setTitle(R.string.disable_whiteboard); menu.findItem(R.id.action_hide_whiteboard).setVisible(true); menu.findItem(R.id.action_clear_whiteboard).setVisible(true); Drawable whiteboardIcon = getResources().getDrawable(R.drawable.ic_gesture_white_24dp); if (mShowWhiteboard) { whiteboardIcon.setAlpha(255); menu.findItem(R.id.action_hide_whiteboard).setIcon(whiteboardIcon); menu.findItem(R.id.action_hide_whiteboard).setTitle(R.string.hide_whiteboard); } else { whiteboardIcon.setAlpha(77); menu.findItem(R.id.action_hide_whiteboard).setIcon(whiteboardIcon); menu.findItem(R.id.action_hide_whiteboard).setTitle(R.string.show_whiteboard); } } else { menu.findItem(R.id.action_enable_whiteboard).setTitle(R.string.enable_whiteboard); } if (!CompatHelper.isHoneycomb() && !mDisableClipboard) { menu.findItem(R.id.action_search_dictionary).setVisible(true) .setEnabled(!(mPrefWhiteboard && mShowWhiteboard)) .setTitle(clipboardHasText() ? Lookup.getSearchStringTitle() : res.getString(R.string.menu_select)); } if (getCol().getDecks().isDyn(getParentDid())) { menu.findItem(R.id.action_open_deck_options).setVisible(false); } return super.onCreateOptionsMenu(menu); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { char keyPressed = (char) event.getUnicodeChar(); if (mAnswerField != null && !mAnswerField.isFocused()) { if (sDisplayAnswer) { if (keyPressed == '1') { answerCard(EASE_1); return true; } if (keyPressed == '2') { answerCard(EASE_2); return true; } if (keyPressed == '3') { answerCard(EASE_3); return true; } if (keyPressed == '4') { answerCard(EASE_4); return true; } if (keyCode == KeyEvent.KEYCODE_SPACE || keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER) { answerCard(getDefaultEase()); return true; } } if (keyPressed == 'e') { editCard(); return true; } if (keyPressed == '*') { onMark(mCurrentCard); refreshActionBar(); return true; } if (keyPressed == '-') { DeckTask.launchDeckTask(DeckTask.TASK_TYPE_DISMISS_NOTE, mDismissCardHandler, new DeckTask.TaskData(mCurrentCard, 4)); return true; } if (keyPressed == '=') { DeckTask.launchDeckTask(DeckTask.TASK_TYPE_DISMISS_NOTE, mDismissCardHandler, new DeckTask.TaskData(mCurrentCard, 0)); return true; } if (keyPressed == '@') { DeckTask.launchDeckTask(DeckTask.TASK_TYPE_DISMISS_NOTE, mDismissCardHandler, new DeckTask.TaskData(mCurrentCard, 1)); return true; } if (keyPressed == '!') { DeckTask.launchDeckTask(DeckTask.TASK_TYPE_DISMISS_NOTE, mDismissCardHandler, new DeckTask.TaskData(mCurrentCard, 2)); return true; } if (keyPressed == 'r' || keyCode == KeyEvent.KEYCODE_F5) { playSounds(true); return true; } // different from Anki Desktop if (keyPressed == 'z') { undo(); return true; } } return super.onKeyUp(keyCode, event); } @Override protected SharedPreferences restorePreferences() { super.restorePreferences(); SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(getBaseContext()); mBlackWhiteboard = preferences.getBoolean("blackWhiteboard", true); mPrefFullscreenReview = Integer.parseInt(preferences.getString("fullscreenMode", "0")) > 0; return preferences; } @Override public void fillFlashcard() { super.fillFlashcard(); if (!sDisplayAnswer) { if (mShowWhiteboard && mWhiteboard != null) { mWhiteboard.clear(); } } } @Override public void displayCardQuestion() { // show timer, if activated in the deck's preferences initTimer(); super.displayCardQuestion(); } @Override protected void onStop() { super.onStop(); if (!isFinishing()) { if (colIsOpen() && mSched != null) { WidgetStatus.update(this); } } UIUtils.saveCollectionInBackground(this); } @Override protected void initControls() { super.initControls(); if (mPrefWhiteboard) { setWhiteboardVisibility(mShowWhiteboard); } } private void setWhiteboardEnabledState(boolean state) { mPrefWhiteboard = state; MetaDB.storeWhiteboardState(this, getParentDid(), state); if (state && mWhiteboard == null) { createWhiteboard(); } } // Create the whiteboard private void createWhiteboard() { mWhiteboard = new Whiteboard(this, mNightMode, mBlackWhiteboard); FrameLayout.LayoutParams lp2 = new FrameLayout.LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.FILL_PARENT); mWhiteboard.setLayoutParams(lp2); FrameLayout fl = (FrameLayout) findViewById(R.id.whiteboard); fl.addView(mWhiteboard); mWhiteboard.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (mShowWhiteboard) { return false; } return getGestureDetector().onTouchEvent(event); } }); mWhiteboard.setEnabled(true); } // Show or hide the whiteboard private void setWhiteboardVisibility(boolean state) { mShowWhiteboard = state; if (state) { mWhiteboard.setVisibility(View.VISIBLE); disableDrawerSwipe(); } else { mWhiteboard.setVisibility(View.GONE); if (!mHasDrawerSwipeConflicts) { enableDrawerSwipe(); } } } private void disableDrawerSwipeOnConflicts() { SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(getBaseContext()); boolean gesturesEnabled = AnkiDroidApp.initiateGestures(preferences); if (gesturesEnabled) { int gestureSwipeUp = Integer.parseInt(preferences.getString("gestureSwipeUp", "9")); int gestureSwipeDown = Integer.parseInt(preferences.getString("gestureSwipeDown", "0")); int gestureSwipeRight = Integer.parseInt(preferences.getString("gestureSwipeRight", "17")); if (gestureSwipeUp != GESTURE_NOTHING || gestureSwipeDown != GESTURE_NOTHING || gestureSwipeRight != GESTURE_NOTHING) { mHasDrawerSwipeConflicts = true; super.disableDrawerSwipe(); } } } @Override public boolean onItemClick(View view, int i, IDrawerItem iDrawerItem) { // Tell the browser the current card ID so that it can tell us when we need to reload if (mCurrentCard != null) { setCurrentCardId(mCurrentCard.getId()); } return super.onItemClick(view, i, iDrawerItem); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); // Restore full screen once we regain focus if (hasFocus) { delayedHide(INITIAL_HIDE_DELAY); } else { mFullScreenHandler.removeMessages(0); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_STATISTICS || requestCode == REQUEST_BROWSE_CARDS) { // select original deck if the statistics or card browser were opened, // which can change the selected deck if (data != null && data.hasExtra("originalDeck")) { getCol().getDecks().select(data.getLongExtra("originalDeck", 0L)); } } super.onActivityResult(requestCode, resultCode, data); } }