Search in sources :

Example 46 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project Anki-Android by ankidroid.

the class SchedTest method test_cram.

@Test
public void test_cram() throws Exception {
    Collection col = getColV1();
    Note note = col.newNote();
    note.setItem("Front", "one");
    col.addNote(note);
    Card c = note.cards().get(0);
    c.setIvl(100);
    c.setQueue(QUEUE_TYPE_REV);
    c.setType(CARD_TYPE_REV);
    // due in 25 days, so it's been waiting 75 days
    c.setDue(col.getSched().getToday() + 25);
    c.setMod(1);
    c.setFactor(STARTING_FACTOR);
    c.startTimer();
    c.flush();
    col.reset();
    assertEquals(new Counts(0, 0, 0), col.getSched().counts());
    Card cardcopy = c.clone();
    // create a dynamic deck and refresh it
    long did = addDynamicDeck("Cram");
    col.getSched().rebuildDyn(did);
    col.reset();
    // should appear as new in the deck list
    // todo: which sort
    // and should appear in the counts
    assertEquals(new Counts(1, 0, 0), col.getSched().counts());
    // grab it and check estimates
    c = getCard();
    assertEquals(2, col.getSched().answerButtons(c));
    assertEquals(600, col.getSched().nextIvl(c, BUTTON_ONE));
    assertEquals(138 * 60 * 60 * 24, col.getSched().nextIvl(c, BUTTON_TWO));
    Deck cram = col.getDecks().get(did);
    cram.put("delays", new JSONArray(new double[] { 1, 10 }));
    col.getDecks().save(cram);
    assertEquals(3, col.getSched().answerButtons(c));
    assertEquals(60, col.getSched().nextIvl(c, BUTTON_ONE));
    assertEquals(600, col.getSched().nextIvl(c, BUTTON_TWO));
    assertEquals(138 * 60 * 60 * 24, col.getSched().nextIvl(c, BUTTON_THREE));
    col.getSched().answerCard(c, BUTTON_TWO);
    // elapsed time was 75 days
    // factor = 2.5+1.2/2 = 1.85
    // int(75*1.85) = 138
    assertEquals(138, c.getIvl());
    assertEquals(138, c.getODue());
    assertEquals(QUEUE_TYPE_LRN, c.getQueue());
    // should be logged as a cram rep
    assertEquals(3, col.getDb().queryLongScalar("select type from revlog order by id desc limit 1"));
    // check ivls again
    assertEquals(60, col.getSched().nextIvl(c, BUTTON_ONE));
    assertEquals(138 * 60 * 60 * 24, col.getSched().nextIvl(c, BUTTON_TWO));
    assertEquals(138 * 60 * 60 * 24, col.getSched().nextIvl(c, BUTTON_THREE));
    // when it graduates, due is updated
    c = getCard();
    col.getSched().answerCard(c, BUTTON_TWO);
    assertEquals(138, c.getIvl());
    assertEquals(138, c.getDue());
    assertEquals(QUEUE_TYPE_REV, c.getQueue());
    // and it will have moved back to the previous deck
    assertEquals(1, c.getDid());
    // cram the deck again
    col.getSched().rebuildDyn(did);
    col.reset();
    c = getCard();
    // check ivls again - passing should be idempotent
    assertEquals(60, col.getSched().nextIvl(c, BUTTON_ONE));
    assertEquals(600, col.getSched().nextIvl(c, BUTTON_TWO));
    assertEquals(138 * 60 * 60 * 24, col.getSched().nextIvl(c, BUTTON_THREE));
    col.getSched().answerCard(c, BUTTON_TWO);
    assertEquals(138, c.getIvl());
    assertEquals(138, c.getODue());
    // fail
    col.getSched().answerCard(c, BUTTON_ONE);
    assertEquals(60, col.getSched().nextIvl(c, BUTTON_ONE));
    assertEquals(600, col.getSched().nextIvl(c, BUTTON_TWO));
    assertEquals(SECONDS_PER_DAY, col.getSched().nextIvl(c, BUTTON_THREE));
    // delete the deck, returning the card mid-study
    col.getDecks().rem(col.getDecks().selected());
    assertEquals(1, col.getSched().deckDueTree().size());
    c.load();
    assertEquals(1, c.getIvl());
    assertEquals(col.getSched().getToday() + 1, c.getDue());
    // make it due
    col.reset();
    assertEquals(new Counts(0, 0, 0), col.getSched().counts());
    c.setDue(-5);
    c.setIvl(100);
    c.flush();
    col.reset();
    assertEquals(new Counts(0, 0, 1), col.getSched().counts());
    // cram again
    did = addDynamicDeck("Cram");
    col.getSched().rebuildDyn(did);
    col.reset();
    assertEquals(new Counts(0, 0, 1), col.getSched().counts());
    c.load();
    assertEquals(4, col.getSched().answerButtons(c));
    // add a sibling so we can test minSpace, etc
    Card c2 = c.clone();
    c2.setId(0);
    c2.setOrd(1);
    c2.setDue(325);
    c2.flush();
    // should be able to answer it
    c = getCard();
    col.getSched().answerCard(c, BUTTON_FOUR);
    // it should have been moved back to the original deck
    assertEquals(1, c.getDid());
}
Also used : Note(com.ichi2.libanki.Note) JSONArray(com.ichi2.utils.JSONArray) Collection(com.ichi2.libanki.Collection) Deck(com.ichi2.libanki.Deck) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 47 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project Anki-Android by ankidroid.

