Search in sources :

Example 36 with CHANGED

use of com.ichi2.anki.CardBrowser.Column.CHANGED in project AnkiChinaAndroid by ankichinateam.

the class TagsDialog method adjustToolbar.

private void adjustToolbar(View tagsDialogView) {
    Toolbar mToolbar = tagsDialogView.findViewById(R.id.tags_dialog_toolbar);
    mToolbar.setTitle(mDialogTitle);
    mToolbar.inflateMenu(R.menu.tags_dialog_menu);
    final InputFilter addTagFilter = (source, start, end, dest, dstart, dend) -> {
        for (int i = start; i < end; i++) {
            if (source.charAt(i) == ' ') {
                return "";
            }
        }
        return null;
    };
    MenuItem mToolbarAddItem = mToolbar.getMenu().findItem(R.id.tags_dialog_action_add);
    mToolbarAddItem.setOnMenuItemClickListener(menuItem -> {
        String query = mToolbarSearchView.getQuery().toString();
        if (mToolbarSearchItem.isActionViewExpanded() && !TextUtils.isEmpty(query)) {
            addTag(query);
            mToolbarSearchView.setQuery("", true);
        } else {
            MaterialDialog.Builder addTagBuilder = new MaterialDialog.Builder(getActivity()).title(getString(R.string.add_tag)).negativeText(R.string.dialog_cancel).positiveText(R.string.dialog_ok).inputType(InputType.TYPE_CLASS_TEXT).input(R.string.tag_name, R.string.empty_string, (dialog, input) -> addTag(input.toString()));
            final MaterialDialog addTagDialog = addTagBuilder.build();
            EditText inputET = addTagDialog.getInputEditText();
            inputET.setFilters(new InputFilter[] { addTagFilter });
            addTagDialog.show();
        }
        return true;
    });
    mToolbarSearchItem = mToolbar.getMenu().findItem(R.id.tags_dialog_action_filter);
    mToolbarSearchView = (SearchView) mToolbarSearchItem.getActionView();
    EditText queryET = mToolbarSearchView.findViewById(R.id.search_src_text);
    queryET.setFilters(new InputFilter[] { addTagFilter });
    mToolbarSearchView.setQueryHint(getString(R.string.filter_tags));
    mToolbarSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {

        @Override
        public boolean onQueryTextSubmit(String query) {
            mToolbarSearchView.clearFocus();
            return true;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            TagsArrayAdapter adapter = (TagsArrayAdapter) mTagsListRecyclerView.getAdapter();
            adapter.getFilter().filter(newText);
            return true;
        }
    });
    MenuItem checkAllItem = mToolbar.getMenu().findItem(R.id.tags_dialog_action_select_all);
    checkAllItem.setOnMenuItemClickListener(menuItem -> {
        boolean changed = false;
        if (mCurrentTags.containsAll(mTagsArrayAdapter.mTagsList)) {
            mCurrentTags.removeAll(mTagsArrayAdapter.mTagsList);
            changed = true;
        } else {
            for (String tag : mTagsArrayAdapter.mTagsList) {
                if (!mCurrentTags.contains(tag)) {
                    mCurrentTags.add(tag);
                    changed = true;
                }
            }
        }
        if (changed) {
            mTagsArrayAdapter.notifyDataSetChanged();
        }
        return true;
    });
    switch(mType) {
        case TYPE_ADD_TAG:
            mToolbarSearchView.setQueryHint(getString(R.string.add_new_filter_tags));
            break;
        default:
            mToolbarAddItem.setVisible(false);
            break;
    }
}
Also used : Bundle(android.os.Bundle) NonNull(androidx.annotation.NonNull) AnalyticsDialogFragment(com.ichi2.anki.analytics.AnalyticsDialogFragment) WindowManager(android.view.WindowManager) R(com.ichi2.anki.R) Filter(android.widget.Filter) Dialog(android.app.Dialog) RadioGroup(android.widget.RadioGroup) TreeSet(java.util.TreeSet) MenuItem(android.view.MenuItem) ArrayList(java.util.ArrayList) UIUtils(com.ichi2.anki.UIUtils) View(android.view.View) RecyclerView(androidx.recyclerview.widget.RecyclerView) LayoutInflater(android.view.LayoutInflater) InputType(android.text.InputType) TextUtils(android.text.TextUtils) SearchView(androidx.appcompat.widget.SearchView) ViewGroup(android.view.ViewGroup) List(java.util.List) TextView(android.widget.TextView) CheckedTextView(android.widget.CheckedTextView) Toolbar(androidx.appcompat.widget.Toolbar) Filterable(android.widget.Filterable) LinearLayoutManager(androidx.recyclerview.widget.LinearLayoutManager) InputFilter(android.text.InputFilter) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) Collections(java.util.Collections) EditText(android.widget.EditText) Resources(android.content.res.Resources) EditText(android.widget.EditText) InputFilter(android.text.InputFilter) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) MenuItem(android.view.MenuItem) SearchView(androidx.appcompat.widget.SearchView) Toolbar(androidx.appcompat.widget.Toolbar)

