11package ui
22
33import (
4+ "cmp"
45 "context"
56 "fmt"
67 "image/color"
@@ -18,32 +19,38 @@ import (
1819
1920 "github.com/ErikKalkoken/evebuddy/internal/app"
2021 ihumanize "github.com/ErikKalkoken/evebuddy/internal/humanize"
22+ "github.com/ErikKalkoken/evebuddy/internal/xslices"
2123)
2224
2325type wealth struct {
2426 widget.BaseWidget
2527
2628 onUpdate func (wallet , assets float64 )
2729
28- breakdown * coord.CartesianCategoricalChart
29- characters * prop.PieChart
30- top * widget.Label
31- types * prop.PieChart
32- u * baseUI
30+ assetDetail * coord.CartesianCategoricalChart
31+ assetSplit * prop.PieChart
32+ top * widget.Label
33+ u * baseUI
34+ walletDetail * coord.CartesianCategoricalChart
35+ walletSplit * prop.PieChart
3336}
3437
3538func newWealth (u * baseUI ) * wealth {
3639 a := & wealth {
37- breakdown : coord .NewCartesianCategoricalChart ("Wealth Breakdown By Character in B ISK" ),
38- characters : prop .NewPieChart ("Total Wealth By Character in B ISK" ),
39- top : makeTopLabel (),
40- types : prop .NewPieChart ("Total Wealth By Type" ),
41- u : u ,
40+ assetDetail : coord .NewCartesianCategoricalChart ("" ),
41+ assetSplit : prop .NewPieChart ("" ),
42+ top : makeTopLabel (),
43+ u : u ,
44+ walletDetail : coord .NewCartesianCategoricalChart ("" ),
45+ walletSplit : prop .NewPieChart ("" ),
4246 }
4347 a .ExtendBaseWidget (a )
44- a .breakdown .SetTitleStyle (theme .SizeNameSubHeadingText , theme .ColorNameForeground )
45- a .characters .SetTitleStyle (theme .SizeNameSubHeadingText , theme .ColorNameForeground )
46- a .types .SetTitleStyle (theme .SizeNameSubHeadingText , theme .ColorNameForeground )
48+ a .assetDetail .SetTitleStyle (theme .SizeNameSubHeadingText , theme .ColorNameForeground )
49+ a .assetDetail .HideLegend ()
50+ a .assetSplit .SetTitleStyle (theme .SizeNameSubHeadingText , theme .ColorNameForeground )
51+ a .walletSplit .SetTitleStyle (theme .SizeNameSubHeadingText , theme .ColorNameForeground )
52+ a .walletDetail .SetTitleStyle (theme .SizeNameSubHeadingText , theme .ColorNameForeground )
53+ a .walletDetail .HideLegend ()
4754
4855 a .u .characterSectionChanged .AddListener (func (_ context.Context , arg characterSectionUpdated ) {
4956 switch arg .section {
@@ -56,27 +63,20 @@ func newWealth(u *baseUI) *wealth {
5663 a .update ()
5764 }
5865 })
59-
6066 return a
6167}
6268
6369func (a * wealth ) CreateRenderer () fyne.WidgetRenderer {
64- var total * fyne.Container
65- if a .u .isDesktop {
66- total = container .NewGridWithColumns (2 , a .types , a .characters )
67- } else {
68- total = container .NewAdaptiveGrid (2 , a .types , a .characters )
69- }
70- charts := container .NewAppTabs (
71- container .NewTabItem ("Total" , total ),
72- container .NewTabItem ("Breakdown" , a .breakdown ),
73- )
7470 c := container .NewBorder (
7571 a .top ,
7672 nil ,
7773 nil ,
7874 nil ,
79- container .NewScroll (charts ),
75+ container .NewAppTabs (
76+ container .NewTabItem ("Distribution" , container .NewAdaptiveGrid (2 , a .assetSplit , a .walletSplit )),
77+ container .NewTabItem ("Assets" , a .assetDetail ),
78+ container .NewTabItem ("Wallets" , a .walletDetail ),
79+ ),
8080 )
8181 return widget .NewSimpleRenderer (c )
8282}
@@ -101,106 +101,188 @@ func (a *wealth) update() {
101101 return
102102 }
103103
104- colors := newColorWheel ()
105- // type
104+ const maxCharacters = 7
106105 var totalWallet , totalAssets float64
107106 for _ , r := range data {
108107 totalAssets += r .assets
109108 totalWallet += r .wallet
110109 }
111- s1 , err := prop .NewSeries ("Type" , []chartData.ProportionalPoint {{
112- C : "Assets" ,
113- Val : totalAssets ,
114- Col : colors .next (),
115- }, {
116- C : "Wallets" ,
117- Val : totalWallet ,
118- Col : colors .next (),
119- }})
110+ colors := newColorWheel ()
111+
112+ // totals
113+ totalText := ihumanize .Number (totalAssets + totalWallet , 1 )
114+ fyne .Do (func () {
115+ a .top .Text = fmt .Sprintf ("%s ISK total wealth • %d characters" , totalText , characters )
116+ a .top .Importance = widget .MediumImportance
117+ a .top .Refresh ()
118+ })
119+
120+ if a .onUpdate != nil {
121+ a .onUpdate (totalWallet , totalAssets )
122+ }
123+
124+ // total
125+ // s3, err := prop.NewSeries("", []chartData.ProportionalPoint{
126+ // {
127+ // C: "Assets",
128+ // Val: totalAssets,
129+ // Col: colors.next(),
130+ // },
131+ // {
132+ // C: "Wallets",
133+ // Val: totalWallet,
134+ // Col: colors.next(),
135+ // },
136+ // })
137+ // fyne.Do(func() {
138+ // a.total.RemoveSeries("")
139+ // err = a.total.AddSeries(s3)
140+ // if err != nil {
141+ // panic(err)
142+ // }
143+ // a.wallets.SetTitle(fmt.Sprintf("Wealth - Total: %.1f B ISK", totalWallet+totalAssets))
144+ // })
145+
146+ // Asset splits
147+ d1 := xslices .Map (data , func (r dataRow ) chartData.ProportionalPoint {
148+ return chartData.ProportionalPoint {
149+ C : r .label ,
150+ Val : r .assets ,
151+ Col : colors .next (),
152+ }
153+ })
154+ d1 = reduceProportionalPoints (d1 , maxCharacters )
155+ s1 , err := prop .NewSeries ("Characters" , d1 )
120156 if err != nil {
121157 panic (err )
122158 }
123159 fyne .Do (func () {
124- a .types .RemoveSeries ("Type " )
125- err = a .types .AddSeries (s1 )
160+ a .assetSplit .RemoveSeries ("Characters " )
161+ err = a .assetSplit .AddSeries (s1 )
126162 if err != nil {
127163 panic (err )
128164 }
165+ a .assetSplit .SetTitle (fmt .Sprintf ("Assets By Character - Total: %.1f B ISK" , totalAssets ))
129166 })
130167
131- // characters
168+ // Wallet split
132169 colors .reset ()
133- d1 := make ([]chartData.ProportionalPoint , 0 )
134- for _ , r := range data {
135- d1 = append (d1 , chartData.ProportionalPoint {
170+ d2 := xslices .Map (data , func (r dataRow ) chartData.ProportionalPoint {
171+ return chartData.ProportionalPoint {
136172 C : r .label ,
137- Val : r .total ,
173+ Val : r .wallet ,
138174 Col : colors .next (),
139- })
175+ }
176+ })
177+ d2 = reduceProportionalPoints (d2 , maxCharacters )
178+ s2 , err := prop .NewSeries ("Characters" , d2 )
179+ if err != nil {
180+ panic (err )
140181 }
141- s2 , err := prop .NewSeries ("Characters" , d1 )
142182 fyne .Do (func () {
143- a .characters .RemoveSeries ("Characters" )
144- err = a .characters .AddSeries (s2 )
183+ a .walletSplit .RemoveSeries ("Characters" )
184+ err = a .walletSplit .AddSeries (s2 )
145185 if err != nil {
146186 panic (err )
147187 }
188+ a .walletSplit .SetTitle (fmt .Sprintf ("Wallets By Character - Total: %.1f B ISK" , totalWallet ))
148189 })
149190
150- // Breakdown
151- d3 := make ([]chartData. CategoricalPoint , 0 )
152- for _ , r := range data {
153- d3 = append ( d3 , chartData.CategoricalPoint {
191+ // Assets detail
192+ colors . reset ( )
193+ d4 := xslices . Map ( data , func ( r dataRow ) chartData. CategoricalPoint {
194+ return chartData.CategoricalPoint {
154195 C : r .label ,
155196 Val : r .assets ,
156- })
157- }
158- s3 , err := coord .NewCategoricalPointSeries ("Assets" , theme .Color (theme .ColorNameSuccess ), d3 )
197+ }
198+ })
199+ d4 = reduceCategoricalPoints (d4 , maxCharacters )
200+ s4 , err := coord .NewCategoricalPointSeries ("Characters" , colors .next (), d4 )
159201 if err != nil {
160202 panic (err )
161203 }
162- d4 := make ([]chartData.CategoricalPoint , 0 )
163- for _ , r := range data {
164- d4 = append (d4 , chartData.CategoricalPoint {
204+ fyne .Do (func () {
205+ a .assetDetail .RemoveSeries ("Characters" )
206+ err = a .assetDetail .AddBarSeries (s4 )
207+ if err != nil {
208+ panic (err )
209+ }
210+ a .assetDetail .SetTitle (fmt .Sprintf ("Assets By Character - Total: %.1f B ISK" , totalAssets ))
211+ })
212+
213+ // Wallet details
214+ colors .reset ()
215+ d3 := xslices .Map (data , func (r dataRow ) chartData.CategoricalPoint {
216+ return chartData.CategoricalPoint {
165217 C : r .label ,
166218 Val : r .wallet ,
167- })
168- }
169- s4 , err := coord .NewCategoricalPointSeries ("Wallets" , theme .Color (theme .ColorNameError ), d4 )
219+ }
220+ })
221+ d3 = reduceCategoricalPoints (d3 , maxCharacters )
222+ s3 , err := coord .NewCategoricalPointSeries ("Characters" , colors .next (), d3 )
170223 if err != nil {
171224 panic (err )
172225 }
173-
174226 fyne .Do (func () {
175- a .breakdown .RemoveSeries ("Assets" )
176- a .breakdown .RemoveSeries ("Wallets" )
177- err = a .breakdown .AddBarSeries (s3 )
227+ a .walletDetail .RemoveSeries ("Characters" )
228+ err = a .walletDetail .AddBarSeries (s3 )
178229 if err != nil {
179230 panic (err )
180231 }
181- err = a .breakdown .AddBarSeries (s4 )
182- if err != nil {
183- panic (err )
184- }
185- a .breakdown .SetYAxisLabel ("B ISK" )
232+ a .walletDetail .SetTitle (fmt .Sprintf ("Wallets By Character - Total: %.1f B ISK" , totalWallet ))
186233 })
187234
188- var total float64
189- for _ , r := range data {
190- total += r .assets + r .wallet
191- }
192-
193- totalText := ihumanize .Number (total , 1 )
235+ }
194236
195- fyne .Do (func () {
196- a .top .Text = fmt .Sprintf ("%s ISK total wealth • %d characters" , totalText , characters )
197- a .top .Importance = widget .MediumImportance
198- a .top .Refresh ()
237+ func reduceProportionalPoints (data []chartData.ProportionalPoint , m int ) []chartData.ProportionalPoint {
238+ if len (data ) <= m {
239+ return data
240+ }
241+ slices .SortFunc (data , func (a , b chartData.ProportionalPoint ) int {
242+ return cmp .Compare (b .Val , a .Val )
243+ })
244+ others := data [m ].Val
245+ if len (data ) > m {
246+ for _ , x := range data [m + 1 :] {
247+ others += x .Val
248+ }
249+ }
250+ data = data [:m ]
251+ slices .SortFunc (data , func (a , b chartData.ProportionalPoint ) int {
252+ return strings .Compare (a .C , b .C )
199253 })
254+ data = append (data ,
255+ chartData.ProportionalPoint {
256+ C : "Others" ,
257+ Val : others ,
258+ Col : theme .Color (theme .ColorNameDisabled ),
259+ })
260+ return data
261+ }
200262
201- if a .onUpdate != nil {
202- a .onUpdate (totalWallet , totalAssets )
263+ func reduceCategoricalPoints (data []chartData.CategoricalPoint , m int ) []chartData.CategoricalPoint {
264+ if len (data ) <= m {
265+ return data
203266 }
267+ slices .SortFunc (data , func (a , b chartData.CategoricalPoint ) int {
268+ return cmp .Compare (b .Val , a .Val )
269+ })
270+ others := data [m ].Val
271+ if len (data ) > m {
272+ for _ , x := range data [m + 1 :] {
273+ others += x .Val
274+ }
275+ }
276+ data = data [:m ]
277+ slices .SortFunc (data , func (a , b chartData.CategoricalPoint ) int {
278+ return strings .Compare (a .C , b .C )
279+ })
280+ data = append (data ,
281+ chartData.CategoricalPoint {
282+ C : "Others" ,
283+ Val : others ,
284+ })
285+ return data
204286}
205287
206288type dataRow struct {
@@ -270,7 +352,6 @@ func newColorWheel() colorWheel {
270352 theme .Color (colorNameSystem ),
271353 theme .Color (colorNameAttention ),
272354 theme .Color (theme .ColorNamePlaceHolder ),
273- theme .Color (theme .ColorNameDisabled ),
274355 }
275356 return w
276357}
0 commit comments