Adds bullets covering the new Store Page action, opt-in store-price
label, and the settings entry that controls them. Refreshes the
screenshot to show the current layout (Balatro on sale, formatted
in full strike+sale+% style).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Settings checkbox (off by default) toggles a price label between the
title and the cover image. Format combo offers four styles
(final / final+%, strikethrough, full strike+sale+%). Prices come from
the public appdetails endpoint, cached in-memory for 15 minutes.
"Free" / "—" cover F2P / unavailable apps.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous absolute URL pointed at the Gitea instance and was
proxied by GitHub's camo image cache, which kept serving an old
copy after the screenshot was updated. A relative path lets each
forge (GitHub, Gitea) resolve and serve the image from its own
repo blob, bypassing camo.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Catches the cached pkgver up to the current HEAD so makepkg's
displayed version matches what the dynamic pkgver() function
would compute.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The README still described the install-state filter as the only top-row
control. Bring it in line with what the app actually offers now: install
state, genre, multi-select tags (with search, AND'd), and multi-select
friends (intersection). Document the friends-filter prerequisites
(friend's profile privacy must expose friends list + game details).
Adds keyring and xdg-utils to the hard-dep list (already required at
runtime; previously omitted from the README) and python-steam as the
optional dep that unlocks instant genre + tag filtering via
appinfo.vdf. Replaces the Void Linux install hint with an Arch one
that mirrors what the PKGBUILD installs.
PKGBUILD optdepends wording updated alongside: it now reflects that
python-steam unlocks both genre AND tag filters, not just genre.
Screenshot replaced with one taken on the current build showing all
four filter controls.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces the single-select tag QComboBox with a TagsButton + TagsPopup
mirroring the friends pattern: a combo-styled button labelled "Tags (N) ▾"
opens a borderless popup containing a search input and a checkable list of
tags. Selecting multiple tags AND-filters games — a game must carry every
selected tag to survive — which makes it easy to narrow large libraries to
specific intersections (e.g. Roguelike + Co-op).
The search input is auto-focused on popup open and filters the list as the
user types, with a status line showing "N of M tag(s)". Selection state
survives search filtering and popup close/reopen.
The popup style and button style are renamed from FRIENDS_*_STYLE to
MULTISELECT_*_STYLE and reused by both FriendsPopup and TagsPopup; the
popup objectName moves from "FriendsPopup" to "MultiSelectPopup". The
TagsPopup adds a QLineEdit selector to the shared style.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a fourth filter control next to install/genre/tag: a "Friends ▾" button
that opens a checkable popup of the user's Steam friends. Selected friends'
libraries are intersected with the user's so only games everyone owns survive,
making it easy to combine with genre/tag to find a category of game everyone
in the room can play.
Friend list (with display names) is fetched via GetFriendList +
GetPlayerSummaries and cached at ~/.cache/steam-dice/friends.json. Each
friend's owned-games set is fetched lazily the first time they're checked
and cached at ~/.cache/steam-dice/friend_games/<steamid>.json. The main
refresh button re-fetches selected friends alongside the user's library;
the popup's own refresh button re-pulls just the friend list.
While a selected friend's library is still loading, the dice button stays
disabled and the status line shows which friend(s) are pending. Settings
changes that switch the steam_id clear in-memory friends state so the
previous user's friends don't pollute the new account.
Window width grows 40px (500 -> 540) and combo width shrinks 115 -> 100 so
all four controls fit on a single row.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The genre column hid its progress sub-label by default, so its effective
height was 28px while the filter and tag columns were 46px (combo +
sub-label). Qt's default vertical centering then dropped the genre combo
~9px below the others.
Use a single _combo_column() helper for all three filters, with fixed
115px width, fixed 28px combo height, and an always-present 14px sub-row
(progress label for genres, empty spacer for filter/tag). The progress
label now toggles its text instead of its visibility, preserving the
column's reserved space.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Steam's official genres list is coarse (~12 entries) and doesn't include
community-relevant categories like Roguelike, Soulslike, or Metroidvania —
those live in Steam's store tags. This adds a second combo box that filters
by store tag, AND'd with the genre filter.
Tag IDs in appinfo.vdf are translated via Steam's IStoreService/GetTagList
endpoint (~450 entries, fetched once on first use, cached at
~/.cache/steam-dice/tags.json). The genre cache file is replaced by
~/.cache/steam-dice/taxonomy.json, which stores both genres and tags per
appid as {"genres": [...], "tags": [...]}; the old genres.json is left in
place as harmless orphan data. Cache merge logic preserves non-empty
fields per appid so the API-fallback genre fetcher doesn't clobber tags
populated from appinfo.vdf.
Tags are appinfo.vdf-only — Steam's appdetails endpoint doesn't return
store_tags, so there's no API fallback. Without python-steam, the tag
combo stays empty and a tooltip-style dialog explains why.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds genre/category filter dropdown. Reads from Steam's local
appinfo.vdf for instant population, with rate-limited appdetails API
as fallback when local data is unavailable.
_save_genre_cache now reads the on-disk state and merges before writing,
so a concurrent writer can't shrink the cache. Likewise the API thread's
progress/done handlers now `update()` the in-memory cache instead of
replacing it wholesale.
Reachable only in the rare path where both the appinfo loader and the
API fetch thread run in the same session.
Adds a second dropdown next to the install filter that lets the user
narrow rolls to a single Steam genre (RPG, Strategy, etc.).
Genre data is loaded from Steam's local appinfo.vdf cache via
python-steam (instant, no network). If that's unavailable or a game
isn't in the cache, falls back to a rate-limited background fetch of
appdetails?filters=genres, prompted via confirm dialog. Cached at
~/.cache/steam-dice/genres.json across runs.
python-steam declared as optdepends — app degrades gracefully to the
API path if missing.
The icon name "steam-dice" triggers freedesktop's compound-name
fallback: when not found, it strips "-dice" and resolves to the
Steam package's icon. Switch to io.github.silvernode.SteamDice
so the fallback can't collide with anything pre-existing.
Also add .gitignore for makepkg build artifacts and pycache.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- steam-dice.svg: flat dice icon on Steam-blue gradient
- steam-dice.desktop: launcher entry under Game category
- PKGBUILD: steam-dice-git, builds from GitHub source
- Use setDesktopFileName for correct Wayland WM_CLASS, with
local SVG fallback when running from the source tree
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Store API key in system keyring instead of plaintext QSettings
- Migrate away from plaintext api_key on first save
- Redact API key from error messages emitted to the UI
- Validate API key (32 hex chars) and Steam ID (17 digits) before use
- Apply refresh cooldown when settings dialog triggers a fetch
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes hardcoded credentials. Users enter their Steam API key and Steam ID
via a gear-icon settings dialog. Help text in the dialog explains how to
obtain each value with clickable links. Settings persist to
~/.config/butter/steam-dice.conf via QSettings. Dialog auto-opens on first
launch if credentials are not yet configured.
Scans libraryfolders.vdf and all steamapps directories at load time to
build the installed appid set. Dropdown filters the roll pool between
All games, Installed, and Not installed. Re-scans on each library refresh.
Uses steam://rungameid/{appid} with xdg-open to hand off to the local
Steam client. Button appears below the game image after a roll and hides
again when the dice is rolled next.
Adds a view-refresh icon button in the top-right corner to re-fetch the
Steam library. A countdown label appears below it during the cooldown and
hides when the timer expires, preventing API spam.
- Set QT_QPA_PLATFORM=wayland when WAYLAND_DISPLAY is present so the
app runs natively instead of via XWayland
- Show version string (v0.1.0-<git short hash>) in bottom-left corner