Example 37 with CHANGED

use of com.ichi2.anki.CardBrowser.Column.CHANGED in project AnkiChinaAndroid by ankichinateam.

the class CardContentProvider method update.

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    if (!hasReadWritePermission() && shouldEnforceUpdateSecurity(uri)) {
        throwSecurityException("update", uri);
    }
    Collection col = CollectionHelper.getInstance().getCol(mContext);
    if (col == null) {
        throw new IllegalStateException(COL_NULL_ERROR_MSG);
    }
    col.log(getLogMessage("update", uri));
    // Find out what data the user is requesting
    int match = sUriMatcher.match(uri);
    // Number of updated entries (return value)
    int updated = 0;
    switch(match) {
        case NOTES_V2:
        case NOTES:
            throw new IllegalArgumentException("Not possible to update notes directly (only through data URI)");
        case NOTES_ID:
            {
                /* Direct access note details
                 */
                Note currentNote = getNoteFromUri(uri, col);
                // the key of the ContentValues contains the column name
                // the value of the ContentValues contains the row value.
                Set<Map.Entry<String, Object>> valueSet = values.valueSet();
                for (Map.Entry<String, Object> entry : valueSet) {
                    String key = entry.getKey();
                    // when the client does not specify FLDS, then don't update the FLDS
                    if (key.equals(FlashCardsContract.Note.FLDS)) {
                        // Update FLDS
                        Timber.d("CardContentProvider: flds update...");
                        String newFldsEncoded = (String) entry.getValue();
                        String[] flds = Utils.splitFields(newFldsEncoded);
                        // Check that correct number of flds specified
                        if (flds.length != currentNote.getFields().length) {
                            throw new IllegalArgumentException("Incorrect flds argument : " + newFldsEncoded);
                        }
                        // Update the note
                        for (int idx = 0; idx < flds.length; idx++) {
                            currentNote.setField(idx, flds[idx]);
                        }
                        updated++;
                    } else if (key.equals(FlashCardsContract.Note.TAGS)) {
                        // Update tags
                        Timber.d("CardContentProvider: tags update...");
                        Object tags = entry.getValue();
                        if (tags != null) {
                            currentNote.setTagsFromStr(String.valueOf(tags));
                        }
                        updated++;
                    } else {
                        // Unsupported column
                        throw new IllegalArgumentException("Unsupported column: " + key);
                    }
                }
                Timber.d("CardContentProvider: Saving note...");
                currentNote.flush();
                break;
            }
        case NOTES_ID_CARDS:
            // TODO: To be implemented
            throw new UnsupportedOperationException("Not yet implemented");
        // break;
        case NOTES_ID_CARDS_ORD:
            {
                Card currentCard = getCardFromUri(uri, col);
                boolean isDeckUpdate = false;
                long did = -1;
                // the key of the ContentValues contains the column name
                // the value of the ContentValues contains the row value.
                Set<Map.Entry<String, Object>> valueSet = values.valueSet();
                for (Map.Entry<String, Object> entry : valueSet) {
                    // Only updates on deck id is supported
                    String key = entry.getKey();
                    isDeckUpdate = key.equals(FlashCardsContract.Card.DECK_ID);
                    did = values.getAsLong(key);
                }
                if (col.getDecks().isDyn(did)) {
                    throw new IllegalArgumentException("Cards cannot be moved to a filtered deck");
                }
                /* now update the card
                 */
                if ((isDeckUpdate) && (did >= 0)) {
                    Timber.d("CardContentProvider: Moving card to other deck...");
                    col.getDecks().flush();
                    currentCard.setDid(did);
                    currentCard.flush();
                    col.save();
                    updated++;
                } else {
                    // User tries an operation that is not (yet?) supported.
                    throw new IllegalArgumentException("Currently only updates of decks are supported");
                }
                break;
            }
        case MODELS:
            throw new IllegalArgumentException("Cannot update models in bulk");
        case MODELS_ID:
            // Get the input parameters
            String newModelName = values.getAsString(FlashCardsContract.Model.NAME);
            String newCss = values.getAsString(FlashCardsContract.Model.CSS);
            String newDid = values.getAsString(FlashCardsContract.Model.DECK_ID);
            String newFieldList = values.getAsString(FlashCardsContract.Model.FIELD_NAMES);
            if (newFieldList != null) {
                // Changing the field names would require a full-sync
                throw new IllegalArgumentException("Field names cannot be changed via provider");
            }
            Integer newSortf = values.getAsInteger(FlashCardsContract.Model.SORT_FIELD_INDEX);
            Integer newType = values.getAsInteger(FlashCardsContract.Model.TYPE);
            String newLatexPost = values.getAsString(FlashCardsContract.Model.LATEX_POST);
            String newLatexPre = values.getAsString(FlashCardsContract.Model.LATEX_PRE);
            // Get the original note JSON
            Model model = col.getModels().get(getModelIdFromUri(uri, col));
            try {
                // Update model name and/or css
                if (newModelName != null) {
                    model.put("name", newModelName);
                    updated++;
                }
                if (newCss != null) {
                    model.put("css", newCss);
                    updated++;
                }
                if (newDid != null) {
                    if (col.getDecks().isDyn(Long.parseLong(newDid))) {
                        throw new IllegalArgumentException("Cannot set a filtered deck as default deck for a model");
                    }
                    model.put("did", newDid);
                    updated++;
                }
                if (newSortf != null) {
                    model.put("sortf", newSortf);
                    updated++;
                }
                if (newType != null) {
                    model.put("type", newType);
                    updated++;
                }
                if (newLatexPost != null) {
                    model.put("latexPost", newLatexPost);
                    updated++;
                }
                if (newLatexPre != null) {
                    model.put("latexPre", newLatexPre);
                    updated++;
                }
                col.getModels().save(model);
                col.save();
            } catch (JSONException e) {
                Timber.e(e, "JSONException updating model");
            }
            break;
        case MODELS_ID_TEMPLATES:
            throw new IllegalArgumentException("Cannot update templates in bulk");
        case MODELS_ID_TEMPLATES_ID:
            Long mid = values.getAsLong(CardTemplate.MODEL_ID);
            Integer ord = values.getAsInteger(CardTemplate.ORD);
            String name = values.getAsString(CardTemplate.NAME);
            String qfmt = values.getAsString(CardTemplate.QUESTION_FORMAT);
            String afmt = values.getAsString(CardTemplate.ANSWER_FORMAT);
            String bqfmt = values.getAsString(CardTemplate.BROWSER_QUESTION_FORMAT);
            String bafmt = values.getAsString(CardTemplate.BROWSER_ANSWER_FORMAT);
            // Throw exception if read-only fields are included
            if (mid != null || ord != null) {
                throw new IllegalArgumentException("Updates to mid or ord are not allowed");
            }
            // Update the model
            try {
                Integer templateOrd = Integer.parseInt(uri.getLastPathSegment());
                Model existingModel = col.getModels().get(getModelIdFromUri(uri, col));
                JSONArray templates = existingModel.getJSONArray("tmpls");
                JSONObject template = templates.getJSONObject(templateOrd);
                if (name != null) {
                    template.put("name", name);
                    updated++;
                }
                if (qfmt != null) {
                    template.put("qfmt", qfmt);
                    updated++;
                }
                if (afmt != null) {
                    template.put("afmt", afmt);
                    updated++;
                }
                if (bqfmt != null) {
                    template.put("bqfmt", bqfmt);
                    updated++;
                }
                if (bafmt != null) {
                    template.put("bafmt", bafmt);
                    updated++;
                }
                // Save the model
                templates.put(templateOrd, template);
                existingModel.put("tmpls", templates);
                col.getModels().save(existingModel, true);
                col.save();
            } catch (JSONException e) {
                throw new IllegalArgumentException("Model is malformed", e);
            }
            break;
        case SCHEDULE:
            {
                Set<Map.Entry<String, Object>> valueSet = values.valueSet();
                int cardOrd = -1;
                long noteID = -1;
                int ease = -1;
                long timeTaken = -1;
                int bury = -1;
                int suspend = -1;
                for (Map.Entry<String, Object> entry : valueSet) {
                    String key = entry.getKey();
                    if (key.equals(FlashCardsContract.ReviewInfo.NOTE_ID)) {
                        noteID = values.getAsLong(key);
                    } else if (key.equals(FlashCardsContract.ReviewInfo.CARD_ORD)) {
                        cardOrd = values.getAsInteger(key);
                    } else if (key.equals(FlashCardsContract.ReviewInfo.EASE)) {
                        ease = values.getAsInteger(key);
                    } else if (key.equals(FlashCardsContract.ReviewInfo.TIME_TAKEN)) {
                        timeTaken = values.getAsLong(key);
                    } else if (key.equals(FlashCardsContract.ReviewInfo.BURY)) {
                        bury = values.getAsInteger(key);
                    } else if (key.equals(FlashCardsContract.ReviewInfo.SUSPEND)) {
                        suspend = values.getAsInteger(key);
                    }
                }
                if (cardOrd != -1 && noteID != -1) {
                    Card cardToAnswer = getCard(noteID, cardOrd, col);
                    if (cardToAnswer != null) {
                        if (bury == 1) {
                            // bury card
                            buryOrSuspendCard(col, col.getSched(), cardToAnswer, true);
                        } else if (suspend == 1) {
                            // suspend card
                            buryOrSuspendCard(col, col.getSched(), cardToAnswer, false);
                        } else {
                            answerCard(col, col.getSched(), cardToAnswer, ease, timeTaken);
                        }
                        updated++;
                    } else {
                        Timber.e("Requested card with noteId %d and cardOrd %d was not found. Either the provided " + "noteId/cardOrd were wrong or the card has been deleted in the meantime.", noteID, cardOrd);
                    }
                }
                break;
            }
        case DECKS:
            throw new IllegalArgumentException("Can't update decks in bulk");
        case DECKS_ID:
            // TODO: be sure to throw exception if change to the dyn value of a deck is requested
            throw new UnsupportedOperationException("Not yet implemented");
        case DECK_SELECTED:
            {
                Set<Map.Entry<String, Object>> valueSet = values.valueSet();
                for (Map.Entry<String, Object> entry : valueSet) {
                    String key = entry.getKey();
                    if (key.equals(FlashCardsContract.Deck.DECK_ID)) {
                        long deckId = values.getAsLong(key);
                        if (selectDeckWithCheck(col, deckId)) {
                            updated++;
                        }
                    }
                }
                col.save();
                break;
            }
        default:
            // Unknown URI type
            throw new IllegalArgumentException("uri " + uri + " is not supported");
    }
    return updated;
}
Also used : Set(java.util.Set) JSONArray(com.ichi2.utils.JSONArray) JSONException(com.ichi2.utils.JSONException) Card(com.ichi2.libanki.Card) JSONObject(com.ichi2.utils.JSONObject) Note(com.ichi2.libanki.Note) Model(com.ichi2.libanki.Model) Collection(com.ichi2.libanki.Collection) JSONObject(com.ichi2.utils.JSONObject) Map(java.util.Map)

