Commit Graph

11 Commits

Author SHA1 Message Date
e3725cee55 Add a vanilla-creature filter to card and library search
Filtering for creatures with an empty rules box can't be done from
`oracle_cards.oracle_text`: that column joins every face together, so an
Adventure card always carries its spell half's text and a naive `oracle_text
= ''` test would exclude exactly the cards worth including.

Derive it at ingest instead, from the front face's own text — the front is the
half that resolves as the creature, and adventure/prepared/transform cards are
all cast from it. Exposed as `vanilla_only` behind its own `has_vanilla`
capability check rather than folded into `has_universes_beyond`, since it
lands in a later reference-schema revision and a db can have one column
without the other. Needs a card-data re-download before it does anything.
2026-08-14 01:02:29 -05:00
dfba2403a8 Add colorless filters, and make set listings filterable
Colorless

There was no way to ask for colorless cards — the colour toggles are a 5-bit
WUBRG mask where 0 already means "don't filter by colour", leaving nothing to
express "no colours at all". That's exactly what you need to find a colorless
commander's card pool.

Adds a "C" pip to both colour rows, matching how ColorPips already renders
colorless cards, backed by two explicit booleans rather than a sixth bit — a
filter mask and a card's real colour mask staying the same shape is worth
keeping. The two rows mean different things and both are useful: on the
commander row C filters colour *identity*, which is the Commander rule; on the
includes row it filters the card's own colours. A card printed colorless can
still carry a coloured identity through mana symbols in its text, and it's the
identity that bars it from a colorless commander's deck.

Set listings

News > Releases had its own card path and so couldn't be filtered. A new
set_code filter (matched against printings.set_code, already ingested) lets the
set browser run through search_reference instead, so every criterion works
there identically rather than being reimplemented over a live Scryfall
response.

That alone would have cost the ability to browse an upcoming set, since
search_reference only knows downloaded card data — and upcoming sets are half
the point of the tab. So the browser picks a source per set: downloaded data
where it exists, with the full filter panel; otherwise Scryfall directly, with
the panel hidden and a line explaining why. A panel that silently does nothing
would be worse than no panel.

The source is decided by an *unfiltered* probe. Keying off whether the current
criteria match anything would flip a properly indexed set to "live" the moment
a filter excluded everything, dropping the panel exactly when it was in use.
2026-08-10 22:34:46 -05:00
04e9c3cbbb Rework library sync around a JSON document; add card filters
Sync

The previous design put the merge inside SQL: timestamp-stamping triggers,
a tombstone table, per-device SQLite snapshots, a device id in the database,
and row merges written as correlated-subquery UPDATEs. All of that schema
was inherited by desktop, and the merge was very hard to verify.

Replace it with a single JSON document plus a three-way merge in plain Rust.
Storing the last-read remote document as the merge base makes "who changed
what" and "what was deleted" derivable, which removes the tombstone table,
the updated_at columns and all eight triggers. It also makes a single shared
file safe: if a publish is lost the remote is unchanged, so the next merge
re-detects the local edits and republishes rather than reading their absence
as a deletion. That removes the need for per-device files and for device
identity entirely. Schema impact drops to one column, decks.uuid.

Conflicts resolve to "theirs", which is required for convergence rather than
chosen for taste — preferring ours has each device re-asserting its own value
forever. Every such choice is reported to the user.

SQLite becomes invisible: the working copy lives in the app data dir and the
user only ever names a .json file. There is always a document, defaulting to
private storage, so edits are never stranded with nowhere to be saved.
Pointing at a file that doesn't exist yet moves the current library there;
pointing at one that does adopts it. A converter brings a pre-document
library.db across.

Android reaches the folder through the Storage Access Framework rather than
MANAGE_EXTERNAL_STORAGE, so no storage permission is declared at all.

Filters

Track card origin in reference.db: Universes Beyond, digital-only and
Un-set cards, plus numeric power/toughness. Each origin flag is derived as
"every printing", not "any printing" — ordinary cards get reprinted into
those sets, and Lightning Bolt appearing in Marvel Commander must not hide
it. Non-numeric power ("*", "1+*") stays NULL so it drops out of range
filters instead of being compared as zero.

Also wire up filters over data already present: price range, format legality
(restricted counts as legal) and "can be a commander". All of these degrade
silently against an older reference.db rather than failing every query.

The shared criteria live in one component used by both filter panels, as a
compact row of icon toggles.

Card Search gains the Library tab's bulk selection: checkboxes in both views,
select-all, and a bulk add-to-deck with a single undo for the whole batch.
2026-08-07 22:03:49 -05:00
2b361c4a85 Add a Card Search tab and fix horizontal-card (Battle/Plane) preview orientation
Card Search browses the whole downloaded card universe (not just owned
cards), reusing the Library tab's filter/group/sort/list/tiles UI; results
show ownership and offer quick "own" and "add to deck" actions.

Battles, Planes, and Phenomena store their Scryfall image portrait-shaped
with the content itself rotated, so hover/click previews now detect this
(a new `horizontal` flag threaded through ingest and every card query, with
graceful fallback for a reference.db built before the column existed) and
rotate the image back into place. Single-faced and non-DFC cases are
verified fixed; a double-faced Battle's front face still needs another pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 20:55:17 -05:00
008ab33723 Add deck legality checking, deck/library import-export, and a command palette
Threads Scryfall's per-format legalities through the reference db and adds a
deck-page indicator (structural rules + banned/restricted lists) that lists
violation reasons inline. Decks and selected library cards can now be
exported to/imported from plain-text decklists, with best-effort name
resolution and a report of anything that didn't match. Also adds a shuffle-
and-draw sample hand modal, and an Alt+/ command palette for jumping to a
tab, deck, or card without leaving the keyboard.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 00:21:22 -05:00
cf9c930b02 Add card USD pricing and a deck maybeboard
Prices come from Scryfall's prices.usd on printings, shown as a hover badge
on card tiles. The price is picked independently of whichever printing
supplies the display image (the cheapest known price across all printings),
since the display printing is often a promo/variant with no listed price.

The maybeboard lets a deck track cards under consideration without counting
them in deck analysis stats or library assignment totals. Cards move between
mainboard and maybeboard via a per-card toggle; maybeboarding the commander
clears commander status.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 21:32:25 -05:00
e3f8a299de Add deck analysis panel with mana production/consumption bars and oracle text search
Threads a new produced_mana/produces_colorless field through the whole card
read path (ingest, library, filters, decks, search) so the deck view can
show what colors a deck's manabase actually produces, alongside its existing
color identity. Also adds a mana consumption bar (colored casting costs of
nonland spells) and stacks the mana curve histogram by color. Adds an
oracle-text substring filter to the library search, mirroring the existing
location filter. Rearranges the deck sidebar list into two rows (name, then
format chip + actions) so long names and action buttons no longer collide,
and removes the drop shadows from the commander hero panel/image.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-08 23:54:47 -05:00
436975f64f Add location filter to library search
LibraryFilter.location does a case-insensitive substring match against
the stored location (e.g. "Box 1"), mirroring the existing text filter.
Tested for substring/case-insensitivity and the empty-string no-op case.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-07 21:34:58 -05:00
3e41c9d055 Add library_stats aggregate query for the sidebar summary
New LibraryStats (unique cards owned, total copies, deck count, and
per-color copy counts including colorless) via Catalog::library_stats,
tested against the fixture catalog.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-07 21:21:33 -05:00
2ea3c56511 Capture back-face printing images for double-faced cards
Add a back_image_uri column to printings, populated during ingest from
a card's second card_faces image (only present for transform/MDFC/
reversible cards — split/adventure cards share one combined image and
correctly get ""). Plumb it through CardRef across every query path
(search, library, filters, deck contents) via the same printing row,
using a shared deterministic ORDER BY so front/back always come from
one printing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-07 20:54:55 -05:00
399c628461 Initial commit: MTG personal library catalog (Tauri v2 + React/TS)
Full working app with:
- Rust core (mtgc-core): Scryfall ingester, nucleo fuzzy search, SQLite two-DB
  architecture (reference.db + library.db via ATTACH), criteria filters, deck ops
- Tauri v2 shell exposing the core as typed IPC commands
- React/TS frontend: card entry, library browser, deck editor
- Features: fuzzy card search, color/CMC/type/commander-identity filters,
  tile/list view toggle, hover card previews, deck format + commander support,
  per-card location field, grouping by type/subtype/CMC/color, localStorage
  persistence for active tab/deck/grouping, Discord-inspired dark UI (#C8553D accent)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-07 19:37:56 -05:00