Search in sources :

Example 41 with Template

use of com.ichi2.libanki.template.Template in project Anki-Android by ankidroid.

the class ModelTest method regression_test_pipe.

@Test
@Config(qualifiers = "en")
public void regression_test_pipe() {
    Collection col = getCol();
    ModelManager mm = col.getModels();
    Model basic = mm.byName("Basic");
    JSONObject template = basic.getJSONArray("tmpls").getJSONObject(0);
    template.put("qfmt", "{{|Front}}{{Front}}{{/Front}}{{Front}}");
    try {
        // in V16, the "save" throws, in V11, the "add" throws
        mm.save(basic, true);
        Note note = addNoteUsingBasicModel("foo", "bar");
        fail();
    } catch (Exception er) {
    }
}
Also used : JSONObject(com.ichi2.utils.JSONObject) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test) Config(org.robolectric.annotation.Config)

Example 42 with Template

use of com.ichi2.libanki.template.Template in project Anki-Android by ankidroid.

the class ModelTest method test_chained_mods.

@Test
public void test_chained_mods() throws ConfirmModSchemaException {
    Collection col = getCol();
    col.getModels().setCurrent(col.getModels().byName("Cloze"));
    Model m = col.getModels().current();
    ModelManager mm = col.getModels();
    // We replace the default Cloze template
    JSONObject t = Models.newTemplate("ChainedCloze");
    t.put("qfmt", "{{cloze:text:Text}}");
    t.put("afmt", "{{cloze:text:Text}}");
    mm.addTemplateModChanged(m, t);
    mm.save(m);
    col.getModels().remTemplate(m, m.getJSONArray("tmpls").getJSONObject(0));
    Note note = col.newNote();
    String q1 = "<span style=\"color:red\">phrase</span>";
    String a1 = "<b>sentence</b>";
    String q2 = "<span style=\"color:red\">en chaine</span>";
    String a2 = "<i>chained</i>";
    note.setItem("Text", "This {{c1::" + q1 + "::" + a1 + "}} demonstrates {{c1::" + q2 + "::" + a2 + "}} clozes.");
    assertEquals(1, col.addNote(note));
    String question = note.cards().get(0).q();
/* TODO: chained modifier
        assertThat("Question «"+question+"» does not contain the expected string", question, containsString("This <span class=cloze>[sentence]</span> demonstrates <span class=cloze>[chained]</span> clozes.")
                   );
        assertThat(note.cards().get(0).a(), containsString("This <span class=cloze>phrase</span> demonstrates <span class=cloze>en chaine</span> clozes."
                                                    ));

         */
}
Also used : JSONObject(com.ichi2.utils.JSONObject) Matchers.containsString(org.hamcrest.Matchers.containsString) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 43 with Template

use of com.ichi2.libanki.template.Template in project Anki-Android by Ramblurr.

the class Collection method _renderQA.

