/
dcrdex_page.go
214 lines (186 loc) · 6.41 KB
/
dcrdex_page.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
package dcrdex
import (
"decred.org/dcrdex/client/core"
"gioui.org/layout"
"gioui.org/widget"
"gioui.org/widget/material"
"github.com/crypto-power/cryptopower/app"
"github.com/crypto-power/cryptopower/libwallet"
"github.com/crypto-power/cryptopower/libwallet/utils"
libutils "github.com/crypto-power/cryptopower/libwallet/utils"
"github.com/crypto-power/cryptopower/ui/cryptomaterial"
"github.com/crypto-power/cryptopower/ui/load"
"github.com/crypto-power/cryptopower/ui/page/components"
"github.com/crypto-power/cryptopower/ui/page/settings"
"github.com/crypto-power/cryptopower/ui/values"
)
const DCRDEXPageID = "DCRDEXPageID"
type (
C = layout.Context
D = layout.Dimensions
)
type DEXPage struct {
*app.MasterPage
*load.Load
switchToTestnetBtn cryptomaterial.Button
openTradeMainPage *cryptomaterial.Clickable
splashPageInfoButton cryptomaterial.IconButton
splashPageContainer *widget.List
startTradingBtn cryptomaterial.Button
showSplashPage bool
dexIsLoading bool
materialLoader material.LoaderStyle
}
func NewDEXPage(l *load.Load) *DEXPage {
dp := &DEXPage{
MasterPage: app.NewMasterPage(DCRDEXPageID),
Load: l,
openTradeMainPage: l.Theme.NewClickable(false),
startTradingBtn: l.Theme.Button(values.String(values.StrStartTrading)),
splashPageContainer: &widget.List{List: layout.List{
Alignment: layout.Middle,
Axis: layout.Vertical,
}},
showSplashPage: true,
switchToTestnetBtn: l.Theme.Button(values.String(values.StrSwitchToTestnet)),
materialLoader: material.Loader(l.Theme.Base),
}
if dp.AssetsManager.DEXCInitialized() && dp.AssetsManager.DexClient().InitializedWithPassword() {
dp.showSplashPage = false
}
// Init splash page more info widget.
_, dp.splashPageInfoButton = components.SubpageHeaderButtons(l)
return dp
}
// ID is a unique string that identifies the page and may be used to
// differentiate this page from other pages.
// Part of the load.Page interface.
func (pg *DEXPage) ID() string {
return DCRDEXPageID
}
// OnNavigatedTo is called when the page is about to be displayed and may be
// used to initialize page features that are only relevant when the page is
// displayed.
// Part of the load.Page interface.
func (pg *DEXPage) OnNavigatedTo() {
if !pg.AssetsManager.DEXCInitialized() {
return
}
if pg.CurrentPage() != nil {
pg.CurrentPage().OnNavigatedTo()
} else {
pg.prepareInitialPage()
}
}
// prepareInitialPage starts a goroutine that waits for dexc to get ready before
// displaying an appropriate page.
func (pg *DEXPage) prepareInitialPage() {
dexClient := pg.AssetsManager.DexClient()
if dexClient == nil {
return
}
pg.dexIsLoading = true
go func() {
<-dexClient.Ready()
showOnBoardingPage := true
if len(dexClient.Exchanges()) != 0 { // has at least one exchange
_, _, pendingBond := pendingBondConfirmation(pg.AssetsManager, "")
showOnBoardingPage = pendingBond != nil
}
if showOnBoardingPage {
pg.Display(NewDEXOnboarding(pg.Load, ""))
} else {
pg.Display(NewDEXMarketPage(pg.Load, ""))
}
pg.dexIsLoading = false
pg.showSplashPage = false
}()
}
// Layout draws the page UI components into the provided layout context to be
// eventually drawn on screen.
// Part of the load.Page interface.
func (pg *DEXPage) Layout(gtx C) D {
isMainnet := pg.AssetsManager.NetType() == utils.Mainnet
if !isMainnet && (!pg.AssetsManager.DEXCInitialized() || pg.CurrentPage() == nil) { // dexc must have been reset.
pg.showSplashPage = true
if !pg.dexIsLoading {
pg.ParentNavigator().CloseAllPages()
pg.prepareInitialPage()
}
}
if pg.showSplashPage || pg.dexIsLoading {
return pg.Theme.List(pg.splashPageContainer).Layout(gtx, 1, func(gtx C, i int) D {
return pg.splashPage(gtx)
})
}
var msg string
var actionBtn *cryptomaterial.Button
if isMainnet {
if pg.CanChangeNetworkType() {
actionBtn = &pg.switchToTestnetBtn
}
msg = values.String(values.StrDexMainnetNotReady)
} else if hasMultipleWallets := pg.isMultipleAssetTypeWalletAvailable(); !hasMultipleWallets {
msg = values.String(values.StrMultipleAssetRequiredMsg)
}
if msg != "" {
return components.DisablePageWithOverlay(pg.Load, nil, gtx, msg, "", actionBtn)
}
return pg.CurrentPage().Layout(gtx)
}
// isMultipleAssetTypeWalletAvailable checks if wallets exist for more than 1
// asset type. If not, dex functionality is disable till different asset type
// wallets are created.
func (pg *DEXPage) isMultipleAssetTypeWalletAvailable() bool {
allWallets := pg.AssetsManager.AllWallets()
assetTypes := make(map[libutils.AssetType]bool)
for _, wallet := range allWallets {
assetTypes[wallet.GetAssetType()] = true
if len(assetTypes) > 1 {
return true
}
}
return false
}
// HandleUserInteractions is called just before Layout() to determine if any
// user interaction recently occurred on the page and may be used to update the
// page's UI components shortly before they are displayed.
// Part of the load.Page interface.
func (pg *DEXPage) HandleUserInteractions() {
if pg.switchToTestnetBtn.Button.Clicked() {
settings.ChangeNetworkType(pg.Load, pg.ParentWindow(), string(libutils.Testnet))
}
if pg.CurrentPage() != nil {
pg.CurrentPage().HandleUserInteractions()
}
if pg.splashPageInfoButton.Button.Clicked() {
pg.showInfoModal()
}
if pg.startTradingBtn.Button.Clicked() {
pg.showSplashPage = false
}
}
// OnNavigatedFrom is called when the page is about to be removed from the
// displayed window. This method should ideally be used to disable features that
// are irrelevant when the page is NOT displayed.
// NOTE: The page may be re-displayed on the app's window, in which case
// OnNavigatedTo() will be called again. This method should not destroy UI
// components unless they'll be recreated in the OnNavigatedTo() method.
// Part of the load.Page interface.
func (pg *DEXPage) OnNavigatedFrom() {}
// pendingBondConfirmation is a convenience function based on arbitrary
// heuristics to determine when to show bond confirmation step.
func pendingBondConfirmation(am *libwallet.AssetsManager, host string) (string, *core.BondAsset, *core.PendingBondState) {
for _, xc := range am.DexClient().Exchanges() {
if (host != "" && xc.Host != host) || len(xc.Auth.PendingBonds) == 0 {
continue
}
for _, bond := range xc.Auth.PendingBonds {
bondAsset := xc.BondAssets[bond.Symbol]
if bond.Confs < bondAsset.Confs {
return xc.Host, bondAsset, bond
}
}
}
return "", nil, nil
}