diff --git a/src/Zenith/GUI.hs b/src/Zenith/GUI.hs index 1fd9ead..932c07e 100644 --- a/src/Zenith/GUI.hs +++ b/src/Zenith/GUI.hs @@ -59,6 +59,7 @@ import Zenith.Utils , showAddress , validBarValue , validateAddressBool + , isValidString ) data AppEvent @@ -104,13 +105,15 @@ data AppEvent | CheckRecipient !T.Text | CheckAmount !Float | ShowTxId !T.Text + | LoadAbList ![Entity AddressBook] | ShowAdrBook | CloseAdrBook - | NewAdrBkEntry + | NewAdrBkEntry | CloseNewAdrBook - | NotImplemented + | NotImplemented | CloseMsgAB | CheckValidAddress !T.Text + | CheckValidDescrip !T.Text deriving (Eq, Show) data AppModel = AppModel @@ -155,9 +158,11 @@ data AppModel = AppModel , _home :: !FilePath , _showAdrBook :: !Bool , _newAdrBkEntry :: !Bool - , _abdescrip :: !(Maybe T.Text) + , _abdescrip :: !T.Text , _abaddress :: !T.Text , _abAddressValid :: !Bool + , _abDescripValid :: !Bool + , _abaddressList :: ![Entity AddressBook] , _msgAB :: !(Maybe T.Text) } deriving (Eq, Show) @@ -778,16 +783,35 @@ buildUI wenv model = widgetTree (label "Address Book" `styleBasic` [textFont "Bold", textSize 12, textColor white]) `styleBasic` [bgColor btnColor, radius 2, padding 3] + , boxShadow $ + box_ + [alignMiddle] + (vstack + [ vscroll (vstack (zipWith abookRow [0 ..] (model ^. abaddressList))) `nodeKey` "txScroll" + ]) `styleBasic` + [radius 2, padding 3, bgColor white] , spacer , hstack [ button "New" NewAdrBkEntry - , spacer + , spacer , button "Edit" notImplemented , spacer - , button "Copy" notImplemented - - ] + , button "Copy" notImplemented + ] ] + abookRow :: Int -> Entity AddressBook -> WidgetNode AppModel AppEvent + abookRow idx ab = + box_ + [onClick $ ShowTx idx, alignLeft] + (hstack + [ + (label "Descr: ") `styleBasic` [textFont "Bold"] + , spacer + , label + (T.pack $ + show (addressBookAbdescrip $ entityVal ab)) + ]) `styleBasic` + [padding 2, borderB 1 gray] newAdrBkOverlay = alert CloseNewAdrBook $ vstack @@ -800,11 +824,11 @@ buildUI wenv model = widgetTree , hstack [ label "Description: " `styleBasic` [width 80] , spacer - , textField_ sendRecipient [onChange CheckRecipient] `styleBasic` - [ width 320 --- , styleIf --- (not $ model ^. recipientValid) --- (textColor red) + , textField_ abdescrip [onChange CheckValidDescrip] `styleBasic` + [ width 320 + , styleIf + (not $ model ^. abDescripValid) + (textColor red) ] ] , spacer @@ -818,11 +842,11 @@ buildUI wenv model = widgetTree (textColor red) ] ] - , spacer + , spacer , hstack [ button "Save" NotImplemented `nodeEnabled` - (model ^. abAddressValid) - ] + ((model ^. abAddressValid) && (model ^. abDescripValid)) + ] ] msgAdrBookOverlay= alert CloseMsgAB $ @@ -1148,6 +1172,7 @@ handleEvent wenv node model evt = ] ShowTxId tx -> [Model $ model & showId ?~ tx & modalMsg .~ Nothing] CheckValidAddress a -> [Model $ model & abAddressValid .~ isRecipientValid a] + CheckValidDescrip a -> [Model $ model & abDescripValid .~ isValidString a] ShowAdrBook -> [Model $ model & showAdrBook .~ True & menuPopup .~ False] CloseAdrBook -> [Model $ model & showAdrBook .~ False] NewAdrBkEntry -> [Model $ model & newAdrBkEntry .~ True & menuPopup .~ False] @@ -1391,6 +1416,7 @@ runZenithGUI config = do if not (null accList) then getUnconfirmedBalance pool $ entityKey $ head accList else return 0 + abList <- getAdrBook pool (zgb_net chainInfo) let model = AppModel config @@ -1421,7 +1447,7 @@ runZenithGUI config = do "" (SaveAddress (if not (null accList) then Just (head accList) - else Nothing ) ) + else Nothing ) ) False False Nothing @@ -1438,9 +1464,11 @@ runZenithGUI config = do "" False False - Nothing + "" "" False + False + abList Nothing -- hD startApp model handleEvent buildUI (params hD) @@ -1491,10 +1519,12 @@ runZenithGUI config = do "" False False - Nothing + "" "" False - Nothing + False + [] + Nothing -- hD startApp model handleEvent buildUI (params hD) where diff --git a/src/Zenith/Utils.hs b/src/Zenith/Utils.hs index 61e0daa..84b3ab9 100644 --- a/src/Zenith/Utils.hs +++ b/src/Zenith/Utils.hs @@ -9,6 +9,7 @@ import Data.Ord (clamp) import Data.Scientific (Scientific(..), scientific) import qualified Data.Text as T import qualified Data.Text.Encoding as E +import Data.Char (isAlphaNum, isSpace) import System.Directory import System.Process (createProcess_, shell) import Text.Regex.Posix @@ -134,3 +135,21 @@ parseAddress a znet = Just a3 -> Just $ UnifiedAddress znet Nothing Nothing (Just $ ta_receiver a3) Nothing -> Nothing + +isValidContent :: String -> Bool +isValidContent [] = False -- an empty string is invalid +isValidContent (x:xs) + | not (isAlphaNum x ) = False -- string must start with an alphanumeric character + | otherwise = allValidChars xs -- process the rest of the string + where + allValidChars :: String -> Bool + allValidChars [] = True -- if we got here, string is valid + allValidChars (y:ys) + | isAlphaNum y || isSpace y = allValidChars ys -- char is valid, continue + | otherwise = False -- found an invalid character, return false + +isValidString :: T.Text -> Bool +isValidString c = do + let a = T.unpack c + isValidContent a +