Feature: Stock spending report - #996
Open
tbrkkup wants to merge 5 commits into
Open
Conversation
Used by the spending report to render the breakdown as a pie chart. AppDevNext/AndroidChart is the actively maintained fork of MPAndroidChart, whose last release is v3.1.0 from 2019. It is Apache 2.0 and requires minSdk 23, matching this project, and its Kotlin standard library is already on the runtime classpath. It has to come from JitPack, since Maven Central carries only snapshots of it.
Grocy exposes no dedicated price history object, so spending is derived from stock_log filtered to transaction_type=purchase and undone=0 within the selected date range.
Updates products, product groups and stores, reads them back in a single Single.zip(), then fetches the purchase log for the range and sums amount x price per group key. The update keeps group labels from falling back to raw ids when an entity has not been synced by another screen yet; it is not forced, so it stays a cheap no-op once the data is current. Amounts are taken as absolute values so a correction recorded with a negative amount still counts as spend, and entries without a price contribute zero rather than being dropped.
Pie chart over the breakdown plus a sorted list of the same figures. Date range and grouping are picked with filter chips; changing the grouping re-aggregates in memory without another request. The top eight slices are shown individually and the remainder is collapsed into one "Others" slice. Because the library supports only one value text size per data set, the renderer draws the values in two passes so that labels on narrow slices can be smaller and still fit; the formatter blanks out whichever group is not part of the current pass, and the slice geometry stays entirely in the library.
Reachable from the stock overview overflow menu, next to stock journal and stock entries, mirroring where the web UI keeps its stock reports.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #995
Implements the report discussed in the issue.
Commits
Split by layer, so the build change, the query and the UI can be read apart from one another.
Query and arithmetic
Built on the
stock_logsource proposed in the issue:Per row the spend is
|amount| × price. Two details worth confirming against how the web report behaves:amountis taken as an absolute value, so a correction row recorded with a negative amount still registers as spend rather than subtractingfrom the period.
Loading
Products, product groups and stores are updated, then read back in one
Single.zip()before the purchase log is fetched. The update matters because those three resolve the grouping labels: without it, whichever entity no other screen had synced yet would leave raw ids on screen. It is not forced, so it is a cheap no-op once the data is current.Switching the grouping afterwards re-aggregates in memory with no second round trip; only a period change or pull-to-refresh hits the network.
Chart decisions
The top eight slices are shown individually and the remainder is collapsed into a single Others slice; past that the legend stops being readable at phone width. The list below is not truncated, so the full breakdown stays available.
Labels on narrow slices are drawn smaller so they still fit their segment. The library supports only one value text size per data set, so rather than reimplementing the slice geometry, the renderer draws the values in two passes — wide slices at the regular size, narrow ones reduced — with the formatter blanking out whichever group is not part of the current pass. That is the one piece of custom drawing code here and the part I would look at first in review.
Slice colours are a fixed twelve-colour palette rather than theme colours, because adjacent slices have to stay distinguishable from one another. The chart hole, legend text and surrounding chrome do follow the active theme in both light and dark.
For an empty period the chart is hidden and an inline label takes its place. Deliberately not
InfoFullscreenHelper: that helper injects into a container sitting behind the scroll view, which on this screen draws the illustration underneath the filter chips.Dependency
com.github.AppDevNext.AndroidChart:chartLib:5.2.4, which also required adding the JitPack repository tosettings.gradle— Maven Central holds only snapshots of it. This is the only addition to the dependency set.It is Apache 2.0 and needs minSdk 23, both matching this project, and the Kotlin standard library it brings was already on the runtime classpath, so it adds no new runtime.
Formatting
Amounts use the configured
PREF.CURRENCYwith the device locale's decimal separators. English and German strings are included.Testing
Ran on device Pixel 9 Pro running LineageOS 24 against a production server across all three periods and all three groupings, with the resulting figures reconciled line by line against the same report in the web UI. Also covered: a period with no purchases, a dataset with more than eight groups to confirm the Others collapse, and purchases with a missing price and with a null shopping location.