public HashMap<String, String> _renderQA(Object[] data, List<String> args) {
    // data is [cid, nid, mid, did, ord, tags, flds]
    // unpack fields and create dict
    String[] flist = Utils.splitFields((String) data[6]);
    Map<String, String> fields = new HashMap<String, String>();
    long modelId = (Long) data[2];
    JSONObject model = mModels.get(modelId);
    Map<String, Pair<Integer, JSONObject>> fmap = mModels.fieldMap(model);
    for (String fname : fmap.keySet()) {
        fields.put(fname, flist[fmap.get(fname).first]);
    }
    fields.put("Tags", ((String) data[5]).trim());
    try {
        fields.put("Type", (String) model.get("name"));
        fields.put("Deck", mDecks.name((Long) data[3]));
        JSONObject template;
        if (model.getInt("type") == Sched.MODEL_STD) {
            template = model.getJSONArray("tmpls").getJSONObject((Integer) data[4]);
        } else {
            template = model.getJSONArray("tmpls").getJSONObject(0);
        }
        fields.put("Card", template.getString("name"));
        fields.put("c" + (((Integer) data[4]) + 1), "1");
        // render q & a
        HashMap<String, String> d = new HashMap<String, String>();
        try {
            d.put("id", Long.toString((Long) data[0]));
            String qfmt = template.getString("qfmt");
            String afmt = template.getString("afmt");
            String html;
            String format;
            // runFilter mungeFields for type "q"
            Models.fieldParser fparser = new Models.fieldParser(fields);
            Matcher m = fClozePattern.matcher(qfmt);
            format = m.replaceFirst(String.format(Locale.US, "{{cq:%d:", ((Integer) data[4]) + 1));
            m = fAltClozePattern.matcher(format);
            format = m.replaceFirst(String.format(Locale.US, "<%%cq:%d:", ((Integer) data[4]) + 1));
            html = mModels.getCmpldTemplate(format).execute(fparser);
            html = (String) AnkiDroidApp.getHooks().runFilter("mungeQA", html, "q", fields, model, data, this);
            d.put("q", html);
            // empty cloze?
            if (model.getInt("type") == Sched.MODEL_CLOZE) {
                if (getModels()._availClozeOrds(model, (String) data[6], false).size() == 0) {
                    d.put("q", "Please edit this note and add some cloze deletions.");
                }
            }
            fields.put("FrontSide", mMedia.stripAudio(d.get("q")));
            // runFilter mungeFields for type "a"
            fparser = new Models.fieldParser(fields);
            m = fClozePattern.matcher(afmt);
            format = m.replaceFirst(String.format(Locale.US, "{{ca:%d:", ((Integer) data[4]) + 1));
            m = fAltClozePattern.matcher(format);
            format = m.replaceFirst(String.format(Locale.US, "<%%ca:%d:", ((Integer) data[4]) + 1));
            html = mModels.getCmpldTemplate(format).execute(fparser);
            html = (String) AnkiDroidApp.getHooks().runFilter("mungeQA", html, "a", fields, model, data, this);
            d.put("a", html);
            // empty cloze?
            if (model.getInt("type") == Sched.MODEL_CLOZE) {
                if (getModels()._availClozeOrds(model, (String) data[6], false).size() == 0) {
                    d.put("q", AnkiDroidApp.getAppResources().getString(com.ichi2.anki.R.string.empty_cloze_warning, "<a href=" + HELP_SITE + "#cloze>" + AnkiDroidApp.getAppResources().getString(com.ichi2.anki.R.string.help_cloze) + "</a>"));
                }
            }
        } catch (MustacheException e) {
            Resources res = AnkiDroidApp.getAppResources();
            String templateError = String.format(TEMPLATE_ERROR, res.getString(R.string.template_error), res.getString(R.string.template_error_detail), e.getMessage(), res.getString(R.string.note_type), model.getString("name"), res.getString(R.string.card_type), template.getString("name"), res.getString(R.string.template_error_fix));
            d.put("q", templateError);
            d.put("a", templateError);
        }
        return d;
    } catch (JSONException e) {
        throw new RuntimeException(e);
    }
}
Also used : HashMap(java.util.HashMap) Matcher(java.util.regex.Matcher) MustacheException(com.samskivert.mustache.MustacheException) JSONException(org.json.JSONException) JSONObject(org.json.JSONObject) Resources(android.content.res.Resources) Pair(com.ichi2.anki.Pair)

Example 44 with Template

use of com.ichi2.libanki.template.Template in project Anki-Android by Ramblurr.

the class Reviewer method onCreate.

