From 93882cedca30a60f3e5e60d9f6ba18abbc2d1659 Mon Sep 17 00:00:00 2001 From: Philemon Ukane Date: Thu, 2 Nov 2023 19:11:18 +0100 Subject: [PATCH] review changes Signed-off-by: Philemon Ukane --- ui/cryptomaterial/dropdown.go | 142 ++++++++------ ui/cryptomaterial/segmented_control.go | 20 +- ui/page/dcrdex/dcrdex_page.go | 26 ++- ui/page/dcrdex/dex_onboarding_page.go | 5 +- ui/page/dcrdex/market.go | 245 +++++++++++++++---------- ui/values/localizable/en.go | 2 + ui/values/strings.go | 2 + 7 files changed, 263 insertions(+), 179 deletions(-) diff --git a/ui/cryptomaterial/dropdown.go b/ui/cryptomaterial/dropdown.go index 656886ce3..234b1fc8d 100644 --- a/ui/cryptomaterial/dropdown.go +++ b/ui/cryptomaterial/dropdown.go @@ -24,8 +24,6 @@ type DropDown struct { Position uint revs bool selectedIndex int - Color color.NRGBA - background color.NRGBA dropdownIcon *widget.Icon navigationIcon *widget.Icon clickable *Clickable @@ -38,12 +36,16 @@ type DropDown struct { padding layout.Inset shadow *Shadow - extraDisplay func(gtx C) D - FontWeight font.Weight - BorderWidth unit.Dp - BorderColor *color.NRGBA - NavigationIconColor *color.NRGBA - Hoverable bool + extraDisplay func(gtx C) D + FontWeight font.Weight + BorderWidth unit.Dp + BorderColor *color.NRGBA + Background *color.NRGBA + SelectedItemIconColor *color.NRGBA + MakeSelectedItemHoverable bool + SelectedItemDirection layout.Direction + Stack bool + OpenedLayoutInset *layout.Inset } type DropDownItem struct { @@ -65,8 +67,6 @@ func (t *Theme) DropDown(items []DropDownItem, group uint, pos uint) *DropDown { isOpen: false, Position: pos, selectedIndex: 0, - Color: t.Color.Gray2, - background: t.Color.Surface, dropdownIcon: t.dropDownIcon, navigationIcon: t.navigationCheckIcon, clickable: t.NewClickable(true), @@ -80,8 +80,9 @@ func (t *Theme) DropDown(items []DropDownItem, group uint, pos uint) *DropDown { Height: WrapContent, Border: Border{Radius: Radius(8)}, }, - padding: layout.Inset{Top: values.MarginPadding8, Bottom: values.MarginPadding8}, - shadow: t.Shadow(), + padding: layout.Inset{Top: values.MarginPadding8, Bottom: values.MarginPadding8}, + shadow: t.Shadow(), + SelectedItemDirection: layout.W, } d.clickable.ChangeStyle(t.Styles.DropdownClickableStyle) @@ -154,22 +155,21 @@ func (d *DropDown) layoutActiveIcon(gtx C, index int) D { var icon *Icon if !d.isOpen { icon = NewIcon(d.dropdownIcon) - icon.Color = d.theme.Color.Gray1 } else if index == d.selectedIndex { icon = NewIcon(d.navigationIcon) - if d.NavigationIconColor != nil { - icon.Color = *d.NavigationIconColor - } else { - icon.Color = d.theme.Color.Gray1 - } } - return layout.E.Layout(gtx, func(gtx C) D { - if icon == nil { - return D{} - } - return icon.Layout(gtx, values.MarginPadding20) - }) + if icon == nil { + return D{} // return early + } + + if !d.isOpen || d.SelectedItemIconColor == nil { + icon.Color = d.theme.Color.Gray1 + } else { + icon.Color = *d.SelectedItemIconColor + } + + return icon.Layout(gtx, values.MarginPadding20) } func (d *DropDown) layoutOption(gtx C, itemIndex int) D { @@ -179,7 +179,7 @@ func (d *DropDown) layoutOption(gtx C, itemIndex int) D { if !d.isOpen { radius = Radius(8) clickable = d.clickable - clickable.Hoverable = d.Hoverable + clickable.Hoverable = d.MakeSelectedItemHoverable } padding := values.MarginPadding10 @@ -187,14 +187,8 @@ func (d *DropDown) layoutOption(gtx C, itemIndex int) D { padding = values.MarginPadding8 } - dropdownWidth := gtx.Dp(d.Width) - dropdownItemWidth := dropdownWidth - if dropdownWidth <= 0 { - dropdownWidth = gtx.Dp(defaultDropdownWidth(d.revs)) - } - return LinearLayout{ - Width: dropdownWidth, + Width: MatchParent, Height: WrapContent, Clickable: clickable, Padding: layout.UniformInset(padding), @@ -205,20 +199,25 @@ func (d *DropDown) layoutOption(gtx C, itemIndex int) D { return D{} } - dropdownItemWidth -= gtx.Dp(values.MarginPadding24) // account for the dropdown Icon return item.Icon.Layout24dp(gtx) }), - layout.Rigid(func(gtx C) D { - gtx.Constraints.Max.X = dropdownItemWidth - gtx.Dp(values.MarginPadding50) // give some space for the dropdown Icon - gtx.Constraints.Min.X = gtx.Constraints.Max.X - if item.DisplayFn != nil { - return item.DisplayFn(gtx) + layout.Flexed(1, func(gtx C) D { + ll := LinearLayout{ + Width: MatchParent, + Height: WrapContent, + Padding: layout.Inset{Right: values.MarginPadding5}, + Direction: layout.W, } - return layout.Inset{ - Right: unit.Dp(5), - Left: unit.Dp(5), - }.Layout(gtx, func(gtx C) D { + if !d.isOpen { + ll.Direction = d.SelectedItemDirection + } + + return ll.Layout2(gtx, func(gtx C) D { + if item.DisplayFn != nil { + return item.DisplayFn(gtx) + } + lbl := d.theme.Body2(item.Text) if !d.isOpen && len(item.Text) > 20 { lbl.Text = item.Text[:20-3] + "..." @@ -255,6 +254,37 @@ func (d *DropDown) Layout(gtx C, dropPos int, reversePos bool) D { iRight = dropPos } + if d.OpenedLayoutInset == nil { + d.OpenedLayoutInset = &layout.Inset{ + Left: unit.Dp(float32(iLeft)), + Right: unit.Dp(float32(iRight)), + } + } + + if d.Stack { + isOpen := d.isOpen + return layout.Stack{Alignment: alig}.Layout(gtx, + layout.Expanded(func(gtx layout.Context) layout.Dimensions { + d.isOpen = false + display := d.closedLayout(gtx, iLeft, iRight) + d.isOpen = isOpen + return display + }), + layout.Stacked(func(gtx layout.Context) layout.Dimensions { + maxY := unit.Dp(len(d.items))*values.MarginPadding50 + d.OpenedLayoutInset.Top + if d.extraDisplay != nil { + maxY += values.MarginPadding50 + } + + gtx.Constraints.Max.Y = gtx.Dp(maxY) + if !d.isOpen { + return D{} + } + return d.openedLayout(gtx, iLeft, iRight) + }), + ) + } + if d.Position == DropdownBasePos && d.isOpenDropdownGroup(d.group) { maxY := unit.Dp(len(d.items)) * values.MarginPadding50 if d.extraDisplay != nil { @@ -297,10 +327,8 @@ func (d *DropDown) Layout(gtx C, dropPos int, reversePos bool) D { // openedLayout computes dropdown layout when dropdown is opened. func (d *DropDown) openedLayout(gtx C, iLeft int, iRight int) D { - return layout.Inset{ - Left: unit.Dp(float32(iLeft)), - Right: unit.Dp(float32(iRight)), - }.Layout(gtx, func(gtx C) D { + inset := *d.OpenedLayoutInset + return inset.Layout(gtx, func(gtx C) D { return d.dropDownItemMenu(gtx) }) } @@ -322,9 +350,6 @@ func (d *DropDown) closedLayout(gtx C, iLeft int, iRight int) D { } return d.layoutOption(gtx, d.selectedIndex) })) - if d.Width <= 0 { - d.Width = defaultDropdownWidth(d.revs) - } return lay }) }) @@ -341,12 +366,6 @@ func (d *DropDown) dropDownItemMenu(gtx C) D { return d.layoutOption(gtx, index) }), layout.Rigid(func(gtx layout.Context) layout.Dimensions { - dropdownWidth := gtx.Dp(d.Width) - if dropdownWidth <= 0 { - dropdownWidth = gtx.Dp(defaultDropdownWidth(d.revs)) - } - - gtx.Constraints.Max.X = dropdownWidth return d.extraDisplay(gtx) }), ) @@ -361,16 +380,25 @@ func (d *DropDown) dropDownItemMenu(gtx C) D { // drawLayout wraps the page tx and sync section in a card layout func (d *DropDown) drawLayout(gtx C, body layout.Widget) D { + if d.Width <= 0 { + d.Width = defaultDropdownWidth(d.revs) + } + d.linearLayout.Width = gtx.Dp(d.Width) + if d.isOpen { - d.linearLayout.Background = d.background + d.linearLayout.Background = d.theme.Color.Surface d.linearLayout.Padding = d.padding d.linearLayout.Shadow = d.shadow } else { - d.linearLayout.Background = d.Color + d.linearLayout.Background = d.theme.Color.Gray2 d.linearLayout.Padding = layout.Inset{} d.linearLayout.Shadow = nil } + if d.Background != nil { + d.linearLayout.Background = *d.Background + } + if d.BorderWidth > 0 { d.linearLayout.Border.Width = d.BorderWidth } diff --git a/ui/cryptomaterial/segmented_control.go b/ui/cryptomaterial/segmented_control.go index 39f2403e0..e674c162e 100644 --- a/ui/cryptomaterial/segmented_control.go +++ b/ui/cryptomaterial/segmented_control.go @@ -16,6 +16,8 @@ type SegmentedControl struct { leftNavBtn, rightNavBtn *Clickable + Padding *layout.Inset + selectedIndex int segmentTitles []string @@ -57,14 +59,20 @@ func (sc *SegmentedControl) Layout(gtx C) D { txt.Color = sc.theme.Color.Text border = Border{Radius: Radius(8)} } - return LinearLayout{ + + ll := LinearLayout{ Width: WrapContent, Height: WrapContent, - Padding: layout.UniformInset(values.MarginPadding8), Background: bg, Margin: layout.UniformInset(values.MarginPadding5), Border: border, - }.Layout2(gtx, txt.Layout) + } + if sc.Padding != nil { + ll.Padding = *sc.Padding + } else { + ll.Padding = layout.UniformInset(values.MarginPadding8) + } + return ll.Layout2(gtx, txt.Layout) }) }) }), @@ -166,11 +174,11 @@ func (sc *SegmentedControl) Changed() bool { return changed } -func (sc *SegmentedControl) SelectedSegmentAtIndex(index int) { +func (sc *SegmentedControl) SetSelectedSegment(segment string) { sc.mu.Lock() defer sc.mu.Unlock() - for i := range sc.segmentTitles { - if i == index { + for i, item := range sc.segmentTitles { + if item == segment { sc.selectedIndex = i break } diff --git a/ui/page/dcrdex/dcrdex_page.go b/ui/page/dcrdex/dcrdex_page.go index 4ec1d415e..4011dd49b 100644 --- a/ui/page/dcrdex/dcrdex_page.go +++ b/ui/page/dcrdex/dcrdex_page.go @@ -34,6 +34,7 @@ func NewDEXPage(l *load.Load) *DEXPage { MasterPage: app.NewMasterPage(DCRDEXID), openTradeMainPage: l.Theme.NewClickable(false), } + // TODO: Setdp.inited dp.inited = true return dp } @@ -51,13 +52,12 @@ func (pg *DEXPage) ID() string { // Part of the load.Page interface. func (pg *DEXPage) OnNavigatedTo() { pg.ctx, pg.ctxCancel = context.WithCancel(context.TODO()) - // TODO: set pg.inited - if !pg.inited { - pg.Display(NewDEXOnboarding(pg.Load)) - } else if pg.CurrentPage() == nil { + if pg.CurrentPage() != nil { + pg.CurrentPage().OnNavigatedTo() + } else if pg.inited { pg.Display(NewDEXMarketPage(pg.Load)) } else { - pg.CurrentPage().OnNavigatedTo() + pg.Display(NewDEXOnboarding(pg.Load)) } } @@ -65,16 +65,12 @@ func (pg *DEXPage) OnNavigatedTo() { // eventually drawn on screen. // Part of the load.Page interface. func (pg *DEXPage) Layout(gtx C) D { - return layout.Stack{}.Layout(gtx, - layout.Expanded(func(gtx C) D { - return cryptomaterial.LinearLayout{ - Width: cryptomaterial.MatchParent, - Height: cryptomaterial.MatchParent, - Orientation: layout.Vertical, - }.Layout(gtx, - layout.Flexed(1, pg.CurrentPage().Layout), - ) - }), + return cryptomaterial.LinearLayout{ + Width: cryptomaterial.MatchParent, + Height: cryptomaterial.MatchParent, + Orientation: layout.Vertical, + }.Layout(gtx, + layout.Flexed(1, pg.CurrentPage().Layout), ) } diff --git a/ui/page/dcrdex/dex_onboarding_page.go b/ui/page/dcrdex/dex_onboarding_page.go index adc1f4ca8..741c87d31 100644 --- a/ui/page/dcrdex/dex_onboarding_page.go +++ b/ui/page/dcrdex/dex_onboarding_page.go @@ -194,9 +194,8 @@ func (pg *DEXOnboarding) Layout(gtx C) D { Orientation: layout.Vertical, Background: pg.Theme.Color.Surface, Margin: layout.Inset{ - Bottom: values.MarginPadding50, - Right: u20, - Left: u20, + Right: u20, + Left: u20, }, Border: cryptomaterial.Border{ Radius: cryptomaterial.Radius(r), diff --git a/ui/page/dcrdex/market.go b/ui/page/dcrdex/market.go index 9cd8ac6f4..9b934b69c 100644 --- a/ui/page/dcrdex/market.go +++ b/ui/page/dcrdex/market.go @@ -27,8 +27,9 @@ const ( var ( u5 = values.MarginPadding5 + u8 = values.MarginPadding8 u300 = unit.Dp(300) - orderFormAndOrderBookWidth = (values.AppWidth / 2) - 30 + orderFormAndOrderBookWidth = (values.AppWidth / 2) - 40 orderFormAndOrderBookHeight = unit.Dp(515) limitOrderIndex = 0 @@ -50,10 +51,9 @@ type DEXMarketPage struct { // and the root WindowNavigator. *app.GenericPageModal - scrollContainer *widget.List - pageContainer layout.List - openOrdersContainer *widget.List - tradeHistoryContainer *widget.List + scrollContainer *widget.List + pageContainer layout.List + ordersContainer *widget.List serverSelector *cryptomaterial.DropDown addServerBtn *cryptomaterial.Clickable @@ -76,7 +76,11 @@ type DEXMarketPage struct { immediateOrder cryptomaterial.CheckBoxStyle immediateMoreInfo *cryptomaterial.Clickable - toggleOpenAndHistoryOrderBtn *cryptomaterial.SegmentedControl + openOrdersBtn cryptomaterial.Button + orderHistoryBtn cryptomaterial.Button + openOrdersDisplayed bool + + ordersTableHorizontalScroll *widget.List showLoader bool } @@ -89,34 +93,41 @@ func NewDEXMarketPage(l *load.Load) *DEXMarketPage { Axis: layout.Vertical, Alignment: layout.Middle, }, - openOrdersContainer: &widget.List{List: layout.List{Axis: layout.Vertical, Alignment: layout.Middle}}, - tradeHistoryContainer: &widget.List{List: layout.List{Axis: layout.Vertical, Alignment: layout.Middle}}, - GenericPageModal: app.NewGenericPageModal(DEXAccountOnboardingID), - scrollContainer: &widget.List{List: layout.List{Axis: layout.Vertical, Alignment: layout.Middle}}, - priceEditor: newTextEditor(l.Theme, values.String(values.StrPrice), "0", false), - totalEditor: newTextEditor(th, values.String(values.StrTotal), "", false), - switchLotsOrAmount: l.Theme.Switch(), // TODO: Set last user choice, default is unchecked. - lotsAmountEditor: newTextEditor(l.Theme, values.String(values.StrLots), "0", false), - createOrderBtn: th.Button(values.String(values.StrBuy)), // TODO: toggle - buyOrder: true, - immediateOrder: th.CheckBox(new(widget.Bool), values.String(values.StrImmediate)), - orderTypesDropdown: th.DropDown(orderTypes, values.DEXOrderTypes, 0), - immediateMoreInfo: th.NewClickable(false), - addServerBtn: th.NewClickable(false), - seeFullOrderBookBtn: th.Button(values.String(values.StrSeeMore)), - toggleBuyAndSellBtn: th.SegmentedControl([]string{values.String(values.StrBuy), values.String(values.StrSell)}), - toggleOpenAndHistoryOrderBtn: th.SegmentedControl([]string{values.String(values.StrOpenOrders), values.String(values.StrTradeHistory)}), + ordersContainer: &widget.List{List: layout.List{Axis: layout.Vertical, Alignment: layout.Middle}}, + GenericPageModal: app.NewGenericPageModal(DEXAccountOnboardingID), + scrollContainer: &widget.List{List: layout.List{Axis: layout.Vertical, Alignment: layout.Middle}}, + priceEditor: newTextEditor(l.Theme, values.String(values.StrPrice), "0", false), + totalEditor: newTextEditor(th, values.String(values.StrTotal), "", false), + switchLotsOrAmount: l.Theme.Switch(), // TODO: Set last user choice, default is unchecked. + lotsAmountEditor: newTextEditor(l.Theme, values.String(values.StrLots), "0", false), + createOrderBtn: th.Button(values.String(values.StrBuy)), // TODO: toggle + buyOrder: true, + immediateOrder: th.CheckBox(new(widget.Bool), values.String(values.StrImmediate)), + orderTypesDropdown: th.DropDown(orderTypes, values.DEXOrderTypes, 0), + immediateMoreInfo: th.NewClickable(false), + addServerBtn: th.NewClickable(false), + seeFullOrderBookBtn: th.Button(values.String(values.StrSeeMore)), + toggleBuyAndSellBtn: th.SegmentedControl([]string{values.String(values.StrBuy), values.String(values.StrSell)}), + openOrdersBtn: th.Button(values.String(values.StrOpenOrders)), + orderHistoryBtn: th.Button(values.String(values.StrTradeHistory)), + openOrdersDisplayed: true, + ordersTableHorizontalScroll: &widget.List{List: layout.List{Axis: layout.Horizontal, Alignment: layout.Middle}}, } + btnPadding := layout.Inset{Top: u8, Right: u20, Left: u20, Bottom: u8} + pg.toggleBuyAndSellBtn.Padding = &btnPadding + pg.openOrdersBtn.Inset, pg.orderHistoryBtn.Inset = btnPadding, btnPadding + pg.openOrdersBtn.Font.Weight, pg.orderHistoryBtn.Font.Weight = font.SemiBold, font.SemiBold + + pg.orderTypesDropdown.SelectedItemDirection = layout.E pg.orderTypesDropdown.Width = values.MarginPadding120 - pg.orderTypesDropdown.Color = pg.Theme.Color.Surface pg.orderTypesDropdown.FontWeight = font.SemiBold - pg.orderTypesDropdown.Hoverable = false - pg.orderTypesDropdown.NavigationIconColor = &pg.Theme.Color.Primary + pg.orderTypesDropdown.MakeSelectedItemHoverable = false + pg.orderTypesDropdown.SelectedItemIconColor = &pg.Theme.Color.Primary + pg.orderTypesDropdown.OpenedLayoutInset = &layout.Inset{Top: values.MarginPadding30} + pg.orderTypesDropdown.Stack = true - pg.priceEditor.IsTitleLabel = false - pg.lotsAmountEditor.IsTitleLabel = false - pg.totalEditor.IsTitleLabel = false + pg.priceEditor.IsTitleLabel, pg.lotsAmountEditor.IsTitleLabel, pg.totalEditor.IsTitleLabel = false, false, false pg.seeFullOrderBookBtn.HighlightColor, pg.seeFullOrderBookBtn.Background = color.NRGBA{}, color.NRGBA{} pg.seeFullOrderBookBtn.Color = th.Color.Primary @@ -157,20 +168,20 @@ func (pg *DEXMarketPage) OnNavigatedTo() { Text: "DCR/LTC", DisplayFn: pg.marketDropdownListItem(libutils.DCRWalletAsset, libutils.LTCWalletAsset), }, + { + Text: "LTC/BTC", + DisplayFn: pg.marketDropdownListItem(libutils.LTCWalletAsset, libutils.BTCWalletAsset), + }, }, values.DEXCurrencyPairGroup, 0) - pg.serverSelector.Color = pg.Theme.Color.Surface - pg.serverSelector.BorderWidth = values.MarginPadding2 - pg.serverSelector.BorderColor = &pg.Theme.Color.Gray5 - pg.serverSelector.NavigationIconColor = &pg.Theme.Color.Primary - - pg.marketSelector.Color = pg.Theme.Color.Surface - pg.marketSelector.BorderWidth = values.MarginPadding2 - pg.marketSelector.BorderColor = &pg.Theme.Color.Gray5 - pg.marketSelector.NavigationIconColor = &pg.Theme.Color.Primary - - pg.serverSelector.Hoverable, pg.marketSelector.Hoverable = false, false pg.serverSelector.Width, pg.marketSelector.Width = u300, u300 + pg.serverSelector.Stack, pg.marketSelector.Stack = true, true + pg.serverSelector.BorderWidth, pg.marketSelector.BorderWidth = u2, u2 + pg.serverSelector.MakeSelectedItemHoverable, pg.marketSelector.MakeSelectedItemHoverable = false, false + pg.serverSelector.SelectedItemIconColor, pg.marketSelector.SelectedItemIconColor = &pg.Theme.Color.Primary, &pg.Theme.Color.Primary + + inset := &layout.Inset{Top: 45} + pg.serverSelector.OpenedLayoutInset, pg.marketSelector.OpenedLayoutInset = inset, inset // TODO: Fetch orders or order history. } @@ -264,10 +275,9 @@ func (pg *DEXMarketPage) pageContentLayout(gtx C) D { Width: cryptomaterial.MatchParent, Height: cryptomaterial.MatchParent, Direction: layout.Center, - Padding: layout.UniformInset(values.MarginPadding20), }.Layout2(gtx, func(gtx C) D { return cryptomaterial.LinearLayout{ - Width: gtx.Dp(values.AppWidth - 40), + Width: gtx.Dp(values.AppWidth - 50), Height: cryptomaterial.MatchParent, Margin: layout.Inset{ Bottom: values.MarginPadding30, @@ -284,7 +294,7 @@ func (pg *DEXMarketPage) pageContentLayout(gtx C) D { }) }) }), - layout.Expanded(pg.serverAndCurrencySelection()), + layout.Stacked(pg.serverAndCurrencySelection()), ) }) }) @@ -305,9 +315,8 @@ func (pg DEXMarketPage) addServerDisplay() func(gtx C) D { Width: cryptomaterial.MatchParent, Height: cryptomaterial.WrapContent, Orientation: layout.Horizontal, - Padding: layout.UniformInset(u10), + Padding: layout.Inset{Top: u10, Bottom: u5, Left: values.MarginPadding8}, Direction: layout.W, - Alignment: layout.Middle, Clickable: pg.addServerBtn, }.Layout(gtx, layout.Rigid(func(gtx C) D { @@ -344,13 +353,11 @@ func (pg *DEXMarketPage) serverAndCurrencySelection() func(gtx C) D { return pg.semiBoldLabelText(gtx, values.String(values.StrServer)) }), layout.Rigid(func(gtx C) D { - return layout.Stack{}.Layout(gtx, - layout.Expanded(func(gtx C) D { - return layout.Inset{Top: u2}.Layout(gtx, func(gtx C) D { - return pg.serverSelector.Layout(gtx, 0, false) - }) - }), - ) + return layout.Inset{Top: u2}.Layout(gtx, func(gtx C) D { + pg.serverSelector.Background = &pg.Theme.Color.Surface + pg.serverSelector.BorderColor = &pg.Theme.Color.Gray5 + return pg.serverSelector.Layout(gtx, 0, false) + }) }), ) }), @@ -362,6 +369,8 @@ func (pg *DEXMarketPage) serverAndCurrencySelection() func(gtx C) D { }), layout.Rigid(func(gtx C) D { return layout.Inset{Top: u2}.Layout(gtx, func(gtx C) D { + pg.marketSelector.Background = &pg.Theme.Color.Surface + pg.marketSelector.BorderColor = &pg.Theme.Color.Gray5 return pg.marketSelector.Layout(gtx, 0, false) }) }), @@ -650,7 +659,8 @@ func (pg *DEXMarketPage) orderForm() func(gtx C) D { return pg.toggleBuyAndSellBtn.Layout(gtx) }), layout.Flexed(1, func(gtx C) D { - return layout.Inset{Bottom: u10, Top: u10}.Layout(gtx, func(gtx C) D { + return layout.Inset{Bottom: u5, Top: u5}.Layout(gtx, func(gtx C) D { + pg.orderTypesDropdown.Background = &pg.Theme.Color.Surface return pg.orderTypesDropdown.Layout(gtx, 0, true) }) }), @@ -789,14 +799,16 @@ type order struct { filled float64 settled float64 epoch uint64 + status string } func (pg *DEXMarketPage) openOrdersAndHistory(gtx C) D { - sectionWidth := values.AppWidth - values.MarginPadding80 - columnWidth := sectionWidth / 7 + headers := []string{values.String(values.StrType), values.String(values.StrPair), values.String(values.StrAge), values.StringF(values.StrAssetPrice, "BTC"), values.StringF(values.StrAssetAmount, "DCR"), values.String(values.StrFilled), values.String(values.StrSettled), values.String(values.StrStatus)} + + sectionWidth := values.AppWidth + columnWidth := sectionWidth / unit.Dp(len(headers)) sepWidth := sectionWidth - values.MarginPadding60 - headers := []string{values.String(values.StrType), values.String(values.StrPair), values.String(values.StrAge), values.StringF(values.StrAssetPrice, "BTC"), values.StringF(values.StrAssetAmount, "DCR"), values.String(values.StrFilled), values.String(values.StrSettled)} // TODO: Use real values var headersFn []layout.FlexChild for _, header := range headers { @@ -815,6 +827,7 @@ func (pg *DEXMarketPage) openOrdersAndHistory(gtx C) D { amount: 23.00457, filled: 100.0, settled: 70.5, + status: "booked", } orders = append(orders, ord) @@ -832,53 +845,79 @@ func (pg *DEXMarketPage) openOrdersAndHistory(gtx C) D { Orientation: layout.Vertical, }.Layout(gtx, layout.Rigid(func(gtx C) D { - return layout.Inset{Left: u2}.Layout(gtx, pg.toggleOpenAndHistoryOrderBtn.Layout) - }), - layout.Rigid(func(gtx C) D { - return layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceBetween, Alignment: layout.Middle}.Layout(gtx, headersFn...) - }), - layout.Rigid(func(gtx C) D { - if len(orders) == 0 { - selectedItem := pg.toggleOpenAndHistoryOrderBtn.SelectedIndex() - var noOrderMsg string - if selectedItem == 0 { // TODO: Fetch open orders - noOrderMsg = values.String(values.StrNoOpenOrdersMsg) - } else if selectedItem == 1 { // TODO: Fetch History orders - noOrderMsg = values.String(values.StrNoTradeHistoryMsg) - } - return components.LayoutNoOrderHistoryWithMsg(gtx, pg.Load, false, noOrderMsg) + gr2 := pg.Theme.Color.Gray2 + pg.openOrdersBtn.HighlightColor, pg.orderHistoryBtn.HighlightColor = gr2, gr2 + if pg.openOrdersDisplayed { + pg.openOrdersBtn.Background = gr2 + pg.openOrdersBtn.Color = pg.Theme.Color.GrayText1 + pg.orderHistoryBtn.Background = pg.Theme.Color.SurfaceHighlight + pg.orderHistoryBtn.Color = pg.Theme.Color.Text + } else { + pg.openOrdersBtn.Background = pg.Theme.Color.SurfaceHighlight + pg.openOrdersBtn.Color = pg.Theme.Color.Text + pg.orderHistoryBtn.Background = gr2 + pg.orderHistoryBtn.Color = pg.Theme.Color.GrayText1 } - - return pg.Theme.List(pg.openOrdersContainer).Layout(gtx, len(orders), func(gtx C, index int) D { - ord := orders[index] - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - layout.Rigid(func(gtx C) D { - if index == 0 { - sep := pg.Theme.Separator() - sep.Width = gtx.Dp(sepWidth) - return layout.Center.Layout(gtx, sep.Layout) - } - return D{} - }), + return layout.Flex{Axis: layout.Horizontal}.Layout(gtx, + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return layout.Inset{Left: u5, Right: u10}.Layout(gtx, pg.openOrdersBtn.Layout) + }), + layout.Rigid(pg.orderHistoryBtn.Layout), + ) + }), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return pg.Theme.List(pg.ordersTableHorizontalScroll).Layout(gtx, 1, func(gtx layout.Context, index int) layout.Dimensions { + gtx.Constraints.Max.X = gtx.Dp(sectionWidth) + gtx.Constraints.Min.X = gtx.Constraints.Max.X + return layout.Flex{Axis: layout.Vertical, Alignment: layout.Middle}.Layout(gtx, layout.Rigid(func(gtx C) D { - return layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceBetween, Alignment: layout.Middle}.Layout(gtx, - pg.orderColumn(false, ord.ordType, columnWidth), - pg.orderColumn(false, ord.market, columnWidth), - pg.orderColumn(false, ord.age, columnWidth), - pg.orderColumn(false, pg.Printer.Sprintf("%f", ord.price), columnWidth), - pg.orderColumn(false, pg.Printer.Sprintf("%f", ord.amount), columnWidth), - pg.orderColumn(false, pg.Printer.Sprintf("%.1f", ord.filled), columnWidth), - pg.orderColumn(false, pg.Printer.Sprintf("%.1f", ord.price), columnWidth), - ) + return layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceBetween, Alignment: layout.Middle}.Layout(gtx, headersFn...) }), layout.Rigid(func(gtx C) D { - // No divider for last row - if index == len(orders)-1 { - return D{} + if len(orders) == 0 { + var noOrderMsg string + if pg.openOrdersDisplayed { // TODO: Fetch open orders + noOrderMsg = values.String(values.StrNoOpenOrdersMsg) + } else { // TODO: Fetch History orders + noOrderMsg = values.String(values.StrNoTradeHistoryMsg) + } + return components.LayoutNoOrderHistoryWithMsg(gtx, pg.Load, false, noOrderMsg) } - sep := pg.Theme.Separator() - sep.Width = gtx.Dp(sepWidth) - return layout.Center.Layout(gtx, sep.Layout) + + return pg.Theme.List(pg.ordersContainer).Layout(gtx, len(orders), func(gtx C, index int) D { + ord := orders[index] + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(func(gtx C) D { + if index == 0 { + sep := pg.Theme.Separator() + sep.Width = gtx.Dp(sepWidth) + return layout.Center.Layout(gtx, sep.Layout) + } + return D{} + }), + layout.Rigid(func(gtx C) D { + return layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceBetween, Alignment: layout.Middle}.Layout(gtx, + pg.orderColumn(false, ord.ordType, columnWidth), + pg.orderColumn(false, ord.market, columnWidth), + pg.orderColumn(false, ord.age, columnWidth), + pg.orderColumn(false, pg.Printer.Sprintf("%f", ord.price), columnWidth), + pg.orderColumn(false, pg.Printer.Sprintf("%f", ord.amount), columnWidth), + pg.orderColumn(false, pg.Printer.Sprintf("%.1f", ord.filled), columnWidth), + pg.orderColumn(false, pg.Printer.Sprintf("%.1f", ord.price), columnWidth), + pg.orderColumn(false, values.String(ord.status), columnWidth), + ) + }), + layout.Rigid(func(gtx C) D { + // No divider for last row + if index == len(orders)-1 { + return D{} + } + sep := pg.Theme.Separator() + sep.Width = gtx.Dp(sepWidth) + return layout.Center.Layout(gtx, sep.Layout) + }), + ) + }) }), ) }) @@ -946,6 +985,16 @@ func (pg *DEXMarketPage) HandleUserInteractions() { log.Info("Add server clicked") } + for pg.openOrdersBtn.Clicked() { + pg.openOrdersDisplayed = true + // TODO: Fetch orders and set pg.orders? + } + + for pg.orderHistoryBtn.Clicked() { + pg.openOrdersDisplayed = false + // TODO: Fetch orders and set pg.orders? + } + if pg.orderTypesDropdown.Changed() { pg.isMarketOrder = pg.orderTypesDropdown.SelectedIndex() != limitOrderIndex } diff --git a/ui/values/localizable/en.go b/ui/values/localizable/en.go index bd1531139..d65ea40ab 100644 --- a/ui/values/localizable/en.go +++ b/ui/values/localizable/en.go @@ -822,4 +822,6 @@ const EN = ` "market" = "Market" "assetPrice" = "Price (%s)" "assetAmount" = "Amount (%s)" +"booked" = "Booked" +"executed" = "Executed" ` diff --git a/ui/values/strings.go b/ui/values/strings.go index 4d0a34286..0d17fa2bc 100644 --- a/ui/values/strings.go +++ b/ui/values/strings.go @@ -931,4 +931,6 @@ const ( StrSeeMore = "seeMore" StrAssetPrice = "assetPrice" StrAssetAmount = "assetAmount" + StrBooked = "booked" + StrExecuted = "executed" )