diff --git a/ui/assets/decredicons/ic_moon.png b/ui/assets/decredicons/ic_moon.png new file mode 100644 index 000000000..bf39d52e5 Binary files /dev/null and b/ui/assets/decredicons/ic_moon.png differ diff --git a/ui/assets/decredicons/ic_sun.png b/ui/assets/decredicons/ic_sun.png new file mode 100644 index 000000000..b16e25a8b Binary files /dev/null and b/ui/assets/decredicons/ic_sun.png differ diff --git a/ui/decredmaterial/icon_gallery.go b/ui/decredmaterial/icon_gallery.go index 89e1b3e6e..65fb4fc57 100644 --- a/ui/decredmaterial/icon_gallery.go +++ b/ui/decredmaterial/icon_gallery.go @@ -24,7 +24,7 @@ type Icons struct { DecredSymbol2, GovernanceActiveIcon, GovernanceInactiveIcon, LogoDarkMode, TimerDarkMode, Rebroadcast, SettingsActiveIcon, SettingsInactiveIcon, ActivatedActiveIcon, ActivatedInactiveIcon, LockinActiveIcon, LockinInactiveIcon, SuccessIcon, FailedIcon, ReceiveInactiveIcon, SendInactiveIcon, DarkmodeIcon, - ChevronExpand, ChevronCollapse, ChevronLeft, NotSynced *Image + ChevronExpand, ChevronCollapse, ChevronLeft, NotSynced, InfoAction, LightMode, DarkMode *Image NewStakeIcon, TicketImmatureIcon, @@ -151,6 +151,9 @@ func (i *Icons) DefaultIcons() *Icons { i.ChevronCollapse = NewImage(decredIcons["chevron_expand"]) i.ChevronLeft = NewImage(decredIcons["chevron_left"]) i.NotSynced = NewImage(decredIcons["notSynced"]) + i.InfoAction = NewImage(decredIcons["info_icon"]) + i.DarkMode = NewImage(decredIcons["ic_moon"]) + i.LightMode = NewImage(decredIcons["ic_sun"]) return i } diff --git a/ui/decredmaterial/switch.go b/ui/decredmaterial/switch.go index d172e212f..60d3f6a7a 100644 --- a/ui/decredmaterial/switch.go +++ b/ui/decredmaterial/switch.go @@ -157,7 +157,7 @@ func (s *Switch) SetChecked(value bool) { } func (s *Switch) SetEnabled(value bool) { - s.disabled = value + s.disabled = !value } func (s *SwitchButtonText) Layout(gtx layout.Context) layout.Dimensions { diff --git a/ui/modal/info_modal.go b/ui/modal/info_modal.go index 56460eccf..8ba9fd4da 100644 --- a/ui/modal/info_modal.go +++ b/ui/modal/info_modal.go @@ -6,6 +6,7 @@ import ( "gioui.org/io/key" "gioui.org/layout" "gioui.org/text" + "gioui.org/unit" "gioui.org/widget/material" "github.com/planetdecred/godcr/ui/decredmaterial" @@ -28,7 +29,8 @@ type InfoModal struct { positiveButtonText string positiveButtonClicked func(isChecked bool) bool - btnPositve decredmaterial.Button + btnPositive decredmaterial.Button + btnPositiveWidth unit.Dp negativeButtonText string negativeButtonClicked func() @@ -45,22 +47,33 @@ type InfoModal struct { } func NewInfoModal(l *load.Load) *InfoModal { - return NewInfoModalWithKey(l, "info_modal") + return NewInfoModalWithKey(l, "info_modal", false) } -func NewInfoModalWithKey(l *load.Load, key string) *InfoModal { +// This function for normal positive button +func NewInfoModal2(l *load.Load) *InfoModal { + return NewInfoModalWithKey(l, "info_modal", true) +} + +func NewInfoModalWithKey(l *load.Load, key string, isPositiveButtonNormal bool) *InfoModal { in := &InfoModal{ - Load: l, - Modal: l.Theme.ModalFloatTitle(key), - btnPositve: l.Theme.OutlineButton(values.String(values.StrYes)), - btnNegative: l.Theme.OutlineButton(values.String(values.StrNo)), - isCancelable: true, - isLoading: false, - btnAlignment: layout.E, + Load: l, + Modal: l.Theme.ModalFloatTitle(key), + btnNegative: l.Theme.OutlineButton(values.String(values.StrNo)), + isCancelable: true, + isLoading: false, + btnAlignment: layout.E, + btnPositiveWidth: 0, + } + + if isPositiveButtonNormal { + in.btnPositive = l.Theme.Button(values.String(values.StrYes)) + } else { + in.btnPositive = l.Theme.OutlineButton(values.String(values.StrYes)) } - in.btnPositve.Font.Weight = text.Medium + in.btnPositive.Font.Weight = text.Medium in.btnNegative.Font.Weight = text.Medium in.materialLoader = material.Loader(l.Theme.Base) @@ -116,7 +129,12 @@ func (in *InfoModal) PositiveButton(text string, clicked func(isChecked bool) bo } func (in *InfoModal) PositiveButtonStyle(background, text color.NRGBA) *InfoModal { - in.btnPositve.Background, in.btnPositve.Color = background, text + in.btnPositive.Background, in.btnPositive.Color = background, text + return in +} + +func (in *InfoModal) PositiveButtonWidth(width unit.Dp) *InfoModal { + in.btnPositiveWidth = width return in } @@ -173,12 +191,12 @@ func (in *InfoModal) KeysToHandle() key.Set { // window that match any of the key combinations returned by KeysToHandle(). // Satisfies the load.KeyEventHandler interface for receiving key events. func (in *InfoModal) HandleKeyPress(evt *key.Event) { - in.btnPositve.Click() + in.btnPositive.Click() in.ParentWindow().Reload() } func (in *InfoModal) Handle() { - for in.btnPositve.Clicked() { + for in.btnPositive.Clicked() { if in.isLoading { return } @@ -311,9 +329,12 @@ func (in *InfoModal) actionButtonsLayout() layout.Widget { return layout.Dimensions{} } - in.btnPositve.Text = in.positiveButtonText + in.btnPositive.Text = in.positiveButtonText gtx.Constraints.Max.X = gtx.Dp(values.MarginPadding250) - return in.btnPositve.Layout(gtx) + if in.btnPositiveWidth > 0 { + gtx.Constraints.Min.X = gtx.Dp(in.btnPositiveWidth) + } + return in.btnPositive.Layout(gtx) }), ) }) diff --git a/ui/modal/text_input_modal.go b/ui/modal/text_input_modal.go index ca01cc3d8..91246b48d 100644 --- a/ui/modal/text_input_modal.go +++ b/ui/modal/text_input_modal.go @@ -29,7 +29,7 @@ type TextInputModal struct { func NewTextInputModal(l *load.Load) *TextInputModal { tm := &TextInputModal{ - InfoModal: NewInfoModalWithKey(l, "text_input_modal"), + InfoModal: NewInfoModalWithKey(l, "text_input_modal", false), isCancelable: true, } @@ -65,7 +65,7 @@ func (tm *TextInputModal) PositiveButton(text string, callback func(string, *Tex } func (tm *TextInputModal) PositiveButtonStyle(background, text color.NRGBA) *TextInputModal { - tm.positiveButtonColor, tm.btnPositve.Color = background, text + tm.positiveButtonColor, tm.btnPositive.Color = background, text return tm } @@ -93,10 +93,10 @@ func (tm *TextInputModal) SetTextWithTemplate(template string) *TextInputModal { func (tm *TextInputModal) Handle() { if editorsNotEmpty(tm.textInput.Editor) { - tm.btnPositve.Background = tm.positiveButtonColor + tm.btnPositive.Background = tm.positiveButtonColor tm.isEnabled = true } else { - tm.btnPositve.Background = tm.Theme.Color.Gray3 + tm.btnPositive.Background = tm.Theme.Color.Gray3 tm.isEnabled = false } @@ -105,7 +105,7 @@ func (tm *TextInputModal) Handle() { tm.textInput.SetError("") } - if (tm.btnPositve.Clicked() || isSubmit) && tm.isEnabled { + if (tm.btnPositive.Clicked() || isSubmit) && tm.isEnabled { if tm.isLoading { return } diff --git a/ui/page/about_page.go b/ui/page/about_page.go index ca0fb6f6e..2015b3918 100644 --- a/ui/page/about_page.go +++ b/ui/page/about_page.go @@ -85,34 +85,53 @@ func (pg *AboutPage) OnNavigatedTo() { // to be eventually drawn on screen. // Part of the load.Page interface. func (pg *AboutPage) Layout(gtx C) D { - body := func(gtx C) D { - page := components.SubPage{ - Load: pg.Load, - Title: values.String(values.StrAbout), - BackButton: pg.backButton, - Back: func() { - pg.ParentNavigator().CloseCurrentPage() - }, - Body: func(gtx C) D { - return pg.card.Layout(gtx, func(gtx C) D { - return pg.layoutRows(gtx) - }) - }, - } - return page.Layout(pg.ParentWindow(), gtx) - } if pg.Load.GetCurrentAppWidth() <= gtx.Dp(values.StartMobileView) { - return pg.layoutMobile(gtx, body) + return pg.layoutMobile(gtx) } - return pg.layoutDesktop(gtx, body) + return pg.layoutDesktop(gtx) +} + +func (pg *AboutPage) layoutDesktop(gtx layout.Context) layout.Dimensions { + return layout.UniformInset(values.MarginPadding20).Layout(gtx, func(gtx C) D { + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(pg.pageHeaderLayout), + layout.Rigid(func(gtx C) D { + return layout.Inset{Top: values.MarginPadding16, Bottom: values.MarginPadding20}.Layout(gtx, pg.pageContentLayout) + }), + ) + }) } -func (pg *AboutPage) layoutDesktop(gtx layout.Context, body layout.Widget) layout.Dimensions { - return components.UniformPadding(gtx, body) +func (pg *AboutPage) layoutMobile(gtx layout.Context) layout.Dimensions { + return layout.Dimensions{} } -func (pg *AboutPage) layoutMobile(gtx layout.Context, body layout.Widget) layout.Dimensions { - return components.UniformMobile(gtx, false, false, body) +func (pg *AboutPage) pageHeaderLayout(gtx layout.Context) layout.Dimensions { + return layout.Flex{Spacing: layout.SpaceBetween}.Layout(gtx, + layout.Flexed(1, func(gtx C) D { + return layout.W.Layout(gtx, func(gtx C) D { + return layout.Flex{}.Layout(gtx, + layout.Rigid(func(gtx C) D { + return layout.Inset{ + Right: values.MarginPadding16, + Top: values.MarginPaddingMinus2, + }.Layout(gtx, pg.backButton.Layout) + }), + layout.Rigid(pg.Theme.Label(values.TextSize20, values.String(values.StrAbout)).Layout), + ) + }) + }), + ) +} + +func (pg *AboutPage) pageContentLayout(gtx layout.Context) layout.Dimensions { + gtx.Constraints.Min.X = gtx.Constraints.Max.X + return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions { + gtx.Constraints.Min.X = gtx.Dp(values.MarginPadding550) + gtx.Constraints.Max.X = gtx.Constraints.Min.X + gtx.Constraints.Min.Y = gtx.Constraints.Max.Y + return pg.card.Layout(gtx, pg.layoutRows) + }) } func (pg *AboutPage) layoutRows(gtx C) D { @@ -190,6 +209,10 @@ func (pg *AboutPage) HandleUserInteractions() { if pg.licenseRow.Clicked() { pg.ParentNavigator().Display(NewLicensePage(pg.Load)) } + + if pg.backButton.Button.Clicked() { + pg.ParentNavigator().CloseCurrentPage() + } } // OnNavigatedFrom is called when the page is about to be removed from diff --git a/ui/page/help_page.go b/ui/page/help_page.go index 80f48d100..f167bbd01 100644 --- a/ui/page/help_page.go +++ b/ui/page/help_page.go @@ -67,26 +67,14 @@ func (pg *HelpPage) Layout(gtx C) D { } func (pg *HelpPage) layoutDesktop(gtx layout.Context) layout.Dimensions { - body := func(gtx C) D { - sp := components.SubPage{ - Load: pg.Load, - Title: values.String(values.StrHelp), - SubTitle: values.String(values.StrHelpInfo), - BackButton: pg.backButton, - Back: func() { - pg.ParentNavigator().CloseCurrentPage() - }, - Body: func(gtx C) D { - return layout.Inset{Top: values.MarginPadding5}.Layout(gtx, func(gtx C) D { - return layout.Flex{Spacing: layout.SpaceBetween, WeightSum: 2}.Layout(gtx, - layout.Flexed(1, pg.document()), - ) - }) - }, - } - return sp.Layout(pg.ParentWindow(), gtx) - } - return components.UniformPadding(gtx, body) + return layout.UniformInset(values.MarginPadding20).Layout(gtx, func(gtx C) D { + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(pg.pageHeaderLayout), + layout.Rigid(func(gtx C) D { + return layout.Inset{Top: values.MarginPadding16, Bottom: values.MarginPadding20}.Layout(gtx, pg.pageContentLayout) + }), + ) + }) } func (pg *HelpPage) layoutMobile(gtx layout.Context) layout.Dimensions { @@ -114,8 +102,48 @@ func (pg *HelpPage) layoutMobile(gtx layout.Context) layout.Dimensions { return components.UniformMobile(gtx, false, false, body) } +func (pg *HelpPage) pageHeaderLayout(gtx layout.Context) layout.Dimensions { + return layout.Flex{Spacing: layout.SpaceBetween}.Layout(gtx, + layout.Flexed(1, func(gtx C) D { + return layout.W.Layout(gtx, func(gtx C) D { + return layout.Flex{}.Layout(gtx, + layout.Rigid(func(gtx C) D { + return layout.Inset{ + Right: values.MarginPadding16, + Top: values.MarginPaddingMinus2, + }.Layout(gtx, pg.backButton.Layout) + }), + layout.Rigid(pg.Theme.Label(values.TextSize20, values.String(values.StrHelp)).Layout), + ) + }) + }), + ) +} + +func (pg *HelpPage) pageContentLayout(gtx layout.Context) layout.Dimensions { + gtx.Constraints.Min.X = gtx.Constraints.Max.X + return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions { + gtx.Constraints.Min.X = gtx.Dp(values.MarginPadding550) + gtx.Constraints.Max.X = gtx.Constraints.Min.X + gtx.Constraints.Min.Y = gtx.Constraints.Max.Y + return layout.Inset{Top: values.MarginPadding5}.Layout(gtx, func(gtx C) D { + return layout.Flex{Axis: layout.Vertical, Alignment: layout.Middle}.Layout(gtx, + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + sub := pg.Load.Theme.Label(values.TextSize14, values.String(values.StrHelpInfo)) + sub.Color = pg.Load.Theme.Color.GrayText2 + return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions { + return layout.Inset{Bottom: values.MarginPadding12}.Layout(gtx, sub.Layout) + }) + }), + layout.Flexed(1, pg.document()), + ) + }) + }) +} + func (pg *HelpPage) document() layout.Widget { return func(gtx C) D { + gtx.Constraints.Max.X = gtx.Dp(values.MarginPadding372) return pg.pageSections(gtx, pg.Theme.Icons.DocumentationIcon, pg.documentation, values.String(values.StrDocumentation)) } } @@ -128,7 +156,6 @@ func (pg *HelpPage) pageSections(gtx C, icon *decredmaterial.Image, action *decr Height: decredmaterial.WrapContent, Background: pg.Theme.Color.Surface, Clickable: action, - Direction: layout.Center, Alignment: layout.Middle, Shadow: pg.shadowBox, Border: decredmaterial.Border{Radius: decredmaterial.Radius(14)}, @@ -230,6 +257,10 @@ func (pg *HelpPage) HandleUserInteractions() { }) pg.ParentWindow().ShowModal(info) } + + if pg.backButton.Button.Clicked() { + pg.ParentNavigator().CloseCurrentPage() + } } // OnNavigatedFrom is called when the page is about to be removed from diff --git a/ui/page/license_page.go b/ui/page/license_page.go index f4b7c589e..e96bff95f 100644 --- a/ui/page/license_page.go +++ b/ui/page/license_page.go @@ -2,6 +2,7 @@ package page import ( "gioui.org/layout" + "gioui.org/unit" "gioui.org/widget" "github.com/planetdecred/godcr/app" @@ -15,19 +16,11 @@ const LicensePageID = "License" const license = `ISC License -Copyright (c) 2018-2022, Raedah Group +Copyright (c) 2018-2019 The Decred developers -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. +Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.` +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.` type LicensePage struct { *load.Load @@ -71,29 +64,14 @@ func (pg *LicensePage) Layout(gtx C) D { } func (pg *LicensePage) layoutDesktop(gtx layout.Context) layout.Dimensions { - d := func(gtx C) D { - sp := components.SubPage{ - Load: pg.Load, - Title: values.String(values.StrLicense), - BackButton: pg.backButton, - Back: func() { - pg.ParentNavigator().CloseCurrentPage() - }, - Body: func(gtx C) D { - return pg.Theme.List(pg.pageContainer).Layout(gtx, 1, func(gtx C, i int) D { - return pg.Theme.Card().Layout(gtx, func(gtx C) D { - return layout.UniformInset(values.MarginPadding25).Layout(gtx, func(gtx C) D { - licenseText := pg.Theme.Body1(license) - licenseText.Color = pg.Theme.Color.GrayText2 - return layout.Inset{Bottom: values.MarginPadding20}.Layout(gtx, licenseText.Layout) - }) - }) - }) - }, - } - return sp.Layout(pg.ParentWindow(), gtx) - } - return components.UniformPadding(gtx, d) + return layout.UniformInset(values.MarginPadding20).Layout(gtx, func(gtx C) D { + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(pg.pageHeaderLayout), + layout.Rigid(func(gtx C) D { + return layout.Inset{Top: values.MarginPadding16, Bottom: values.MarginPadding20}.Layout(gtx, pg.pageContentLayout) + }), + ) + }) } func (pg *LicensePage) layoutMobile(gtx layout.Context) layout.Dimensions { @@ -122,12 +100,52 @@ func (pg *LicensePage) layoutMobile(gtx layout.Context) layout.Dimensions { return components.UniformMobile(gtx, false, false, d) } +func (pg *LicensePage) pageHeaderLayout(gtx layout.Context) layout.Dimensions { + return layout.Flex{Spacing: layout.SpaceBetween}.Layout(gtx, + layout.Flexed(1, func(gtx C) D { + return layout.W.Layout(gtx, func(gtx C) D { + return layout.Flex{}.Layout(gtx, + layout.Rigid(func(gtx C) D { + return layout.Inset{ + Right: values.MarginPadding16, + Top: values.MarginPaddingMinus2, + }.Layout(gtx, pg.backButton.Layout) + }), + layout.Rigid(pg.Theme.Label(values.TextSize20, values.String(values.StrLicense)).Layout), + ) + }) + }), + ) +} + +func (pg *LicensePage) pageContentLayout(gtx layout.Context) layout.Dimensions { + gtx.Constraints.Min.X = gtx.Constraints.Max.X + return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions { + gtx.Constraints.Min.X = gtx.Dp(unit.Dp(560)) + gtx.Constraints.Max.X = gtx.Constraints.Min.X + gtx.Constraints.Min.Y = gtx.Constraints.Max.Y + return pg.Theme.List(pg.pageContainer).Layout(gtx, 1, func(gtx C, i int) D { + return pg.Theme.Card().Layout(gtx, func(gtx C) D { + return layout.UniformInset(values.MarginPadding16).Layout(gtx, func(gtx C) D { + licenseText := pg.Theme.Body1(license) + licenseText.Color = pg.Theme.Color.GrayText1 + return layout.Inset{Bottom: values.MarginPadding20}.Layout(gtx, licenseText.Layout) + }) + }) + }) + }) +} + // 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 *LicensePage) HandleUserInteractions() {} +func (pg *LicensePage) HandleUserInteractions() { + if pg.backButton.Button.Clicked() { + pg.ParentNavigator().CloseCurrentPage() + } +} // OnNavigatedFrom is called when the page is about to be removed from // the displayed window. This method should ideally be used to disable diff --git a/ui/page/settings_page.go b/ui/page/settings_page.go index ff55a5df0..bfd0b81ee 100644 --- a/ui/page/settings_page.go +++ b/ui/page/settings_page.go @@ -35,31 +35,22 @@ type SettingsPage struct { pageContainer *widget.List wal *wallet.Wallet - updateConnectToPeer *decredmaterial.Clickable - updateUserAgent *decredmaterial.Clickable - changeStartupPass *decredmaterial.Clickable - language *decredmaterial.Clickable - currency *decredmaterial.Clickable + changeStartupPass *decredmaterial.Clickable + language *decredmaterial.Clickable + currency *decredmaterial.Clickable + help *decredmaterial.Clickable + about *decredmaterial.Clickable + appearanceMode *decredmaterial.Clickable chevronRightIcon *decredmaterial.Icon backButton decredmaterial.IconButton infoButton decredmaterial.IconButton - isDarkModeOn *decredmaterial.Switch - spendUnconfirmed *decredmaterial.Switch + isDarkModeOn bool startupPassword *decredmaterial.Switch - beepNewBlocks *decredmaterial.Switch - connectToPeer *decredmaterial.Switch - userAgent *decredmaterial.Switch - governance *decredmaterial.Switch - proposalNotification *decredmaterial.Switch transactionNotification *decredmaterial.Switch - peerLabel, agentLabel decredmaterial.Label - isStartupPassword bool - peerAddr string - agentValue string errorReceiver chan error } @@ -74,28 +65,23 @@ func NewSettingsPage(l *load.Load) *SettingsPage { }, wal: l.WL.Wallet, - isDarkModeOn: l.Theme.Switch(), - spendUnconfirmed: l.Theme.Switch(), startupPassword: l.Theme.Switch(), - beepNewBlocks: l.Theme.Switch(), - connectToPeer: l.Theme.Switch(), - userAgent: l.Theme.Switch(), - governance: l.Theme.Switch(), - proposalNotification: l.Theme.Switch(), transactionNotification: l.Theme.Switch(), chevronRightIcon: decredmaterial.NewIcon(chevronRightIcon), errorReceiver: make(chan error), - updateConnectToPeer: l.Theme.NewClickable(false), - updateUserAgent: l.Theme.NewClickable(false), - changeStartupPass: l.Theme.NewClickable(false), - language: l.Theme.NewClickable(false), - currency: l.Theme.NewClickable(false), + changeStartupPass: l.Theme.NewClickable(false), + language: l.Theme.NewClickable(false), + currency: l.Theme.NewClickable(false), + help: l.Theme.NewClickable(false), + about: l.Theme.NewClickable(false), + appearanceMode: l.Theme.NewClickable(false), } pg.backButton, pg.infoButton = components.SubpageHeaderButtons(l) + pg.isDarkModeOn = pg.WL.MultiWallet.ReadBoolConfigValueForKey(load.DarkModeConfigKey, false) return pg } @@ -105,14 +91,13 @@ func NewSettingsPage(l *load.Load) *SettingsPage { // the page is displayed. // Part of the load.Page interface. func (pg *SettingsPage) OnNavigatedTo() { - + pg.updateSettingOptions() } // Layout draws the page UI components into the provided C // to be eventually drawn on screen. // Part of the load.Page interface. func (pg *SettingsPage) Layout(gtx C) D { - pg.updateSettingOptions() if pg.Load.GetCurrentAppWidth() <= gtx.Dp(values.StartMobileView) { return pg.layoutMobile(gtx) } @@ -120,85 +105,113 @@ func (pg *SettingsPage) Layout(gtx C) D { } func (pg *SettingsPage) layoutDesktop(gtx layout.Context) layout.Dimensions { - body := func(gtx C) D { - sp := components.SubPage{ - Load: pg.Load, - Title: values.String(values.StrSettings), - BackButton: pg.backButton, - Back: func() { - pg.ParentNavigator().CloseCurrentPage() - }, - Body: func(gtx C) D { - pageContent := []func(gtx C) D{ - pg.general(), - pg.security(), - pg.notification(), - pg.connection(), - } - - return pg.Theme.List(pg.pageContainer).Layout(gtx, len(pageContent), func(gtx C, i int) D { - return layout.Inset{Right: values.MarginPadding2}.Layout(gtx, pageContent[i]) - }) - }, - } - return sp.Layout(pg.ParentWindow(), gtx) - } + return layout.UniformInset(values.MarginPadding20).Layout(gtx, func(gtx C) D { + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(pg.pageHeaderLayout), + layout.Rigid(func(gtx C) D { + return layout.Inset{Bottom: values.MarginPadding20}.Layout(gtx, pg.pageContentLayout) + }), + ) + }) +} + +func (pg *SettingsPage) pageHeaderLayout(gtx layout.Context) layout.Dimensions { + return layout.Flex{Spacing: layout.SpaceBetween}.Layout(gtx, + layout.Flexed(1, func(gtx C) D { + return layout.W.Layout(gtx, func(gtx C) D { + return layout.Flex{}.Layout(gtx, + layout.Rigid(func(gtx C) D { + return layout.Inset{ + Right: values.MarginPadding16, + Top: values.MarginPaddingMinus2, + }.Layout(gtx, pg.backButton.Layout) + }), + layout.Rigid(pg.Theme.Label(values.TextSize20, values.String(values.StrSettings)).Layout), + ) + }) + }), + ) +} - return components.UniformPadding(gtx, body) +func (pg *SettingsPage) pageContentLayout(gtx layout.Context) layout.Dimensions { + pageContent := []func(gtx C) D{ + pg.general(), + pg.security(), + pg.info(), + } + gtx.Constraints.Min.X = gtx.Constraints.Max.X + return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions { + gtx.Constraints.Min.X = gtx.Dp(values.MarginPadding500) + gtx.Constraints.Max.X = gtx.Constraints.Min.X + gtx.Constraints.Min.Y = gtx.Constraints.Max.Y + return pg.Theme.List(pg.pageContainer).Layout(gtx, len(pageContent), func(gtx C, i int) D { + return layout.Inset{Right: values.MarginPadding2}.Layout(gtx, pageContent[i]) + }) + }) } func (pg *SettingsPage) layoutMobile(gtx layout.Context) layout.Dimensions { - body := func(gtx C) D { - sp := components.SubPage{ - Load: pg.Load, - Title: values.String(values.StrSettings), - BackButton: pg.backButton, - Back: func() { - pg.ParentNavigator().CloseCurrentPage() - }, - Body: func(gtx C) D { - pageContent := []func(gtx C) D{ - pg.general(), - pg.security(), - pg.notification(), - pg.connection(), - } - - return pg.Theme.List(pg.pageContainer).Layout(gtx, len(pageContent), func(gtx C, i int) D { - return layout.Inset{Right: values.MarginPadding2}.Layout(gtx, pageContent[i]) - }) - }, - } - return sp.Layout(pg.ParentWindow(), gtx) - } + return layout.Dimensions{} +} - return components.UniformMobile(gtx, false, true, body) +func (pg *SettingsPage) settingLine(gtx C) D { + line := pg.Theme.Line(1, 0) + line.Color = pg.Theme.Color.Gray3 + return line.Layout(gtx) } -func (pg *SettingsPage) general() layout.Widget { - return func(gtx C) D { - return pg.mainSection(gtx, values.String(values.StrGeneral), func(gtx C) D { +func (pg *SettingsPage) wrapSection(gtx C, title string, body layout.Widget) D { + return layout.Inset{Bottom: values.MarginPadding10}.Layout(gtx, func(gtx C) D { + return layout.UniformInset(values.MarginPadding15).Layout(gtx, func(gtx C) D { return layout.Flex{Axis: layout.Vertical}.Layout(gtx, layout.Rigid(func(gtx C) D { - return pg.subSectionSwitch(gtx, values.String(values.StrDarkMode), pg.isDarkModeOn) - }), - layout.Rigid(func(gtx C) D { - return pg.subSectionSwitch(gtx, values.String(values.StrUnconfirmedFunds), pg.spendUnconfirmed) + return layout.Flex{Axis: layout.Horizontal}.Layout(gtx, + layout.Rigid(func(gtx C) D { + txt := pg.Theme.Body2(title) + txt.Color = pg.Theme.Color.GrayText2 + return layout.Inset{Bottom: values.MarginPadding10}.Layout(gtx, txt.Layout) + }), + layout.Flexed(1, func(gtx C) D { + if title == values.String(values.StrSecurity) { + pg.infoButton.Inset = layout.UniformInset(values.MarginPadding0) + pg.infoButton.Size = values.MarginPadding20 + return layout.E.Layout(gtx, pg.infoButton.Layout) + } + if title == values.String(values.StrGeneral) { + layout.E.Layout(gtx, func(gtx C) D { + appearanceIcon := pg.Theme.Icons.DarkMode + if pg.isDarkModeOn { + appearanceIcon = pg.Theme.Icons.LightMode + } + return pg.appearanceMode.Layout(gtx, appearanceIcon.Layout16dp) + }) + } + return D{} + }), + ) }), layout.Rigid(func(gtx C) D { - return pg.subSectionSwitch(gtx, values.String(values.StrGovernance), pg.governance) + return layout.Inset{Bottom: values.MarginPadding5}.Layout(gtx, pg.settingLine) }), - layout.Rigid(pg.lineSeparator()), + layout.Rigid(body), + ) + }) + }) +} + +func (pg *SettingsPage) general() layout.Widget { + return func(gtx C) D { + return pg.wrapSection(gtx, values.String(values.StrGeneral), func(gtx C) D { + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, layout.Rigid(func(gtx C) D { - currencyConversionRow := row{ - title: values.String(values.StrCurrencyConversion), + exchangeRate := row{ + title: values.String(values.StrExchangeRate), clickable: pg.currency, icon: pg.chevronRightIcon, label: pg.Theme.Body2(pg.WL.MultiWallet.ReadStringConfigValueForKey(dcrlibwallet.CurrencyConversionConfigKey)), } - return pg.clickableRow(gtx, currencyConversionRow) + return pg.clickableRow(gtx, exchangeRate) }), - layout.Rigid(pg.lineSeparator()), layout.Rigid(func(gtx C) D { languageRow := row{ title: values.String(values.StrLanguage), @@ -208,24 +221,9 @@ func (pg *SettingsPage) general() layout.Widget { } return pg.clickableRow(gtx, languageRow) }), - ) - }) - } -} - -func (pg *SettingsPage) notification() layout.Widget { - return func(gtx C) D { - return pg.mainSection(gtx, values.String(values.StrNotifications), func(gtx C) D { - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - layout.Rigid(func(gtx C) D { - return pg.subSectionSwitch(gtx, values.String(values.StrBeepForNewBlocks), pg.beepNewBlocks) - }), layout.Rigid(func(gtx C) D { return pg.subSectionSwitch(gtx, values.StringF(values.StrTxNotification, ""), pg.transactionNotification) }), - layout.Rigid(func(gtx C) D { - return pg.subSectionSwitch(gtx, values.StringF(values.StrPropNotification, ""), pg.proposalNotification) - }), ) }) } @@ -233,7 +231,7 @@ func (pg *SettingsPage) notification() layout.Widget { func (pg *SettingsPage) security() layout.Widget { return func(gtx C) D { - return pg.mainSection(gtx, values.String(values.StrSecurity), func(gtx C) D { + return pg.wrapSection(gtx, values.String(values.StrSecurity), func(gtx C) D { return layout.Flex{Axis: layout.Vertical}.Layout(gtx, layout.Rigid(func(gtx C) D { return pg.subSectionSwitch(gtx, values.String(values.StrStartupPassword), pg.startupPassword) @@ -254,106 +252,33 @@ func (pg *SettingsPage) security() layout.Widget { } } -func (pg *SettingsPage) connection() layout.Widget { +func (pg *SettingsPage) info() layout.Widget { return func(gtx C) D { - return pg.mainSection(gtx, values.String(values.StrConnection), func(gtx C) D { + return pg.wrapSection(gtx, values.String(values.StrInfo), func(gtx C) D { return layout.Flex{Axis: layout.Vertical}.Layout(gtx, layout.Rigid(func(gtx C) D { - return pg.subSectionSwitch(gtx, values.String(values.StrConnectToSpecificPeer), pg.connectToPeer) + helpRow := row{ + title: values.String(values.StrHelp), + clickable: pg.help, + icon: pg.chevronRightIcon, + label: pg.Theme.Body2(""), + } + return pg.clickableRow(gtx, helpRow) }), layout.Rigid(func(gtx C) D { - peerLabel := pg.Theme.Body1(pg.peerAddr) - peerLabel.Color = pg.Theme.Color.GrayText2 - peerAddrRow := row{ - title: values.String(values.StrChangeSpecificPeer), - clickable: pg.updateConnectToPeer, + aboutRow := row{ + title: values.String(values.StrAbout), + clickable: pg.about, icon: pg.chevronRightIcon, - label: peerLabel, + label: pg.Theme.Body2(""), } - return pg.conditionalDisplay(gtx, pg.peerAddr != "", func(gtx C) D { - return pg.clickableRow(gtx, peerAddrRow) - }) + return pg.clickableRow(gtx, aboutRow) }), - layout.Rigid(pg.lineSeparator()), - layout.Rigid(pg.agent()), ) }) } } -func (pg *SettingsPage) agent() layout.Widget { - return func(gtx C) D { - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - layout.Rigid(func(gtx C) D { - return layout.Flex{}.Layout(gtx, - layout.Rigid(func(gtx C) D { - m10 := values.MarginPadding10 - return layout.Inset{Top: m10, Bottom: m10}.Layout(gtx, func(gtx C) D { - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - layout.Rigid(pg.subSectionLabel(values.String(values.StrCustomUserAgent))), - layout.Rigid(func(gtx C) D { - txt := pg.Theme.Body2(values.String(values.StrHTTPRequest)) - txt.Color = pg.Theme.Color.GrayText2 - return layout.Inset{Top: values.MarginPadding5}.Layout(gtx, func(gtx C) D { - return txt.Layout(gtx) - }) - }), - ) - }) - }), - layout.Flexed(1, func(gtx C) D { - return layout.Inset{Top: values.MarginPadding7}.Layout(gtx, func(gtx C) D { - return layout.E.Layout(gtx, pg.userAgent.Layout) - }) - }), - ) - }), - layout.Rigid(func(gtx C) D { - agentLabel := pg.Theme.Body1(pg.agentValue) - agentLabel.Color = pg.Theme.Color.GrayText2 - return pg.conditionalDisplay(gtx, pg.agentValue != "", func(gtx C) D { - userAgentRow := row{ - title: values.String(values.StrUserAgentDialogTitle), - clickable: pg.updateUserAgent, - icon: pg.chevronRightIcon, - label: agentLabel, - } - return pg.clickableRow(gtx, userAgentRow) - }) - }), - ) - } -} - -func (pg *SettingsPage) mainSection(gtx C, title string, body layout.Widget) D { - return layout.Inset{Bottom: values.MarginPadding10}.Layout(gtx, func(gtx C) D { - return pg.Theme.Card().Layout(gtx, func(gtx C) D { - return layout.UniformInset(values.MarginPadding15).Layout(gtx, func(gtx C) D { - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - layout.Rigid(func(gtx C) D { - return layout.Flex{Axis: layout.Horizontal}.Layout(gtx, - layout.Rigid(func(gtx C) D { - txt := pg.Theme.Body2(title) - txt.Color = pg.Theme.Color.GrayText2 - return layout.Inset{Bottom: values.MarginPadding10}.Layout(gtx, txt.Layout) - }), - layout.Flexed(1, func(gtx C) D { - if title == values.String(values.StrSecurity) { - pg.infoButton.Inset = layout.UniformInset(values.MarginPadding0) - pg.infoButton.Size = values.MarginPadding20 - return layout.E.Layout(gtx, pg.infoButton.Layout) - } - return D{} - }), - ) - }), - layout.Rigid(body), - ) - }) - }) - }) -} - func (pg *SettingsPage) subSection(gtx C, title string, body layout.Widget) D { return layout.Inset{Top: values.MarginPadding5, Bottom: values.MarginPadding15}.Layout(gtx, func(gtx C) D { return layout.Flex{}.Layout(gtx, @@ -377,7 +302,7 @@ func (pg *SettingsPage) clickableRow(gtx C, row row) D { layout.Rigid(row.label.Layout), layout.Rigid(func(gtx C) D { ic := row.icon - ic.Color = pg.Theme.Color.Gray3 + ic.Color = pg.Theme.Color.Gray1 return ic.Layout(gtx, values.MarginPadding22) }), ) @@ -440,64 +365,30 @@ func (pg *SettingsPage) HandleUserInteractions() { break } + for pg.backButton.Button.Clicked() { + pg.ParentNavigator().CloseCurrentPage() + } + for pg.currency.Clicked() { currencySelectorModal := preference.NewListPreference(pg.Load, dcrlibwallet.CurrencyConversionConfigKey, values.DefaultExchangeValue, values.ArrExchangeCurrencies). - Title(values.StrCurrencyConversion). + Title(values.StrExchangeRate). UpdateValues(func() {}) pg.ParentWindow().ShowModal(currencySelectorModal) break } - if pg.isDarkModeOn.Changed() { - pg.WL.MultiWallet.SaveUserConfigValue(load.DarkModeConfigKey, pg.isDarkModeOn.IsChecked()) + for pg.appearanceMode.Clicked() { + pg.isDarkModeOn = !pg.isDarkModeOn + pg.WL.MultiWallet.SaveUserConfigValue(load.DarkModeConfigKey, pg.isDarkModeOn) pg.RefreshTheme(pg.ParentWindow()) } - if pg.spendUnconfirmed.Changed() { - pg.WL.MultiWallet.SaveUserConfigValue(dcrlibwallet.SpendUnconfirmedConfigKey, pg.spendUnconfirmed.IsChecked()) - } - - if pg.governance.Changed() { - if pg.governance.IsChecked() { - go pg.WL.MultiWallet.Politeia.Sync() - pg.WL.MultiWallet.SaveUserConfigValue(load.FetchProposalConfigKey, pg.governance.IsChecked()) - pg.Toast.Notify(values.StringF(values.StrPropFetching, values.String(values.StrEnabled), values.String(values.StrCheckGovernace))) - } else { - info := modal.NewInfoModal(pg.Load). - Title(values.String(values.StrGovernance)). - Body(values.String(values.StrGovernanceSettingsInfo)). - NegativeButton(values.String(values.StrCancel), func() {}). - PositiveButtonStyle(pg.Theme.Color.Surface, pg.Theme.Color.Danger). - PositiveButton(values.String(values.StrDisable), func(isChecked bool) bool { - if pg.WL.MultiWallet.Politeia.IsSyncing() { - go pg.WL.MultiWallet.Politeia.StopSync() - } - pg.WL.MultiWallet.SaveUserConfigValue(load.FetchProposalConfigKey, !pg.governance.IsChecked()) - pg.WL.MultiWallet.Politeia.ClearSavedProposals() - pg.Toast.Notify(values.StringF(values.StrPropFetching, values.String(values.StrDisabled))) - return true - }) - pg.ParentWindow().ShowModal(info) - } - } - - if pg.beepNewBlocks.Changed() { - pg.WL.MultiWallet.SaveUserConfigValue(dcrlibwallet.BeepNewBlocksConfigKey, pg.beepNewBlocks.IsChecked()) - } - - if pg.proposalNotification.Changed() { - pg.WL.MultiWallet.SaveUserConfigValue(load.ProposalNotificationConfigKey, pg.proposalNotification.IsChecked()) - if pg.proposalNotification.IsChecked() { - pg.Toast.Notify(values.StringF(values.StrPropNotification, values.String(values.StrEnabled))) - } else { - pg.Toast.Notify(values.StringF(values.StrPropNotification, values.String(values.StrDisabled))) - } - } - if pg.transactionNotification.Changed() { - pg.WL.MultiWallet.SaveUserConfigValue(load.TransactionNotificationConfigKey, pg.transactionNotification.IsChecked()) + go func() { + pg.WL.MultiWallet.SaveUserConfigValue(load.TransactionNotificationConfigKey, pg.transactionNotification.IsChecked()) + }() if pg.transactionNotification.IsChecked() { pg.Toast.Notify(values.StringF(values.StrTxNotification, values.String(values.StrEnabled))) } else { @@ -506,15 +397,24 @@ func (pg *SettingsPage) HandleUserInteractions() { } if pg.infoButton.Button.Clicked() { - info := modal.NewInfoModal(pg.Load). - Title(values.String(values.StrSetupStartupPassword)). + info := modal.NewInfoModal2(pg.Load). + SetContentAlignment(layout.Center, layout.Center). Body(values.String(values.StrStartupPasswordInfo)). - PositiveButton(values.String(values.StrGotIt), func(isChecked bool) bool { + PositiveButtonWidth(values.MarginPadding100). + PositiveButton(values.String(values.StrOk), func(isChecked bool) bool { return true }) pg.ParentWindow().ShowModal(info) } + if pg.help.Clicked() { + pg.ParentNavigator().Display(NewHelpPage(pg.Load)) + } + + if pg.about.Clicked() { + pg.ParentNavigator().Display(NewAboutPage(pg.Load)) + } + for pg.changeStartupPass.Clicked() { currentPasswordModal := modal.NewPasswordModal(pg.Load). Title(values.String(values.StrConfirmStartupPass)). @@ -550,7 +450,7 @@ func (pg *SettingsPage) HandleUserInteractions() { m.SetLoading(false) return } - pg.Toast.Notify(values.String(values.StrStartupPassConfirm)) + pg.showNoticeSuccess(values.String(values.StrStartupPassConfirm)) m.Dismiss() }() return false @@ -580,7 +480,7 @@ func (pg *SettingsPage) HandleUserInteractions() { m.SetLoading(false) return } - pg.Toast.Notify(values.StringF(values.StrStartupPasswordEnabled, values.String(values.StrEnabled))) + pg.showNoticeSuccess(values.StringF(values.StrStartupPasswordEnabled, values.String(values.StrEnabled))) m.Dismiss() }() return false @@ -605,7 +505,7 @@ func (pg *SettingsPage) HandleUserInteractions() { pm.SetLoading(false) return } - pg.Toast.Notify(values.StringF(values.StrStartupPasswordEnabled, values.String(values.StrDisabled))) + pg.showNoticeSuccess(values.StringF(values.StrStartupPasswordEnabled, values.String(values.StrDisabled))) pm.Dismiss() }() @@ -615,40 +515,6 @@ func (pg *SettingsPage) HandleUserInteractions() { } } - specificPeerKey := dcrlibwallet.SpvPersistentPeerAddressesConfigKey - if pg.connectToPeer.Changed() { - if pg.connectToPeer.IsChecked() { - pg.showSPVPeerDialog() - return - } - - title := values.String(values.StrRemovePeer) - msg := values.String(values.StrRemovePeerWarn) - pg.showWarningModalDialog(title, msg, specificPeerKey) - } - - for pg.updateConnectToPeer.Clicked() { - pg.showSPVPeerDialog() - break - } - - userAgentKey := dcrlibwallet.UserAgentConfigKey - for pg.updateUserAgent.Clicked() { - pg.showUserAgentDialog() - break - } - - if pg.userAgent.Changed() { - if pg.userAgent.IsChecked() { - pg.showUserAgentDialog() - return - } - - title := values.String(values.StrRemoveUserAgent) - msg := values.String(values.StrRemoveUserAgentWarn) - pg.showWarningModalDialog(title, msg, userAgentKey) - } - select { case err := <-pg.errorReceiver: if err.Error() == dcrlibwallet.ErrInvalidPassphrase { @@ -660,6 +526,20 @@ func (pg *SettingsPage) HandleUserInteractions() { } } +func (pg *SettingsPage) showNoticeSuccess(title string) { + icon := decredmaterial.NewIcon(pg.Theme.Icons.ActionCheckCircle) + icon.Color = pg.Theme.Color.Green500 + info := modal.NewInfoModal2(pg.Load). + SetContentAlignment(layout.Center, layout.Center). + Title(title). + Icon(icon). + PositiveButtonWidth(values.MarginPadding100). + PositiveButton(values.String(values.StrOk), func(isChecked bool) bool { + return true + }) + pg.ParentWindow().ShowModal(info) +} + func (pg *SettingsPage) showSPVPeerDialog() { textModal := modal.NewTextInputModal(pg.Load). Hint(values.String(values.StrIPAddress)). @@ -701,50 +581,6 @@ func (pg *SettingsPage) updateSettingOptions() { pg.isStartupPassword = true } - isDarkModeOn := pg.WL.MultiWallet.ReadBoolConfigValueForKey(load.DarkModeConfigKey, false) - pg.isDarkModeOn.SetChecked(false) - if isDarkModeOn { - pg.isDarkModeOn.SetChecked(isDarkModeOn) - } - - isSpendUnconfirmed := pg.WL.MultiWallet.ReadBoolConfigValueForKey(dcrlibwallet.SpendUnconfirmedConfigKey, false) - pg.spendUnconfirmed.SetChecked(false) - if isSpendUnconfirmed { - pg.spendUnconfirmed.SetChecked(isSpendUnconfirmed) - } - - beep := pg.WL.MultiWallet.ReadBoolConfigValueForKey(dcrlibwallet.BeepNewBlocksConfigKey, false) - pg.beepNewBlocks.SetChecked(false) - if beep { - pg.beepNewBlocks.SetChecked(beep) - } - - pg.peerAddr = pg.WL.MultiWallet.ReadStringConfigValueForKey(dcrlibwallet.SpvPersistentPeerAddressesConfigKey) - pg.connectToPeer.SetChecked(false) - if pg.peerAddr != "" { - pg.peerLabel.Text = pg.peerAddr - pg.connectToPeer.SetChecked(true) - } - - pg.agentValue = pg.WL.MultiWallet.ReadStringConfigValueForKey(dcrlibwallet.UserAgentConfigKey) - pg.userAgent.SetChecked(false) - if pg.agentValue != "" { - pg.agentLabel.Text = pg.agentValue - pg.userAgent.SetChecked(true) - } - - governanceSet := pg.WL.MultiWallet.ReadBoolConfigValueForKey(load.FetchProposalConfigKey, false) - pg.governance.SetChecked(false) - if governanceSet { - pg.governance.SetChecked(governanceSet) - } - - proposalNotification := pg.WL.MultiWallet.ReadBoolConfigValueForKey(load.ProposalNotificationConfigKey, false) - pg.proposalNotification.SetChecked(false) - if proposalNotification { - pg.proposalNotification.SetChecked(proposalNotification) - } - transactionNotification := pg.WL.MultiWallet.ReadBoolConfigValueForKey(load.TransactionNotificationConfigKey, false) pg.transactionNotification.SetChecked(false) if transactionNotification { diff --git a/ui/page/staking/stake_overview.go b/ui/page/staking/stake_overview.go index 52c41eb4e..2e829263f 100644 --- a/ui/page/staking/stake_overview.go +++ b/ui/page/staking/stake_overview.go @@ -109,7 +109,7 @@ func (pg *Page) fetchTicketPrice() { func (pg *Page) setStakingButtonsState() { //disable auto ticket purchase if wallet is not synced - pg.stake.SetEnabled(!pg.WL.MultiWallet.IsSynced() || pg.WL.SelectedWallet.Wallet.IsWatchingOnlyWallet()) + pg.stake.SetEnabled(pg.WL.MultiWallet.IsSynced() || !pg.WL.SelectedWallet.Wallet.IsWatchingOnlyWallet()) } func (pg *Page) loadPageData() { diff --git a/ui/preference/list_preference.go b/ui/preference/list_preference.go index c9181d27e..916c59e12 100644 --- a/ui/preference/list_preference.go +++ b/ui/preference/list_preference.go @@ -4,11 +4,11 @@ import ( "sort" "gioui.org/layout" + "gioui.org/text" "gioui.org/widget" "github.com/planetdecred/godcr/ui/decredmaterial" "github.com/planetdecred/godcr/ui/load" - "github.com/planetdecred/godcr/ui/page/components" "github.com/planetdecred/godcr/ui/values" ) @@ -17,7 +17,9 @@ type ListPreferenceModal struct { *decredmaterial.Modal optionsRadioGroup *widget.Enum - cancelButton decredmaterial.IconButton + + btnSave decredmaterial.Button + btnCancel decredmaterial.Button items map[string]string //[key]str-key itemKeys []string @@ -45,6 +47,9 @@ func NewListPreference(l *load.Load, preferenceKey, defaultValue string, items m preferenceKey: preferenceKey, defaultValue: defaultValue, + btnSave: l.Theme.Button(values.String(values.StrSave)), + btnCancel: l.Theme.OutlineButton(values.String(values.StrCancel)), + items: items, itemKeys: sortedKeys, @@ -52,8 +57,8 @@ func NewListPreference(l *load.Load, preferenceKey, defaultValue string, items m Modal: l.Theme.ModalFloatTitle("list_preference"), } - lp.cancelButton, _ = components.SubpageHeaderButtons(l) - lp.cancelButton.Icon = l.Theme.Icons.ContentClear + lp.btnSave.Font.Weight = text.Medium + lp.btnCancel.Font.Weight = text.Medium return &lp } @@ -83,8 +88,7 @@ func (lp *ListPreferenceModal) UpdateValues(clicked func()) *ListPreferenceModal } func (lp *ListPreferenceModal) Handle() { - - for lp.optionsRadioGroup.Changed() { + for lp.btnSave.Button.Clicked() { lp.currentValue = lp.optionsRadioGroup.Value lp.WL.MultiWallet.SaveUserConfigValue(lp.preferenceKey, lp.optionsRadioGroup.Value) lp.updateButtonClicked() @@ -92,7 +96,7 @@ func (lp *ListPreferenceModal) Handle() { lp.Dismiss() } - for lp.cancelButton.Button.Clicked() { + for lp.btnCancel.Button.Clicked() { lp.Modal.Dismiss() } @@ -106,16 +110,19 @@ func (lp *ListPreferenceModal) Layout(gtx layout.Context) layout.Dimensions { func(gtx layout.Context) layout.Dimensions { txt := lp.Theme.H6(values.String(lp.title)) txt.Color = lp.Theme.Color.Text - return layout.Flex{Axis: layout.Horizontal, Spacing: layout.SpaceBetween}. - Layout(gtx, layout.Rigid(txt.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return layout.Inset{ - Top: values.MarginPaddingMinus2, - }.Layout(gtx, lp.cancelButton.Layout) - })) + return txt.Layout(gtx) }, func(gtx layout.Context) layout.Dimensions { return layout.Flex{Axis: layout.Vertical}.Layout(gtx, lp.layoutItems()...) }, + func(gtx layout.Context) layout.Dimensions { + return layout.E.Layout(gtx, func(gtx layout.Context) layout.Dimensions { + return layout.Flex{Axis: layout.Horizontal}.Layout(gtx, + layout.Rigid(lp.btnCancel.Layout), + layout.Rigid(lp.btnSave.Layout), + ) + }) + }, } return lp.Modal.Layout(gtx, w) diff --git a/ui/values/dimensions.go b/ui/values/dimensions.go index 09b2776fe..54e36d658 100644 --- a/ui/values/dimensions.go +++ b/ui/values/dimensions.go @@ -78,10 +78,12 @@ var ( MarginPaddingMinus230 = unit.Dp(-230) MarginPadding280 = unit.Dp(280) MarginPadding350 = unit.Dp(350) + MarginPadding372 = unit.Dp(372) MarginPadding377 = unit.Dp(377) MarginPadding390 = unit.Dp(390) MarginPadding450 = unit.Dp(450) MarginPadding550 = unit.Dp(550) + MarginPadding500 = unit.Dp(500) TextSize10 = unit.Sp(10) TextSize12 = unit.Sp(12) diff --git a/ui/values/localizable/en.go b/ui/values/localizable/en.go index 3fdf71628..84d050f59 100644 --- a/ui/values/localizable/en.go +++ b/ui/values/localizable/en.go @@ -135,7 +135,7 @@ unlockWithPassword = "Unlock with password" "general" = "General"; "unconfirmedFunds" = "Spend Unconfirmed Funds"; "confirmed" = "Confirmed"; -"currencyConversion" = "Currency conversion"; +"exchangeRate" = "Fetch exchange rate"; "language" = "Language"; "security" = "Security"; "newStartupPass" = "New startup password" @@ -398,7 +398,7 @@ unlockWithPassword = "Unlock with password" "userAgent" = "User agent" "validateMsg" = "Validate address" "validate" = "Validate" -"helpInfo" = "For more information, please visit the Decred documentation." +"helpInfo" = "For more information, click and please visit the Decred documentation." "documentation" = "Documentation" "verifyMsgNote" = "Enter the address, signature, and message to verify:" "verifyMsgError" = "Error verifying message: %v" @@ -488,6 +488,7 @@ unlockWithPassword = "Unlock with password" "selectDexServerToOpen" = "Select the Dex server you would like to open." "addDexServer" = "Add dex server" "canBuy" = "Can Buy" +"ok" = "OK" "treasurySpending" = "Treasury Spending" "treasurySpendingInfo" = "Spending treasury funds now requires stakeholders to vote on the expenditure. You can participate and set a voting policy for treasury spending by a particular Governance Key. The keys can be verified in the dcrd source." "verifyGovernanceKeys" = "Verify Governance Keys" diff --git a/ui/values/localizable/es.go b/ui/values/localizable/es.go index 6c5c0c820..f08d8d1b7 100644 --- a/ui/values/localizable/es.go +++ b/ui/values/localizable/es.go @@ -132,7 +132,7 @@ const ES = ` "general" = "General"; "unconfirmedFunds" = "Gastar fondos no confirmados"; "confirmed" = "Confirmado"; -"currencyConversion" = "Conversión de Moneda"; +"exchangeRate" = "Obtener tipo de cambio"; "language" = "Idioma"; "security" = "Seguridad"; "newStartupPass" = "Nueva contraseña de inicio" @@ -478,4 +478,5 @@ syncCompTime" = "Est. Sync completion time" "selectDexServerToOpen" = "Select the Dex server you would like to open." "addDexServer" = "Add dex server" "canBuy" = "Can Buy" +"ok" = "OK" ` diff --git a/ui/values/localizable/fr.go b/ui/values/localizable/fr.go index 465b5f3f3..230be8d20 100644 --- a/ui/values/localizable/fr.go +++ b/ui/values/localizable/fr.go @@ -49,7 +49,7 @@ const FR = ` "autoSyncInfo" = "La fonction de synchronisation automatique a été activée et les portefeuilles ne sont pas synchronisés.\nVoulez-vous commencer à synchroniser vos portefeuilles maintenant?"; "blockHeaderFetchedCount" = "%d de %d"; "timeLeft" = "%v restant"; -"currencyConversion" = "Conversion de devise"; +"exchangeRate" = "Récupérer le taux de change"; "renameWalletSheetTitle" = "Renommer le porte-monnaie"; "send" = "Envoyer"; "transferred" = "Transféré"; @@ -455,4 +455,5 @@ const FR = ` "selectDexServerToOpen" = "Select the Dex server you would like to open." "addDexServer" = "Add dex server" "canBuy" = "Can Buy" +"ok" = "D'accord" ` diff --git a/ui/values/strings.go b/ui/values/strings.go index bef783c34..bed298750 100644 --- a/ui/values/strings.go +++ b/ui/values/strings.go @@ -267,7 +267,7 @@ const ( StrGeneral = "general" StrChangeUserAgent = "changeUserAgent" StrCreateStartupPassword = "createStartupPassword" - StrCurrencyConversion = "currencyConversion" + StrExchangeRate = "exchangeRate" StrTransactions = "transactions" StrWallets = "wallets" StrTickets = "tickets" @@ -595,6 +595,7 @@ const ( StrSelectDexServerToOpen = "selectDexServerToOpen" StrAddDexServer = "addDexServer" StrCanBuy = "canBuy" + StrOk = "ok" StrTreasurySpending = "treasurySpending" StrTreasurySpendingInfo = "treasurySpendingInfo" StrVerifyGovernanceKeys = "verifyGovernanceKeys"