Skip to content

feat: add card flags to CardContentProvider and api#21322

Open
ColgateTotal77 wants to merge 2 commits into
ankidroid:mainfrom
ColgateTotal77:feature/add-card-flags-to-api
Open

feat: add card flags to CardContentProvider and api#21322
ColgateTotal77 wants to merge 2 commits into
ankidroid:mainfrom
ColgateTotal77:feature/add-card-flags-to-api

Conversation

@ColgateTotal77

@ColgateTotal77 ColgateTotal77 commented Jun 30, 2026

Copy link
Copy Markdown

Purpose / Description

Expand CardContentProvider and api to work with card flags.

Fixes

Approach

Added read/write for card flags in CardContentProvider and api.

How Has This Been Tested?

Implemented test for negative, too large, and valid flag codes.

Learning (optional, can help others)

I just looked at other api functions and content provider cases. Most of the code I just copied and a little tweaked for my case.

Checklist

  • You have a descriptive commit message with a short title (first line, max 50 chars).
  • You have commented your code, particularly in hard-to-understand areas
  • You have performed a self-review of your own code
  • UI changes: include screenshots of all affected screens (in particular showing any new or changed strings)
  • UI Changes: You have tested your change using the Google Accessibility Scanner

@welcome

welcome Bot commented Jun 30, 2026

Copy link
Copy Markdown

First PR! 🚀 We sincerely appreciate that you have taken the time to propose a change to AnkiDroid! Please have patience with us as we are all volunteers - we will get to this as soon as possible.

@sanjaysargam sanjaysargam left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Welcome to the community @ColgateTotal77
Thanks for contributing 🚀

}

Timber.d("CardContentProvider: flags update...")
currentCard.flags = flags

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It overwrites the whole flags field, but only the last 3 bits are meant to be the color, the rest can hold other data.

Please use the existing helper instead, which only touches those 3 bits:

currentCard.setUserFlag(flags)

And also I'd suggest a test that verifies setFlagRaw() preserves any non-flag bits already present in flags, which would also serve as a regression test

@sanjaysargam sanjaysargam added Needs Author Reply Waiting for a reply from the original author and removed Needs Review labels Jul 1, 2026

@criticalAY criticalAY left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really strong first PR, thank you!

FlashCardsContract.Card.FSRS_DESIRED_RETENTION -> rb.add(currentCard.fsrsDesiredRetention)
FlashCardsContract.Card.FSRS_DECAY -> rb.add(currentCard.decay)
FlashCardsContract.Card.LAST_REVIEW_TIME_SECONDS -> rb.add(currentCard.lastReviewTimeSecs)
FlashCardsContract.Card.FLAGS -> rb.add(currentCard.flags)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With card.flags = 8 + flag 4, this query returns 12 but two things break:

  1. The FLAGS contract KDoc says reads are "in the range from 0 to 7", and 12 isn't.
  2. Round-trip fails: a client that reads 12 and calls setFlagRaw(12) hits "must be in the range from 0 to 7" we hand back a value our own writer rejects.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are asking about test (assertEquals(12, it.getInt(it.getColumnIndex(FlashCardsContract.Card.FLAGS)))), idea to test setUserFlag (that this function affects only first 3 bits) was suggested by @sanjaysargam. So I set 8 (1000) manually, and then set 4 (100) with setUserFlag (via contentResolver.update), so if we override only first 3 bits, we won't affect fourth, so it will be 12 (1100).

Maybe I should move it to separate test and add comments with explanations?

*
* param code The code of the flag.
*/
public enum class Flag(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: nothing enforces the "keep in sync with com.ichi2.anki.Flag" comment. A tiny test asserting the code values match would catch drift later. Optional.

Comment on lines +2619 to +2624
val tooLargeValue =
ContentValues().apply {
put(FlashCardsContract.Card.FLAGS, 8)
}
val exception2 = assertThrows<IllegalArgumentException> { contentResolver.update(noteCardUri, tooLargeValue, null, null) }
assertEquals(exception2.message, "Flags value must be in the range from 0 to 7")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@david-allison the forward-compat check you asked for isn't quite this: the 0–7 bound is hardcoded in the provider, so this keeps passing even after a backend bump. Deriving the max from the Flag enum would make it a real canary. Do you want that in this PR or a follow-up?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs Author Reply Waiting for a reply from the original author New contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API] Extension ContentResolver / api to read/write card data

3 participants