Example 38 with CHANGED

use of com.ichi2.anki.CardBrowser.Column.CHANGED in project AnkiChinaAndroid by ankichinateam.

the class CardContentProvider method query.

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String order) {
    if (!hasReadWritePermission() && shouldEnforceQueryOrInsertSecurity()) {
        throwSecurityException("query", uri);
    }
    Collection col = CollectionHelper.getInstance().getCol(mContext);
    if (col == null) {
        throw new IllegalStateException(COL_NULL_ERROR_MSG);
    }
    Timber.d(getLogMessage("query", uri));
    // Find out what data the user is requesting
    int match = sUriMatcher.match(uri);
    switch(match) {
        case NOTES_V2:
            {
                /* Search for notes using direct SQL query */
                String[] proj = sanitizeNoteProjection(projection);
                String sql = SQLiteQueryBuilder.buildQueryString(false, "notes", proj, selection, null, null, order, null);
                return col.getDb().getDatabase().query(sql, selectionArgs);
            }
        case NOTES:
            {
                /* Search for notes using the libanki browser syntax */
                String[] proj = sanitizeNoteProjection(projection);
                String query = (selection != null) ? selection : "";
                List<Long> noteIds = col.findNotes(query);
                if ((noteIds != null) && (!noteIds.isEmpty())) {
                    String sel = String.format("id in (%s)", TextUtils.join(",", noteIds));
                    String sql = SQLiteQueryBuilder.buildQueryString(false, "notes", proj, sel, null, null, order, null);
                    return col.getDb().getDatabase().query(sql);
                } else {
                    return null;
                }
            }
        case NOTES_ID:
            {
                /* Direct access note with specific ID*/
                String noteId = uri.getPathSegments().get(1);
                String[] proj = sanitizeNoteProjection(projection);
                String sql = SQLiteQueryBuilder.buildQueryString(false, "notes", proj, "id=?", null, null, order, null);
                return col.getDb().getDatabase().query(sql, new String[] { noteId });
            }
        case NOTES_ID_CARDS:
            {
                Note currentNote = getNoteFromUri(uri, col);
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Card.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                for (Card currentCard : currentNote.cards()) {
                    addCardToCursor(currentCard, rv, col, columns);
                }
                return rv;
            }
        case NOTES_ID_CARDS_ORD:
            {
                Card currentCard = getCardFromUri(uri, col);
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Card.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                addCardToCursor(currentCard, rv, col, columns);
                return rv;
            }
        case MODELS:
            {
                Models models = col.getModels();
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Model.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                for (Long modelId : models.getModels().keySet()) {
                    addModelToCursor(modelId, models, rv, columns);
                }
                return rv;
            }
        case MODELS_ID:
            {
                long modelId = getModelIdFromUri(uri, col);
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Model.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                addModelToCursor(modelId, col.getModels(), rv, columns);
                return rv;
            }
        case MODELS_ID_TEMPLATES:
            {
                /* Direct access model templates */
                Models models = col.getModels();
                Model currentModel = models.get(getModelIdFromUri(uri, col));
                String[] columns = ((projection != null) ? projection : CardTemplate.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                try {
                    JSONArray templates = currentModel.getJSONArray("tmpls");
                    for (int idx = 0; idx < templates.length(); idx++) {
                        JSONObject template = templates.getJSONObject(idx);
                        addTemplateToCursor(template, currentModel, idx + 1, models, rv, columns);
                    }
                } catch (JSONException e) {
                    throw new IllegalArgumentException("Model is malformed", e);
                }
                return rv;
            }
        case MODELS_ID_TEMPLATES_ID:
            {
                /* Direct access model template with specific ID */
                Models models = col.getModels();
                int ord = Integer.parseInt(uri.getLastPathSegment());
                Model currentModel = models.get(getModelIdFromUri(uri, col));
                String[] columns = ((projection != null) ? projection : CardTemplate.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                try {
                    JSONObject template = getTemplateFromUri(uri, col);
                    addTemplateToCursor(template, currentModel, ord + 1, models, rv, columns);
                } catch (JSONException e) {
                    throw new IllegalArgumentException("Model is malformed", e);
                }
                return rv;
            }
        case SCHEDULE:
            {
                String[] columns = ((projection != null) ? projection : FlashCardsContract.ReviewInfo.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                long selectedDeckBeforeQuery = col.getDecks().selected();
                long deckIdOfTemporarilySelectedDeck = -1;
                // the number of scheduled cards to return
                int limit = 1;
                int selectionArgIndex = 0;
                // parsing the selection arguments
                if (selection != null) {
                    // split selection to get arguments like "limit=?"
                    String[] args = selection.split(",");
                    for (String arg : args) {
                        // split arguments into key ("limit") and value ("?")
                        String[] keyAndValue = arg.split("=");
                        try {
                            // check if value is a placeholder ("?"), if so replace with the next value of selectionArgs
                            String value = "?".equals(keyAndValue[1].trim()) ? selectionArgs[selectionArgIndex++] : keyAndValue[1];
                            if ("limit".equals(keyAndValue[0].trim())) {
                                limit = Integer.valueOf(value);
                            } else if ("deckID".equals(keyAndValue[0].trim())) {
                                deckIdOfTemporarilySelectedDeck = Long.valueOf(value);
                                if (!selectDeckWithCheck(col, deckIdOfTemporarilySelectedDeck)) {
                                    // if the provided deckID is wrong, return empty cursor.
                                    return rv;
                                }
                            }
                        } catch (NumberFormatException nfe) {
                            nfe.printStackTrace();
                        }
                    }
                }
                // retrieve the number of cards provided by the selection parameter "limit"
                col.getSched().deferReset();
                for (int k = 0; k < limit; k++) {
                    Card currentCard = col.getSched().getCard();
                    if (currentCard == null) {
                        break;
                    }
                    int buttonCount = col.getSched().answerButtons(currentCard);
                    JSONArray buttonTexts = new JSONArray();
                    for (int i = 0; i < buttonCount; i++) {
                        buttonTexts.put(col.getSched().nextIvlStr(mContext, currentCard, i + 1));
                    }
                    addReviewInfoToCursor(currentCard, buttonTexts, buttonCount, rv, col, columns);
                }
                if (deckIdOfTemporarilySelectedDeck != -1) {
                    // if the selected deck was changed
                    // change the selected deck back to the one it was before the query
                    col.getDecks().select(selectedDeckBeforeQuery);
                }
                return rv;
            }
        case DECKS:
            {
                List<DeckDueTreeNode> allDecks = col.getSched().deckDueList();
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Deck.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, allDecks.size());
                for (DeckDueTreeNode deck : allDecks) {
                    long id = deck.getDid();
                    String name = deck.getFullDeckName();
                    addDeckToCursor(id, name, getDeckCountsFromDueTreeNode(deck), rv, col, columns);
                }
                return rv;
            }
        case DECKS_ID:
            {
                /* Direct access deck */
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Deck.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                List<DeckDueTreeNode> allDecks = col.getSched().deckDueList();
                long deckId;
                deckId = Long.parseLong(uri.getPathSegments().get(1));
                for (DeckDueTreeNode deck : allDecks) {
                    if (deck.getDid() == deckId) {
                        addDeckToCursor(deckId, deck.getFullDeckName(), getDeckCountsFromDueTreeNode(deck), rv, col, columns);
                        return rv;
                    }
                }
                return rv;
            }
        case DECK_SELECTED:
            {
                long id = col.getDecks().selected();
                String name = col.getDecks().name(id);
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Deck.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                JSONArray counts = new JSONArray(Arrays.asList(col.getSched().counts()));
                addDeckToCursor(id, name, counts, rv, col, columns);
                return rv;
            }
        default:
            // Unknown URI type
            throw new IllegalArgumentException("uri " + uri + " is not supported");
    }
}
Also used : JSONArray(com.ichi2.utils.JSONArray) JSONException(com.ichi2.utils.JSONException) MatrixCursor(android.database.MatrixCursor) Card(com.ichi2.libanki.Card) DeckDueTreeNode(com.ichi2.libanki.sched.DeckDueTreeNode) JSONObject(com.ichi2.utils.JSONObject) Note(com.ichi2.libanki.Note) Model(com.ichi2.libanki.Model) Collection(com.ichi2.libanki.Collection) ArrayList(java.util.ArrayList) List(java.util.List) Models(com.ichi2.libanki.Models)

Example 39 with CHANGED

use of com.ichi2.anki.CardBrowser.Column.CHANGED in project AnkiChinaAndroid by ankichinateam.

the class CollectionTask method doInBackgroundConfSetSubdecks.

private TaskData doInBackgroundConfSetSubdecks(TaskData param) {
    Timber.d("doInBackgroundConfSetSubdecks");
    Collection col = getCol();
    Object[] data = param.getObjArray();
    Deck deck = (Deck) data[0];
    DeckConfig conf = (DeckConfig) data[1];
    try {
        TreeMap<String, Long> children = col.getDecks().children(deck.getLong("id"));
        for (Map.Entry<String, Long> entry : children.entrySet()) {
            Deck child = col.getDecks().get(entry.getValue());
            if (child.getInt("dyn") == 1) {
                continue;
            }
            TaskData newParam = new TaskData(new Object[] { child, conf });
            boolean changed = doInBackgroundConfChange(newParam).getBoolean();
            if (!changed) {
                return new TaskData(false);
            }
        }
        return new TaskData(true);
    } catch (JSONException e) {
        return new TaskData(false);
    }
}
Also used : Deck(com.ichi2.libanki.Deck) JSONException(com.ichi2.utils.JSONException) Collection(com.ichi2.libanki.Collection) JSONObject(com.ichi2.utils.JSONObject) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap) DeckConfig(com.ichi2.libanki.DeckConfig)

Example 40 with CHANGED

use of com.ichi2.anki.CardBrowser.Column.CHANGED in project AnkiChinaAndroid by ankichinateam.

the class CardTemplateEditorTest method testDeleteTemplateWithGeneratedCards.

/**
 * Normal template deletion - with no selective generation should of course work
 */
@SuppressWarnings("PMD.ExcessiveMethodLength")
@Test
public void testDeleteTemplateWithGeneratedCards() {
    String modelName = "Basic (and reversed card)";
    Model collectionBasicModelOriginal = getCurrentDatabaseModelCopy(modelName);
    // Start the CardTemplateEditor with a specific model, and make sure the model starts unchanged
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.putExtra("modelId", collectionBasicModelOriginal.getLong("id"));
    ActivityController<CardTemplateEditor> templateEditorController = Robolectric.buildActivity(CardTemplateEditor.class, intent).create().start().resume().visible();
    saveControllerForCleanup(templateEditorController);
    CardTemplateEditor testEditor = (CardTemplateEditor) templateEditorController.get();
    Assert.assertFalse("Model should not have changed yet", testEditor.modelHasChanged());
    Assert.assertEquals("Model should have 2 templates now", 2, testEditor.getTempModel().getTemplateCount());
    Assert.assertFalse("Ordinal pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 0));
    Assert.assertFalse("Ordinal pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 1));
    // Create note with forward and back info
    Note selectiveGeneratedNote = getCol().newNote(collectionBasicModelOriginal);
    selectiveGeneratedNote.setField(0, "TestFront");
    selectiveGeneratedNote.setField(1, "TestBack");
    getCol().addNote(selectiveGeneratedNote);
    Assert.assertEquals("card generation should result in two cards", 2, getModelCardCount(collectionBasicModelOriginal));
    // Test if we can delete the template - should be possible - but cancel the delete
    ShadowActivity shadowTestEditor = shadowOf(testEditor);
    Assert.assertTrue("Unable to click?", shadowTestEditor.clickMenuItem(R.id.action_delete));
    advanceRobolectricLooper();
    Assert.assertEquals("Did not show dialog about deleting template and it's card?", getQuantityString(R.plurals.card_template_editor_confirm_delete, 1, 1, "Card 1"), getDialogText(true));
    clickDialogButton(DialogAction.NEGATIVE, true);
    advanceRobolectricLooper();
    Assert.assertNotNull("Cannot delete template?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 0 }));
    Assert.assertNotNull("Cannot delete template?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 1 }));
    Assert.assertNull("Can delete both templates?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 0, 1 }));
    Assert.assertEquals("Change in database despite no change?", collectionBasicModelOriginal.toString().trim(), getCurrentDatabaseModelCopy(modelName).toString().trim());
    Assert.assertEquals("Model should have 2 templates still", 2, testEditor.getTempModel().getTemplateCount());
    // Add a template - click add, click confirm for card add, click confirm again for full sync
    shadowTestEditor.clickMenuItem(R.id.action_add);
    advanceRobolectricLooper();
    Assert.assertTrue("Model should have changed", testEditor.modelHasChanged());
    Assert.assertEquals("Change added but not adjusted correctly?", 2, TemporaryModel.getAdjustedAddOrdinalAtChangeIndex(testEditor.getTempModel(), 0));
    Assert.assertFalse("Ordinal pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 0));
    Assert.assertFalse("Ordinal pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 1));
    Assert.assertTrue("Ordinal not pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 2));
    Assert.assertTrue("Unable to click?", shadowTestEditor.clickMenuItem(R.id.action_confirm));
    advanceRobolectricLooper();
    Assert.assertFalse("Model should now be unchanged", testEditor.modelHasChanged());
    Assert.assertEquals("card generation should result in three cards", 3, getModelCardCount(collectionBasicModelOriginal));
    // reload the model for future comparison after saving the edit
    collectionBasicModelOriginal = getCurrentDatabaseModelCopy(modelName);
    // Start the CardTemplateEditor back up after saving (which closes the thing...)
    intent = new Intent(Intent.ACTION_VIEW);
    intent.putExtra("modelId", collectionBasicModelOriginal.getLong("id"));
    templateEditorController = Robolectric.buildActivity(CardTemplateEditor.class, intent).create().start().resume().visible();
    testEditor = (CardTemplateEditor) templateEditorController.get();
    shadowTestEditor = shadowOf(testEditor);
    Assert.assertFalse("Model should not have changed yet", testEditor.modelHasChanged());
    Assert.assertFalse("Ordinal pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 0));
    Assert.assertFalse("Ordinal pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 1));
    Assert.assertFalse("Ordinal pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 2));
    Assert.assertEquals("Model should have 3 templates now", 3, testEditor.getTempModel().getTemplateCount());
    // Add another template - but we work in memory for a while before saving
    shadowTestEditor.clickMenuItem(R.id.action_add);
    advanceRobolectricLooper();
    Assert.assertEquals("Change added but not adjusted correctly?", 3, TemporaryModel.getAdjustedAddOrdinalAtChangeIndex(testEditor.getTempModel(), 0));
    Assert.assertTrue("Model should have changed", testEditor.modelHasChanged());
    Assert.assertEquals("Model should have 4 templates now", 4, testEditor.getTempModel().getTemplateCount());
    Assert.assertFalse("Ordinal pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 0));
    Assert.assertFalse("Ordinal pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 1));
    Assert.assertFalse("Ordinal pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 2));
    Assert.assertTrue("Ordinal not pending add?", TemporaryModel.isOrdinalPendingAdd(testEditor.getTempModel(), 3));
    Assert.assertEquals("Change added but not adjusted correctly?", 3, TemporaryModel.getAdjustedAddOrdinalAtChangeIndex(testEditor.getTempModel(), 0));
    // Delete two pre-existing templates for real now - but still without saving it out, should work fine
    advanceRobolectricLooper();
    testEditor.mViewPager.setCurrentItem(0);
    Assert.assertTrue("Unable to click?", shadowTestEditor.clickMenuItem(R.id.action_delete));
    advanceRobolectricLooper();
    Assert.assertEquals("Did not show dialog about deleting template and it's card?", getQuantityString(R.plurals.card_template_editor_confirm_delete, 1, 1, "Card 1"), getDialogText(true));
    clickDialogButton(DialogAction.POSITIVE, true);
    advanceRobolectricLooper();
    advanceRobolectricLooper();
    testEditor.mViewPager.setCurrentItem(0);
    Assert.assertTrue("Unable to click?", shadowTestEditor.clickMenuItem(R.id.action_delete));
    advanceRobolectricLooper();
    Assert.assertEquals("Did not show dialog about deleting template and it's card?", getQuantityString(R.plurals.card_template_editor_confirm_delete, 1, 1, "Card 2"), getDialogText(true));
    clickDialogButton(DialogAction.POSITIVE, true);
    advanceRobolectricLooper();
    // - assert can delete any 1 or 2 Card templates but not all
    Assert.assertNotNull("Cannot delete template?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 0 }));
    Assert.assertNotNull("Cannot delete template?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 1 }));
    Assert.assertNotNull("Cannot delete template?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 2 }));
    Assert.assertNotNull("Cannot delete two templates?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 0, 1 }));
    Assert.assertNotNull("Cannot delete two templates?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 0, 2 }));
    Assert.assertNotNull("Cannot delete two templates?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 1, 2 }));
    Assert.assertNull("Can delete all templates?", getCol().getModels().getCardIdsForModel(collectionBasicModelOriginal.getLong("id"), new int[] { 0, 1, 2 }));
    Assert.assertEquals("Change already in database?", collectionBasicModelOriginal.toString().trim(), getCurrentDatabaseModelCopy(modelName).toString().trim());
    Assert.assertEquals("Change added but not adjusted correctly?", 1, TemporaryModel.getAdjustedAddOrdinalAtChangeIndex(testEditor.getTempModel(), 0));
    Assert.assertEquals("Change incorrectly pending add?", -1, TemporaryModel.getAdjustedAddOrdinalAtChangeIndex(testEditor.getTempModel(), 1));
    Assert.assertEquals("Change incorrectly pending add?", -1, TemporaryModel.getAdjustedAddOrdinalAtChangeIndex(testEditor.getTempModel(), 2));
    // Now confirm everything to persist it to the database
    Assert.assertTrue("Unable to click?", shadowTestEditor.clickMenuItem(R.id.action_confirm));
    advanceRobolectricLooper();
    advanceRobolectricLooper();
    Assert.assertNotEquals("Change not in database?", collectionBasicModelOriginal.toString().trim(), getCurrentDatabaseModelCopy(modelName).toString().trim());
    Assert.assertEquals("Model should have 2 templates now", 2, getCurrentDatabaseModelCopy(modelName).getJSONArray("tmpls").length());
    Assert.assertEquals("should be two cards", 2, getModelCardCount(collectionBasicModelOriginal));
}
Also used : Note(com.ichi2.libanki.Note) Model(com.ichi2.libanki.Model) ShadowActivity(org.robolectric.shadows.ShadowActivity) ShadowIntent(org.robolectric.shadows.ShadowIntent) Intent(android.content.Intent) Test(org.junit.Test)

Aggregations

JSONObject (com.ichi2.utils.JSONObject)19 Test (org.junit.Test)19 Note (com.ichi2.libanki.Note)16 Card (com.ichi2.libanki.Card)15 Collection (com.ichi2.libanki.Collection)15 Model (com.ichi2.libanki.Model)12 Intent (android.content.Intent)9 JSONArray (com.ichi2.utils.JSONArray)9 JSONException (com.ichi2.utils.JSONException)8 List (java.util.List)7 ShadowActivity (org.robolectric.shadows.ShadowActivity)7 ArrayList (java.util.ArrayList)6 Map (java.util.Map)6 ShadowIntent (org.robolectric.shadows.ShadowIntent)6 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)5 Cursor (android.database.Cursor)4 MatrixCursor (android.database.MatrixCursor)4 TaskData (com.ichi2.async.TaskData)4 Deck (com.ichi2.libanki.Deck)4 AbstractSched (com.ichi2.libanki.sched.AbstractSched)4