the class SchedTest method test_counts_idxV1.

@Test
public void test_counts_idxV1() throws Exception {
    Collection col = getColV1();
    Note note = col.newNote();
    note.setItem("Front", "one");
    note.setItem("Back", "two");
    col.addNote(note);
    col.reset();
    assertEquals(new Counts(1, 0, 0), col.getSched().counts());
    Card c = getCard();
    // counter's been decremented but idx indicates 1
    assertEquals(new Counts(0, 0, 0), col.getSched().counts());
    assertEquals(NEW, col.getSched().countIdx(c));
    // answer to move to learn queue
    col.getSched().answerCard(c, BUTTON_ONE);
    assertEquals(new Counts(0, 2, 0), col.getSched().counts());
    // fetching again will decrement the count
    c = getCard();
    assertEquals(new Counts(0, 0, 0), col.getSched().counts());
    assertEquals(LRN, col.getSched().countIdx(c));
    // answering should add it back again
    col.getSched().answerCard(c, BUTTON_ONE);
    assertEquals(new Counts(0, 2, 0), col.getSched().counts());
}
Also used : Note(com.ichi2.libanki.Note) Collection(com.ichi2.libanki.Collection) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 48 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project Anki-Android by ankidroid.

the class UndoTest method test_review.

@Test
public void test_review() throws Exception {
    Collection col = getColV2();
    col.set_config("counts", COUNT_REMAINING);
    Note note = col.newNote();
    note.setItem("Front", "one");
    col.addNote(note);
    col.reset();
    /* TODO:  undo after reset ?
        assertNotNull(col.undoType());

         */
    // answer
    assertEquals(new Counts(1, 0, 0), col.getSched().counts());
    Card c = col.getSched().getCard();
    assertEquals(QUEUE_TYPE_NEW, c.getQueue());
    col.getSched().answerCard(c, Consts.BUTTON_THREE);
    assertEquals(1001, c.getLeft());
    assertEquals(new Counts(0, 1, 0), col.getSched().counts());
    assertEquals(QUEUE_TYPE_LRN, c.getQueue());
    // undo
    assertNotNull(col.undoType());
    col.undo();
    col.reset();
    assertEquals(new Counts(1, 0, 0), col.getSched().counts());
    c.load();
    assertEquals(QUEUE_TYPE_NEW, c.getQueue());
    assertNotEquals(1001, c.getLeft());
    assertNull(col.undoType());
    // we should be able to undo multiple answers too
    note = col.newNote();
    note.setItem("Front", "two");
    col.addNote(note);
    col.reset();
    assertEquals(new Counts(2, 0, 0), col.getSched().counts());
    c = col.getSched().getCard();
    col.getSched().answerCard(c, Consts.BUTTON_THREE);
    c = col.getSched().getCard();
    col.getSched().answerCard(c, Consts.BUTTON_THREE);
    assertEquals(new Counts(0, 2, 0), col.getSched().counts());
    col.undo();
    col.reset();
    assertEquals(new Counts(1, 1, 0), col.getSched().counts());
    col.undo();
    col.reset();
    assertEquals(new Counts(2, 0, 0), col.getSched().counts());
    // performing a normal op will clear the review queue
    c = col.getSched().getCard();
    col.getSched().answerCard(c, Consts.BUTTON_THREE);
    assertThat(col.undoType(), is(instanceOf(Collection.UndoReview.class)));
    col.save("foo");
    // Upstream, "save" can be undone. This test fails here because it's not the case in AnkiDroid
    assumeThat(col.undoName(getTargetContext().getResources()), is("foo"));
    col.undo();
}
Also used : Counts(com.ichi2.libanki.sched.Counts) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 49 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project Anki-Android by ankidroid.

