Advance the GUI layout

This commit is contained in:
Rene Vergara 2024-05-27 07:37:34 -05:00
parent 2f65401ee7
commit 537f3bc46f
Signed by: pitmutt
GPG key ID: 65122AD495A7F5B2
12 changed files with 385 additions and 19 deletions

BIN
assets/1F993.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/remixicon.ttf Normal file

Binary file not shown.

View file

@ -11,6 +11,7 @@ import Database.Persist
import Lens.Micro ((&), (+~), (.~), (?~), (^.), set)
import Lens.Micro.TH
import Monomer
import qualified Monomer.Lens as L
import TextShow
import ZcashHaskell.Types
( ZcashNet(..)
@ -19,12 +20,25 @@ import ZcashHaskell.Types
)
import Zenith.Core
import Zenith.DB
import Zenith.Types
import Zenith.GUI.Theme
import Zenith.Types hiding (ZcashAddress)
import Zenith.Utils (displayAmount, showAddress)
data AppModel = AppModel
{ _network :: !ZcashNet
{ _configuration :: !Config
, _network :: !ZcashNet
, _wallets :: ![Entity ZcashWallet]
, _selWallet :: !Int
, _accounts :: ![Entity ZcashAccount]
, _selAcc :: !Int
, _addresses :: ![Entity WalletAddress]
, _selAddr :: !Int
, _transactions :: ![Entity UserTx]
, _setTx :: !Int
, _msg :: !(Maybe T.Text)
, _zebraOn :: !Bool
, _balance :: !Integer
, _unconfBalance :: !(Maybe Integer)
} deriving (Eq, Show)
makeLenses ''AppModel
@ -33,21 +47,133 @@ data AppEvent
= AppInit
| ShowMsg !T.Text
| CloseMsg
| WalletClicked
| AccountClicked
deriving (Eq, Show)
remixArrowRightWideLine :: T.Text
remixArrowRightWideLine = toGlyph 0xF496
remixHourglassFill :: T.Text
remixHourglassFill = toGlyph 0xF338
remixIcon :: T.Text -> WidgetNode s e
remixIcon i = label i `styleBasic` [textFont "Remix", textMiddle]
buildUI ::
WidgetEnv AppModel AppEvent -> AppModel -> WidgetNode AppModel AppEvent
buildUI wenv model = widgetTree
where
btnColor = rgbHex "#1818B2"
btnHiLite = rgbHex "#207DE8"
currentWallet =
if null (model ^. wallets)
then Nothing
else Just ((model ^. wallets) !! (model ^. selWallet))
currentAccount =
if null (model ^. accounts)
then Nothing
else Just ((model ^. accounts) !! (model ^. selAcc))
widgetTree =
zstack
[ vstack
[ label "Hello World"
, spacer
, hstack [button "Try the overlay" $ ShowMsg "It works!"]
] `styleBasic`
[padding 10]
, msgOverlay `nodeVisible` isJust (model ^. msg)
zstack [mainWindow, msgOverlay `nodeVisible` isJust (model ^. msg)]
mainWindow =
vstack
[ windowHeader
, spacer
, balanceBox
, filler
, mainPane
, filler
, windowFooter
]
windowHeader =
hstack
[ box_ [onClick WalletClicked, alignMiddle] walletButton `styleBasic`
[cursorHand, height 25, padding 3] `styleHover`
[bgColor btnHiLite]
, box_ [onClick AccountClicked, alignMiddle] accountButton `styleBasic`
[cursorHand, height 25, padding 3] `styleHover`
[bgColor btnHiLite]
, filler
, remixIcon remixErrorWarningFill
, label "Testnet" `nodeVisible` (model ^. network == TestNet)
] `styleBasic`
[bgColor btnColor]
walletButton =
hstack
[ label "Wallet: " `styleBasic` [textFont "Bold", textColor white]
, label (maybe "None" (zcashWalletName . entityVal) currentWallet) `styleBasic`
[textFont "Regular", textColor white]
, remixIcon remixArrowRightWideLine `styleBasic` [textColor white]
]
accountButton =
hstack
[ label "Account: " `styleBasic` [textFont "Bold", textColor white]
, label (maybe "None" (zcashAccountName . entityVal) currentAccount) `styleBasic`
[textFont "Regular", textColor white]
, remixIcon remixArrowRightWideLine `styleBasic` [textColor white]
]
mainPane = box_ [alignMiddle] $ hstack [addressBox, txBox]
balanceBox =
box_
[alignMiddle]
(vstack
[ animFadeIn
(label (displayAmount (model ^. network) $ model ^. balance) `styleBasic`
[textSize 20])
, hstack
[ filler
, remixIcon remixHourglassFill `styleBasic` [textSize 8]
, label
(maybe "0" (displayAmount (model ^. network)) $
model ^. unconfBalance) `styleBasic`
[textSize 8] `nodeVisible`
isJust (model ^. unconfBalance)
, filler
]
])
addressBox =
box_
[alignMiddle]
(vstack
[ label "Addresses:" `styleBasic` [textFont "Regular"]
, vscroll (vstack (zipWith addrRow [0 ..] (model ^. addresses))) `nodeKey`
"addrScroll"
]) `styleBasic`
[border 1 whiteSmoke]
addrRow :: Int -> Entity WalletAddress -> WidgetNode AppModel AppEvent
addrRow idx wAddr =
box_
[onClick $ ShowMsg ("You clicked address " <> showt idx)]
(label
(walletAddressName (entityVal wAddr) <>
": " <> showAddress (walletAddressUAddress $ entityVal wAddr)))
txBox =
box_
[alignMiddle]
(vstack
[ label "Transactions:" `styleBasic` [textFont "Regular"]
, label "2024-04-05 0.003 ZEC" `styleBasic` [textFont "Regular"]
]) `styleBasic`
[border 1 whiteSmoke]
windowFooter =
hstack
[ label
("Last block sync: " <>
maybe "N/A" (showt . zcashWalletLastSync . entityVal) currentWallet) `styleBasic`
[padding 3, textSize 8]
, filler
, image_ "./assets/1F993.png" [fitHeight] `styleBasic`
[height 24, width 24] `nodeVisible`
(model ^. zebraOn)
, label
("Connected on " <>
c_zebraHost (model ^. configuration) <>
":" <> showt (c_zebraPort $ model ^. configuration)) `styleBasic`
[padding 3, textSize 8] `nodeVisible`
(model ^. zebraOn)
, label "Disconnected" `styleBasic` [padding 3, textSize 8] `nodeVisible`
not (model ^. zebraOn)
]
msgOverlay =
alert CloseMsg $
@ -63,6 +189,8 @@ handleEvent wenv node model evt =
case evt of
AppInit -> []
ShowMsg t -> [Model $ model & msg ?~ t]
WalletClicked -> [Model $ model & msg ?~ "You clicked Wallet!"]
AccountClicked -> [Model $ model & msg ?~ "You clicked Account!"]
CloseMsg -> [Model $ model & msg .~ Nothing]
runZenithGUI :: Config -> IO ()
@ -82,18 +210,65 @@ runZenithGUI config = do
Right chainInfo -> do
initDb dbFilePath
walList <- getWallets pool $ zgb_net chainInfo
let model = AppModel (zgb_net chainInfo) walList Nothing
accList <-
if not (null walList)
then runNoLoggingT $ getAccounts pool $ entityKey $ head walList
else return []
addrList <-
if not (null accList)
then runNoLoggingT $ getAddresses pool $ entityKey $ head accList
else return []
txList <-
if not (null addrList)
then getUserTx pool $ entityKey $ head addrList
else return []
let model =
AppModel
config
(zgb_net chainInfo)
walList
0
accList
0
addrList
0
txList
0
Nothing
True
314259000
(Just 300000)
startApp model handleEvent buildUI params
Left e ->
print $
"No Zebra node available on port " <>
show port <> ". Check your configuration."
Left e -> do
initDb dbFilePath
let model =
AppModel
config
TestNet
[]
0
[]
0
[]
0
[]
0
(Just $
"Couldn't connect to Zebra on " <>
host <> ":" <> showt port <> ". Check your configuration.")
False
314259000
(Just 30000)
startApp model handleEvent buildUI params
where
params =
[ appWindowTitle "Zenith - Zcash Full Node Wallet"
, appTheme darkTheme
, appFontDef "Regular" "./assets/DejaVuSansMono.ttf"
, appFontDef "Bold" "./assets/DejaVuSansMono-Bold.ttf"
, appFontDef "Italic" "./assets/DejaVuSansMono-Oblique.ttf"
, appTheme zenithTheme
, appFontDef "Regular" "./assets/Atkinson-Hyperlegible-Regular-102.ttf" --"./assets/DejaVuSansMono.ttf"
, appFontDef "Bold" "./assets/Atkinson-Hyperlegible-Bold-102.ttf"
, appFontDef "Italic" "./assets/Atkinson-Hyperlegible-Italic-102.ttf"
, appFontDef "Remix" "./assets/remixicon.ttf"
, appDisableAutoScale True
, appScaleFactor 2.0
, appInitEvent AppInit
]

183
src/Zenith/GUI/Theme.hs Normal file
View file

@ -0,0 +1,183 @@
{-# LANGUAGE OverloadedStrings #-}
module Zenith.GUI.Theme
( zenithTheme
) where
import Lens.Micro ((&), (+~), (.~), (?~), (^.), at, set)
import Monomer
import Monomer.Core.Themes.BaseTheme
import Monomer.Core.Themes.SampleThemes
import Monomer.Graphics (rgbHex, transparent)
import Monomer.Graphics.ColorTable
import qualified Monomer.Lens as L
zenithTheme :: Theme
zenithTheme =
baseTheme zenithThemeColors & L.basic . L.labelStyle . L.text ?~
TextStyle
Nothing
(Just . FontSize $ 10)
Nothing
Nothing
(Just whiteSmoke)
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing &
L.hover .
L.labelStyle . L.text ?~
TextStyle
Nothing
(Just . FontSize $ 10)
Nothing
Nothing
(Just whiteSmoke)
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
zenithThemeColors :: BaseThemeColors
zenithThemeColors =
BaseThemeColors
{ clearColor = gray01
, sectionColor = gray01
, btnFocusBorder = blue09
, btnBgBasic = gray07b
, btnBgHover = gray08
, btnBgFocus = gray07c
, btnBgActive = gray06
, btnBgDisabled = gray05
, btnText = gray02
, btnTextDisabled = gray01
, btnMainFocusBorder = blue08
, btnMainBgBasic = blue05b
, btnMainBgHover = blue06
, btnMainBgFocus = blue05c
, btnMainBgActive = blue05
, btnMainBgDisabled = blue04
, btnMainText = white
, btnMainTextDisabled = gray08
, dialogBg = gray01
, dialogBorder = gray01
, dialogText = white
, dialogTitleText = white
, emptyOverlay = gray05 & L.a .~ 0.8
, shadow = gray00 & L.a .~ 0.33
, externalLinkBasic = blue07
, externalLinkHover = blue08
, externalLinkFocus = blue07
, externalLinkActive = blue06
, externalLinkDisabled = gray06
, iconBg = gray08
, iconFg = gray01
, inputIconFg = black
, inputBorder = gray02
, inputFocusBorder = blue08
, inputBgBasic = gray04
, inputBgHover = gray06
, inputBgFocus = gray05
, inputBgActive = gray03
, inputBgDisabled = gray07
, inputFgBasic = gray06
, inputFgHover = blue08
, inputFgFocus = blue08
, inputFgActive = blue07
, inputFgDisabled = gray07
, inputSndBasic = gray05
, inputSndHover = gray06
, inputSndFocus = gray05
, inputSndActive = gray05
, inputSndDisabled = gray03
, inputHlBasic = gray07
, inputHlHover = blue08
, inputHlFocus = blue08
, inputHlActive = blue08
, inputHlDisabled = gray08
, inputSelBasic = gray06
, inputSelFocus = blue06
, inputText = white
, inputTextDisabled = gray02
, labelText = white
, scrollBarBasic = gray01 & L.a .~ 0.2
, scrollThumbBasic = gray07 & L.a .~ 0.6
, scrollBarHover = gray01 & L.a .~ 0.4
, scrollThumbHover = gray07 & L.a .~ 0.8
, slMainBg = gray00
, slNormalBgBasic = transparent
, slNormalBgHover = gray05
, slNormalText = white
, slNormalFocusBorder = blue08
, slSelectedBgBasic = gray04
, slSelectedBgHover = gray05
, slSelectedText = white
, slSelectedFocusBorder = blue08
, tooltipBorder = gray05
, tooltipBg = rgbHex "#1D212B"
, tooltipText = white
}
--black = rgbHex "#000000"
{-white = rgbHex "#FFFFFF"-}
blue01 = rgbHex "#002159"
blue02 = rgbHex "#01337D"
blue03 = rgbHex "#03449E"
blue04 = rgbHex "#0552B5"
blue05 = rgbHex "#0967D2"
blue05b = rgbHex "#0F6BD7"
blue05c = rgbHex "#1673DE"
blue06 = rgbHex "#2186EB"
blue06b = rgbHex "#2489EE"
blue06c = rgbHex "#2B8FF6"
blue07 = rgbHex "#47A3F3"
blue07b = rgbHex "#50A6F6"
blue07c = rgbHex "#57ACFC"
blue08 = rgbHex "#7CC4FA"
blue09 = rgbHex "#BAE3FF"
blue10 = rgbHex "#E6F6FF"
gray00 = rgbHex "#111111"
gray01 = rgbHex "#2E2E2E"
gray02 = rgbHex "#393939"
gray03 = rgbHex "#515151"
gray04 = rgbHex "#626262"
gray05 = rgbHex "#7E7E7E"
gray06 = rgbHex "#9E9E9E"
gray07 = rgbHex "#B1B1B1"
gray07b = rgbHex "#B4B4B4"
gray07c = rgbHex "#BBBBBB"
gray08 = rgbHex "#CFCFCF"
gray09 = rgbHex "#E1E1E1"
gray10 = rgbHex "#F7F7F7"

View file

@ -12,6 +12,7 @@ import System.Process (createProcess_, shell)
import Text.Regex.Posix
import ZcashHaskell.Orchard (encodeUnifiedAddress, isValidUnifiedAddress)
import ZcashHaskell.Sapling (isValidShieldedAddress)
import ZcashHaskell.Types (ZcashNet(..))
import Zenith.Types
( AddressGroup(..)
, UnifiedAddressDB(..)
@ -39,6 +40,12 @@ displayTaz s
| abs s < 100000000 = show (fromIntegral s / 100000) ++ " mTAZ "
| otherwise = show (fromIntegral s / 100000000) ++ " TAZ "
displayAmount :: ZcashNet -> Integer -> T.Text
displayAmount n a =
if n == MainNet
then T.pack $ displayZec a
else T.pack $ displayTaz a
-- | Helper function to display abbreviated Unified Address
showAddress :: UnifiedAddressDB -> T.Text
showAddress u = T.take 20 t <> "..."

View file

@ -28,6 +28,7 @@ library
exposed-modules:
Zenith.CLI
Zenith.GUI
Zenith.GUI.Theme
Zenith.Core
Zenith.DB
Zenith.Types