// ----------------------------------------------------------------------------
// ANDROID METHODS
// ----------------------------------------------------------------------------
@Override
protected void onCreate(Bundle savedInstanceState) {
    Themes.applyTheme(this);
    super.onCreate(savedInstanceState);
    // Remove the status bar and title bar
    if (mPrefFullscreenReview) {
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        // Do not hide the title bar in Honeycomb, since it contains the action bar.
        if (AnkiDroidApp.SDK_VERSION <= 11) {
            requestWindowFeature(Window.FEATURE_NO_TITLE);
        }
    }
    mChangeBorderStyle = Themes.getTheme() == Themes.THEME_ANDROID_LIGHT || Themes.getTheme() == Themes.THEME_ANDROID_DARK;
    // The hardware buttons should control the music volume while reviewing.
    setVolumeControlStream(AudioManager.STREAM_MUSIC);
    Collection col = AnkiDroidApp.getCol();
    if (col == null) {
        reloadCollection(savedInstanceState);
        return;
    } else {
        mSched = col.getSched();
        mCollectionFilename = col.getPath();
        mBaseUrl = Utils.getBaseUrl(col.getMedia().getDir());
        restorePreferences();
        setFullScreen(mPrefFullscreenReview);
        registerExternalStorageListener();
        if (mNightMode) {
            mCurrentBackgroundColor = Themes.getNightModeCardBackground(this);
        } else {
            mCurrentBackgroundColor = Color.WHITE;
        }
        mUseQuickUpdate = shouldUseQuickUpdate();
        initLayout(R.layout.flashcard);
        try {
            String[] title = mSched.getCol().getDecks().current().getString("name").split("::");
            AnkiDroidApp.getCompat().setTitle(this, title[title.length - 1], mInvertedColors);
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        AnkiDroidApp.getCompat().setSubtitle(this, "", mInvertedColors);
        if (mPrefTextSelection) {
            clipboardSetText("");
        }
        // Load the template for the card
        try {
            mCardTemplate = Utils.convertStreamToString(getAssets().open("card_template.html"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        // Initialize text-to-speech. This is an asynchronous operation.
        if (mSpeakText) {
            ReadText.initializeTts(this);
        }
        // Get last whiteboard state
        if (mPrefWhiteboard && mCurrentCard != null && MetaDB.getWhiteboardState(this, mCurrentCard.getDid()) == 1) {
            mShowWhiteboard = true;
            mWhiteboard.setVisibility(View.VISIBLE);
        }
        // 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.
        DeckTask.launchDeckTask(DeckTask.TASK_TYPE_ANSWER_CARD, mAnswerCardHandler, new DeckTask.TaskData(mSched, null, 0));
        // Since we aren't actually answering a card, decrement the rep count
        mSched.setReps(mSched.getReps() - 1);
    }
}
Also used : Collection(com.ichi2.libanki.Collection) JSONException(org.json.JSONException) SpannedString(android.text.SpannedString) SpannableString(android.text.SpannableString) IOException(java.io.IOException) DeckTask(com.ichi2.async.DeckTask)

Example 45 with Template

use of com.ichi2.libanki.template.Template in project AnkiChinaAndroid by ankichinateam.

the class NoteEditor method onCollectionLoaded.

// Finish initializing the activity after the collection has been correctly loaded
@Override
protected void onCollectionLoaded(Collection col) {
    super.onCollectionLoaded(col);
    Intent intent = getIntent();
    Timber.d("NoteEditor() onCollectionLoaded: caller: %d", mCaller);
    registerExternalStorageListener();
    View mainView = findViewById(android.R.id.content);
    mToolbar = findViewById(R.id.editor_toolbar);
    mToolbar.setFormatListener(formatter -> {
        View currentFocus = getCurrentFocus();
        if (!(currentFocus instanceof FieldEditText)) {
            return;
        }
        modifyCurrentSelection(formatter, (FieldEditText) currentFocus);
    });
    enableToolbar(mainView);
    mFieldsLayoutContainer = findViewById(R.id.CardEditorEditFieldsLayout);
    mTagsButton = findViewById(R.id.CardEditorTagText);
    mCardsButton = findViewById(R.id.CardEditorCardsText);
    mCardsButton.setOnClickListener(v -> {
        Timber.i("NoteEditor:: Cards button pressed. Opening template editor");
        showCardTemplateEditor();
    });
    mAedictIntent = false;
    mCurrentEditedCard = null;
    switch(mCaller) {
        case CALLER_NOCALLER:
            Timber.e("no caller could be identified, closing");
            finishWithoutAnimation();
            return;
        case CALLER_REVIEWER:
            mCurrentEditedCard = AbstractFlashcardViewer.getEditorCard();
            if (mCurrentEditedCard == null) {
                finishWithoutAnimation();
                return;
            }
            mEditorNote = mCurrentEditedCard.note();
            mAddNote = false;
            break;
        case CALLER_STUDYOPTIONS:
        case CALLER_DECKPICKER:
        case CALLER_REVIEWER_ADD:
        case CALLER_CARDBROWSER_ADD:
        case CALLER_CARDEDITOR:
            mAddNote = true;
            break;
        case CALLER_CARDBROWSER_EDIT:
            mCurrentEditedCard = CardBrowser.sCardBrowserCard;
            if (mCurrentEditedCard == null) {
                finishWithoutAnimation();
                return;
            }
            mEditorNote = mCurrentEditedCard.note();
            mAddNote = false;
            break;
        case CALLER_CARDEDITOR_INTENT_ADD:
            {
                fetchIntentInformation(intent);
                if (mSourceText == null) {
                    finishWithoutAnimation();
                    return;
                }
                if ("Aedict Notepad".equals(mSourceText[0]) && addFromAedict(mSourceText[1])) {
                    finishWithoutAnimation();
                    return;
                }
                mAddNote = true;
                break;
            }
        default:
            break;
    }
    // Note type Selector
    mNoteTypeSpinner = findViewById(R.id.note_type_spinner);
    ArrayList<Model> models = getCol().getModels().all();
    Collections.sort(models, NamedJSONComparator.instance);
    final ArrayList<String> modelNames = new ArrayList<>(models.size());
    mAllModelIds = new ArrayList<>(models.size());
    for (JSONObject m : models) {
        modelNames.add(m.getString("name"));
        mAllModelIds.add(m.getLong("id"));
    }
    ArrayAdapter<String> noteTypeAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, modelNames);
    mNoteTypeSpinner.setAdapter(noteTypeAdapter);
    noteTypeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    // Deck Selector
    TextView deckTextView = findViewById(R.id.CardEditorDeckText);
    // If edit mode and more than one card template distinguish between "Deck" and "Card deck"
    if (!mAddNote && mEditorNote.model().getJSONArray("tmpls").length() > 1) {
        deckTextView.setText(R.string.CardEditorCardDeck);
    }
    mNoteDeckSpinner = findViewById(R.id.note_deck_spinner);
    ArrayList<Deck> decks = getCol().getDecks().all();
    Collections.sort(decks, DeckComparator.instance);
    final ArrayList<String> deckNames = new ArrayList<>(decks.size());
    mAllDeckIds = new ArrayList<>(decks.size());
    for (Deck d : decks) {
        // add current deck and all other non-filtered decks to deck list
        long thisDid = d.getLong("id");
        if (d.getInt("dyn") == 0 || (!mAddNote && mCurrentEditedCard != null && mCurrentEditedCard.getDid() == thisDid)) {
            deckNames.add(d.getString("name"));
            mAllDeckIds.add(thisDid);
        }
    }
    ArrayAdapter<String> noteDeckAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, deckNames);
    mNoteDeckSpinner.setAdapter(noteDeckAdapter);
    noteDeckAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    mNoteDeckSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
            // Timber.i("NoteEditor:: onItemSelected() fired on mNoteDeckSpinner with pos = %d", pos);
            mCurrentDid = mAllDeckIds.get(pos);
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        // Do Nothing
        }
    });
    mCurrentDid = intent.getLongExtra(EXTRA_DID, mCurrentDid);
    setDid(mEditorNote);
    setNote(mEditorNote, FieldChangeType.onActivityCreation(shouldReplaceNewlines()));
    if (mAddNote) {
        mNoteTypeSpinner.setOnItemSelectedListener(new SetNoteTypeListener());
        setTitle(R.string.menu_add_note);
        // set information transferred by intent
        String contents = null;
        String[] tags = intent.getStringArrayExtra(EXTRA_TAGS);
        if (mSourceText != null) {
            if (mAedictIntent && (mEditFields.size() == 3) && mSourceText[1].contains("[")) {
                contents = mSourceText[1].replaceFirst("\\[", "\u001f" + mSourceText[0] + "\u001f");
                contents = contents.substring(0, contents.length() - 1);
            } else if (mEditFields.size() > 0) {
                mEditFields.get(0).setText(mSourceText[0]);
                if (mEditFields.size() > 1) {
                    mEditFields.get(1).setText(mSourceText[1]);
                }
            }
        } else {
            contents = intent.getStringExtra(EXTRA_CONTENTS);
        }
        if (contents != null) {
            setEditFieldTexts(contents);
        }
        if (tags != null) {
            setTags(tags);
        }
    } else {
        mNoteTypeSpinner.setOnItemSelectedListener(new EditNoteTypeListener());
        setTitle(R.string.cardeditor_title_edit_card);
    }
    findViewById(R.id.CardEditorTagButton).setOnClickListener(v -> {
        Timber.i("NoteEditor:: Tags button pressed... opening tags editor");
        showTagsDialog();
    });
    if (!mAddNote && mCurrentEditedCard != null) {
        Timber.i("onCollectionLoaded() Edit note activity successfully started with card id %d", mCurrentEditedCard.getId());
    }
    if (mAddNote) {
        Timber.i("onCollectionLoaded() Edit note activity successfully started in add card mode with node id %d", mEditorNote.getId());
    }
    // don't open keyboard if not adding note
    if (!mAddNote) {
        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
    }
    // set focus to FieldEditText 'first' on startup like Anki desktop
    if (mEditFields != null && !mEditFields.isEmpty()) {
        mEditFields.getFirst().requestFocus();
    }
}
Also used : ArrayList(java.util.ArrayList) Deck(com.ichi2.libanki.Deck) Intent(android.content.Intent) View(android.view.View) AdapterView(android.widget.AdapterView) TextView(android.widget.TextView) SuppressLint(android.annotation.SuppressLint) JSONObject(com.ichi2.utils.JSONObject) Model(com.ichi2.libanki.Model) OnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener) TextView(android.widget.TextView) ArrayAdapter(android.widget.ArrayAdapter)

Aggregations

JSONObject (com.ichi2.utils.JSONObject)53 Test (org.junit.Test)35 JSONArray (com.ichi2.utils.JSONArray)28 Model (com.ichi2.libanki.Model)24 ArrayList (java.util.ArrayList)16 Intent (android.content.Intent)14 RobolectricTest (com.ichi2.anki.RobolectricTest)14 Collection (com.ichi2.libanki.Collection)12 Note (com.ichi2.libanki.Note)12 SuppressLint (android.annotation.SuppressLint)9 HashMap (java.util.HashMap)8 Bundle (android.os.Bundle)7 JSONException (com.ichi2.utils.JSONException)7 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)6 Card (com.ichi2.libanki.Card)6 ShadowActivity (org.robolectric.shadows.ShadowActivity)6 ShadowIntent (org.robolectric.shadows.ShadowIntent)6 View (android.view.View)5 ContentResolver (android.content.ContentResolver)4 ContentValues (android.content.ContentValues)4