the class CardBrowser method onCollectionLoaded.

// Finish initializing the activity after the collection has been correctly loaded
@Override
protected void onCollectionLoaded(Collection col) {
    super.onCollectionLoaded(col);
    Timber.d("onCollectionLoaded()");
    registerExternalStorageListener();
    SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(getBaseContext());
    // Load reference to action bar title
    mActionBarTitle = findViewById(R.id.toolbar_title);
    mOrder = CARD_ORDER_NONE;
    String colOrder = getCol().get_config_string("sortType");
    for (int c = 0; c < fSortTypes.length; ++c) {
        if (fSortTypes[c].equals(colOrder)) {
            mOrder = c;
            break;
        }
    }
    if (mOrder == 1 && preferences.getBoolean("cardBrowserNoSorting", false)) {
        mOrder = 0;
    }
    // This upgrade should already have been done during
    // setConf. However older version of AnkiDroid didn't call
    // upgradeJSONIfNecessary during setConf, which means the
    // conf saved may still have this bug.
    mOrderAsc = Upgrade.upgradeJSONIfNecessary(getCol(), "sortBackwards", false);
    mCards.reset();
    mCardsListView = findViewById(R.id.card_browser_list);
    // Create a spinner for column1
    Spinner cardsColumn1Spinner = findViewById(R.id.browser_column1_spinner);
    ArrayAdapter<CharSequence> column1Adapter = ArrayAdapter.createFromResource(this, R.array.browser_column1_headings, android.R.layout.simple_spinner_item);
    column1Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    cardsColumn1Spinner.setAdapter(column1Adapter);
    mColumn1Index = AnkiDroidApp.getSharedPrefs(getBaseContext()).getInt("cardBrowserColumn1", 0);
    cardsColumn1Spinner.setOnItemSelectedListener(new OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
            // If a new column was selected then change the key used to map from mCards to the column TextView
            if (pos != mColumn1Index) {
                mColumn1Index = pos;
                AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()).edit().putInt("cardBrowserColumn1", mColumn1Index).apply();
                Column[] fromMap = mCardsAdapter.getFromMapping();
                fromMap[0] = COLUMN1_KEYS[mColumn1Index];
                mCardsAdapter.setFromMapping(fromMap);
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        // Do Nothing
        }
    });
    // Load default value for column2 selection
    mColumn2Index = AnkiDroidApp.getSharedPrefs(getBaseContext()).getInt("cardBrowserColumn2", 0);
    // Setup the column 2 heading as a spinner so that users can easily change the column type
    Spinner cardsColumn2Spinner = findViewById(R.id.browser_column2_spinner);
    ArrayAdapter<CharSequence> column2Adapter = ArrayAdapter.createFromResource(this, R.array.browser_column2_headings, android.R.layout.simple_spinner_item);
    column2Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    cardsColumn2Spinner.setAdapter(column2Adapter);
    // Create a new list adapter with updated column map any time the user changes the column
    cardsColumn2Spinner.setOnItemSelectedListener(new OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
            // If a new column was selected then change the key used to map from mCards to the column TextView
            if (pos != mColumn2Index) {
                mColumn2Index = pos;
                AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()).edit().putInt("cardBrowserColumn2", mColumn2Index).apply();
                Column[] fromMap = mCardsAdapter.getFromMapping();
                fromMap[1] = COLUMN2_KEYS[mColumn2Index];
                mCardsAdapter.setFromMapping(fromMap);
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        // Do Nothing
        }
    });
    // get the font and font size from the preferences
    int sflRelativeFontSize = preferences.getInt("relativeCardBrowserFontSize", DEFAULT_FONT_SIZE_RATIO);
    String sflCustomFont = preferences.getString("browserEditorFont", "");
    Column[] columnsContent = { COLUMN1_KEYS[mColumn1Index], COLUMN2_KEYS[mColumn2Index] };
    // make a new list adapter mapping the data in mCards to column1 and column2 of R.layout.card_item_browser
    mCardsAdapter = new MultiColumnListAdapter(this, R.layout.card_item_browser, columnsContent, new int[] { R.id.card_sfld, R.id.card_column2 }, sflRelativeFontSize, sflCustomFont);
    // link the adapter to the main mCardsListView
    mCardsListView.setAdapter(mCardsAdapter);
    // make the items (e.g. question & answer) render dynamically when scrolling
    mCardsListView.setOnScrollListener(new RenderOnScroll());
    // set the spinner index
    cardsColumn1Spinner.setSelection(mColumn1Index);
    cardsColumn2Spinner.setSelection(mColumn2Index);
    mCardsListView.setOnItemClickListener((parent, view, position, id) -> {
        if (mInMultiSelectMode) {
            // click on whole cell triggers select
            CheckBox cb = view.findViewById(R.id.card_checkbox);
            cb.toggle();
            onCheck(position, view);
        } else {
            // load up the card selected on the list
            long clickedCardId = getCards().get(position).getId();
            saveScrollingState(position);
            openNoteEditorForCard(clickedCardId);
        }
    });
    mCardsListView.setOnItemLongClickListener((adapterView, view, position, id) -> {
        if (mInMultiSelectMode) {
            boolean hasChanged = false;
            for (int i = Math.min(mLastSelectedPosition, position); i <= Math.max(mLastSelectedPosition, position); i++) {
                CardCache card = (CardCache) mCardsListView.getItemAtPosition(i);
                // Add to the set of checked cards
                hasChanged |= mCheckedCards.add(card);
            }
            if (hasChanged) {
                onSelectionChanged();
            }
        } else {
            mLastSelectedPosition = position;
            saveScrollingState(position);
            loadMultiSelectMode();
            // click on whole cell triggers select
            CheckBox cb = view.findViewById(R.id.card_checkbox);
            cb.toggle();
            onCheck(position, view);
            recenterListView(view);
            mCardsAdapter.notifyDataSetChanged();
        }
        return true;
    });
    getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
    long deckId = getCol().getDecks().selected();
    mDeckSpinnerSelection = new DeckSpinnerSelection(this, col, this.findViewById(R.id.toolbar_spinner), true, false);
    mDeckSpinnerSelection.initializeActionBarDeckSpinner(this.getSupportActionBar());
    selectDeckAndSave(deckId);
    // If a valid value for last deck exists then use it, otherwise use libanki selected deck
    if (getLastDeckId() != null && getLastDeckId() == ALL_DECKS_ID) {
        selectAllDecks();
    } else if (getLastDeckId() != null && getCol().getDecks().get(getLastDeckId(), false) != null) {
        mDeckSpinnerSelection.selectDeckById(getLastDeckId(), false);
    } else {
        mDeckSpinnerSelection.selectDeckById(getCol().getDecks().selected(), false);
    }
}
Also used : SharedPreferences(android.content.SharedPreferences) Spinner(android.widget.Spinner) SearchView(androidx.appcompat.widget.SearchView) CardBrowserSearchView(com.ichi2.ui.CardBrowserSearchView) View(android.view.View) AdapterView(android.widget.AdapterView) TextView(android.widget.TextView) ListView(android.widget.ListView) AbsListView(android.widget.AbsListView) Column(com.ichi2.anki.CardBrowser.Column) CheckBox(android.widget.CheckBox) OnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)

