diff --git a/src/Zenith/GUI.hs b/src/Zenith/GUI.hs index fa96cbc..3a6e4b5 100644 --- a/src/Zenith/GUI.hs +++ b/src/Zenith/GUI.hs @@ -54,6 +54,8 @@ import Zenith.Utils , getZenithPath , isEmpty , isRecipientValid + , isRecipientValidGUI + , isZecAddressValid , isValidString , jsonNumber , padWithZero @@ -125,6 +127,7 @@ data AppEvent | CopyABAdress !T.Text | DeleteABEntry !T.Text | UpdateABDescrip !T.Text !T.Text + | ResetRecipientValid deriving (Eq, Show) data AppModel = AppModel @@ -605,8 +608,29 @@ buildUI wenv model = widgetTree [textFont "Bold", textSize 12]) , separatorLine `styleBasic` [fgColor btnColor] , spacer + , hstack + [ + label "Privacy Level:" `styleBasic` [width 70, textFont "Bold"] + , spacer + , label "Full " `styleBasic` [width 40] + , radio Full privacyChoice + , spacer + , label "Medium " `styleBasic` [width 40] + , radio Medium privacyChoice + ] + , hstack + [ + label " " `styleBasic` [width 70, textFont "Bold"] + , spacer + , label "Low " `styleBasic` [width 40] + , radio Low privacyChoice + , spacer + , label "None " `styleBasic` [width 40] + , radio None privacyChoice + ] + , spacer , hstack - [ label "To:" `styleBasic` [width 50] + [ label "To:" `styleBasic` [width 50, textFont "Bold"] , spacer , textField_ sendRecipient [onChange CheckRecipient] `styleBasic` [ width 150 @@ -616,7 +640,7 @@ buildUI wenv model = widgetTree ] ] , hstack - [ label "Amount:" `styleBasic` [width 50] + [ label "Amount:" `styleBasic` [width 50, textFont "Bold"] , spacer , numericField_ sendAmount @@ -634,35 +658,13 @@ buildUI wenv model = widgetTree ] ] , hstack - [ label "Memo:" `styleBasic` [width 50] + [ label "Memo:" `styleBasic` [width 50, textFont "Bold"] , spacer , textArea sendMemo `styleBasic` [width 150, height 40] ] , spacer -- Radio button group for privacy level - , hstack - [ - label "Privacy Level:" `styleBasic` [width 70] - , spacer - , label "None " `styleBasic` [width 40] - , radio None privacyChoice - , spacer - , label "Low " `styleBasic` [width 40] - , radio Low privacyChoice - - ] - , hstack - [ - label " " `styleBasic` [width 70] - , spacer - , label "Medium " `styleBasic` [width 40] - , radio Medium privacyChoice - , spacer - , label "Full " `styleBasic` [width 40] - , radio Full privacyChoice - ] - , spacer , box_ [alignMiddle] (hstack @@ -1080,7 +1082,7 @@ handleEvent wenv node model evt = ] ConfirmCancel -> [Model $ model & confirmTitle .~ Nothing & mainInput .~ ""] ShowSeed -> [Model $ model & showSeed .~ True & menuPopup .~ False] - ShowSend -> [Model $ model & openSend .~ True] + ShowSend -> [Model $ model & openSend .~ True & privacyChoice .~ Full & recipientValid .~ False] SendTx -> case currentAccount of Nothing -> [Event $ ShowError "No account available", Event CancelSend] @@ -1261,7 +1263,10 @@ handleEvent wenv node model evt = ("Wallet Sync: " <> T.pack (printf "%.2f%%" (model ^. barValue * 100))) ] - CheckRecipient a -> [Model $ model & recipientValid .~ isRecipientValid a] + ResetRecipientValid -> [Model $ model & recipientValid .~ False] + CheckRecipient a -> [Model $ + model & recipientValid .~ isRecipientValidGUI (model ^.privacyChoice) a ] +-- model & recipientValid .~ ((model ^. privacyChoice) == Low) ] CheckAmount i -> [ Model $ model & amountValid .~ @@ -1272,7 +1277,7 @@ handleEvent wenv node model evt = -- | Address Book Events -- | CheckValidAddress a -> - [Model $ model & abAddressValid .~ isRecipientValid a] + [Model $ model & abAddressValid .~ isZecAddressValid a] CheckValidDescrip a -> [Model $ model & abDescripValid .~ isValidString a] ShowAdrBook -> if null (model ^. abaddressList) @@ -1673,7 +1678,7 @@ runZenithGUI config = do Nothing False False - None + Full startApp model handleEvent buildUI (params hD) Left _e -> print "Zebra not available" where diff --git a/src/Zenith/Utils.hs b/src/Zenith/Utils.hs index ff06973..e23a0ab 100644 --- a/src/Zenith/Utils.hs +++ b/src/Zenith/Utils.hs @@ -24,12 +24,15 @@ import ZcashHaskell.Types , TransparentAddress(..) , UnifiedAddress(..) , ZcashNet(..) + , ValidAddress(..) + , ExchangeAddress(..) ) import Zenith.Types ( AddressGroup(..) , UnifiedAddressDB(..) , ZcashAddress(..) , ZcashPool(..) + , PrivacyPolicy(..) ) -- | Helper function to convert numbers into JSON @@ -71,8 +74,8 @@ getAddresses ag = agtransparent ag <> agsapling ag <> agunified ag -- | Helper function to validate potential Zcash addresses validateAddress :: T.Text -> Maybe ZcashPool validateAddress txt --(tReg || sReg && isJust chk) || (uReg && isJust chk) - | tReg = Just Transparent - | sReg && chkS = Just Sapling + | tReg = Just Zenith.Types.Transparent + | sReg && chkS = Just Zenith.Types.Sapling | uReg && chk = Just Orchard | otherwise = Nothing where @@ -110,7 +113,64 @@ validBarValue :: Float -> Float validBarValue = clamp (0, 1) isRecipientValid :: T.Text -> Bool -isRecipientValid a = +isRecipientValid a = do + case isValidUnifiedAddress (E.encodeUtf8 a) of + Just _a1 -> True + Nothing -> + isValidShieldedAddress (E.encodeUtf8 a) || + (case decodeTransparentAddress (E.encodeUtf8 a) of + Just _a3 -> True + Nothing -> + case decodeExchangeAddress (E.encodeUtf8 a) of + Just _a4 -> True + Nothing -> False) + +isUnifiedAddressValid :: T.Text -> Bool +isUnifiedAddressValid ua = + case isValidUnifiedAddress (E.encodeUtf8 ua) of + Just _a1 -> True + Nothing -> False + +isSaplingAddressValid :: T.Text -> Bool +isSaplingAddressValid sa = isValidShieldedAddress (E.encodeUtf8 sa) + +isTransparentAddressValid :: T.Text -> Bool +isTransparentAddressValid ta = + case decodeTransparentAddress (E.encodeUtf8 ta) of + Just _a3 -> True + Nothing -> False + +isExchangeAddressValid :: T.Text -> Bool +isExchangeAddressValid xa = + case decodeExchangeAddress (E.encodeUtf8 xa) of + Just _a4 -> True + Nothing -> False + +isRecipientValidGUI :: PrivacyPolicy -> T.Text -> Bool +isRecipientValidGUI p a = do + case (parseAddress a) of + Just a1 -> + case p of + Full -> case a1 of + Unified ua -> True + ZcashHaskell.Types.Sapling sa -> True + _ -> False + Medium -> case a1 of + Unified ua -> True + ZcashHaskell.Types.Sapling sa -> True + _ -> False + Low -> case a1 of + Unified ua -> True + ZcashHaskell.Types.Sapling sa -> True + ZcashHaskell.Types.Transparent ta -> True + Exchange ea -> True + None -> case a1 of + ZcashHaskell.Types.Transparent ta -> True + Exchange ea -> True + _ -> False + +isZecAddressValid :: T.Text -> Bool +isZecAddressValid a = do case isValidUnifiedAddress (E.encodeUtf8 a) of Just _a1 -> True Nothing -> @@ -138,27 +198,27 @@ parseAddress a znet = isValidContent :: String -> Bool isValidContent [] = False -- an empty string is invalid -isValidContent (x:xs) +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 :: String -> Bool allValidChars [] = True -- if we got here, string is valid - allValidChars (y:ys) + 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 +isValidString c = do let a = T.unpack c isValidContent a padWithZero :: Int -> String -> String -padWithZero n s - | (length s) >= n = s +padWithZero n s + | (length s) >= n = s | otherwise = padWithZero n ("0" ++ s) isEmpty :: [a] -> Bool isEmpty [] = True isEmpty _ = False - +