Example 50 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project Anki-Android by ankidroid.

the class AbstractFlashcardViewer method initLayout.

// Set the content view to the one provided and initialize accessors.
protected void initLayout() {
    FrameLayout cardContainer = findViewById(R.id.flashcard_frame);
    mTopBarLayout = findViewById(R.id.top_bar);
    mCardFrame = findViewById(R.id.flashcard);
    mCardFrameParent = (ViewGroup) mCardFrame.getParent();
    mTouchLayer = findViewById(R.id.touch_layer);
    mTouchLayer.setOnTouchListener(mGestureListener);
    mCardFrame.removeAllViews();
    // Initialize swipe
    mGestureDetectorImpl = new LinkDetectingGestureDetector();
    mGestureDetector = new GestureDetector(this, mGestureDetectorImpl);
    mEaseButtonsLayout = findViewById(R.id.ease_buttons);
    mEaseButton1 = new EaseButton(EASE_1, findViewById(R.id.flashcard_layout_ease1), findViewById(R.id.ease1), findViewById(R.id.nextTime1));
    mEaseButton1.setListeners(mEaseHandler);
    mEaseButton2 = new EaseButton(EASE_2, findViewById(R.id.flashcard_layout_ease2), findViewById(R.id.ease2), findViewById(R.id.nextTime2));
    mEaseButton2.setListeners(mEaseHandler);
    mEaseButton3 = new EaseButton(EASE_3, findViewById(R.id.flashcard_layout_ease3), findViewById(R.id.ease3), findViewById(R.id.nextTime3));
    mEaseButton3.setListeners(mEaseHandler);
    mEaseButton4 = new EaseButton(EASE_4, findViewById(R.id.flashcard_layout_ease4), findViewById(R.id.ease4), findViewById(R.id.nextTime4));
    mEaseButton4.setListeners(mEaseHandler);
    if (!mShowNextReviewTime) {
        mEaseButton1.hideNextReviewTime();
        mEaseButton2.hideNextReviewTime();
        mEaseButton3.hideNextReviewTime();
        mEaseButton4.hideNextReviewTime();
    }
    Button flipCard = findViewById(R.id.flip_card);
    mFlipCardLayout = findViewById(R.id.flashcard_layout_flip);
    mFlipCardLayout.setOnClickListener(mFlipCardListener);
    if (animationEnabled()) {
        flipCard.setBackgroundResource(Themes.getResFromAttr(this, R.attr.hardButtonRippleRef));
    }
    if (!mButtonHeightSet && mRelativeButtonSize != 100) {
        ViewGroup.LayoutParams params = mFlipCardLayout.getLayoutParams();
        params.height = params.height * mRelativeButtonSize / 100;
        mEaseButton1.setButtonScale(mRelativeButtonSize);
        mEaseButton2.setButtonScale(mRelativeButtonSize);
        mEaseButton3.setButtonScale(mRelativeButtonSize);
        mEaseButton4.setButtonScale(mRelativeButtonSize);
        mButtonHeightSet = true;
    }
    mInitialFlipCardHeight = mFlipCardLayout.getLayoutParams().height;
    if (mLargeAnswerButtons) {
        ViewGroup.LayoutParams params = mFlipCardLayout.getLayoutParams();
        params.height = mInitialFlipCardHeight * 2;
    }
    mAnswerField = findViewById(R.id.answer_field);
    initControls();
    // Position answer buttons
    String answerButtonsPosition = AnkiDroidApp.getSharedPrefs(this).getString(getString(R.string.answer_buttons_position_preference), "bottom");
    LinearLayout answerArea = findViewById(R.id.bottom_area_layout);
    RelativeLayout.LayoutParams answerAreaParams = (RelativeLayout.LayoutParams) answerArea.getLayoutParams();
    RelativeLayout.LayoutParams cardContainerParams = (RelativeLayout.LayoutParams) cardContainer.getLayoutParams();
    switch(answerButtonsPosition) {
        case "top":
            cardContainerParams.addRule(RelativeLayout.BELOW, R.id.bottom_area_layout);
            answerAreaParams.addRule(RelativeLayout.BELOW, R.id.mic_tool_bar_layer);
            answerArea.removeView(mAnswerField);
            answerArea.addView(mAnswerField, 1);
            answerArea.setVisibility(View.VISIBLE);
            break;
        case "bottom":
            cardContainerParams.addRule(RelativeLayout.ABOVE, R.id.bottom_area_layout);
            cardContainerParams.addRule(RelativeLayout.BELOW, R.id.mic_tool_bar_layer);
            answerAreaParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
            answerArea.setVisibility(View.VISIBLE);
            break;
        case "none":
            answerArea.setVisibility(View.GONE);
            break;
        default:
            Timber.w("Unknown answerButtonsPosition: %s", answerButtonsPosition);
            break;
    }
    answerArea.setLayoutParams(answerAreaParams);
    cardContainer.setLayoutParams(cardContainerParams);
}
Also used : EaseButton(com.ichi2.anki.reviewer.EaseButton) Button(android.widget.Button) ViewGroup(android.view.ViewGroup) FrameLayout(android.widget.FrameLayout) RelativeLayout(android.widget.RelativeLayout) GestureDetector(android.view.GestureDetector) EaseButton(com.ichi2.anki.reviewer.EaseButton) LinearLayout(android.widget.LinearLayout)

Aggregations

Test (org.junit.Test)29 Collection (com.ichi2.libanki.Collection)20 Note (com.ichi2.libanki.Note)20 Card (com.ichi2.libanki.Card)17 RobolectricTest (com.ichi2.anki.RobolectricTest)16 View (android.view.View)9 Intent (android.content.Intent)8 JSONArray (com.ichi2.utils.JSONArray)8 JSONObject (com.ichi2.utils.JSONObject)8 Model (com.ichi2.libanki.Model)7 Bundle (android.os.Bundle)6 WebView (android.webkit.WebView)6 SuppressLint (android.annotation.SuppressLint)5 SharedPreferences (android.content.SharedPreferences)5 TextView (android.widget.TextView)5 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)5 Matcher (java.util.regex.Matcher)5 InputMethodManager (android.view.inputmethod.InputMethodManager)4 Context (android.content.Context)3 Uri (android.net.Uri)3