{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE StrictData #-} {-# LANGUAGE TemplateHaskell #-} module Simplex.Chat.AppSettings where import Control.Applicative ((<|>)) import Data.Aeson (FromJSON (..), (.:?)) import qualified Data.Aeson as J import qualified Data.Aeson.TH as JQ import Data.Map.Strict (Map) import Data.Maybe (fromMaybe) import Data.Text (Text) import Simplex.Chat.Types.UITheme import Simplex.Messaging.Client (NetworkConfig, defaultNetworkConfig) import Simplex.Messaging.Parsers (defaultJSON, dropPrefix, enumJSON) import Simplex.Messaging.Util (catchAll_) data AppPlatform = APIOS | APAndroid | APDesktop deriving (Show) data NotificationMode = NMOff | NMPeriodic | NMInstant deriving (Show) data NotificationPreviewMode = NPMHidden | NPMContact | NPMMessage deriving (Show) data LockScreenCalls = LSCDisable | LSCShow | LSCAccept deriving (Show) data AppSettings = AppSettings { appPlatform :: Maybe AppPlatform, networkConfig :: Maybe NetworkConfig, networkProxy :: Maybe NetworkProxy, privacyEncryptLocalFiles :: Maybe Bool, privacyAskToApproveRelays :: Maybe Bool, privacyAcceptImages :: Maybe Bool, privacyLinkPreviews :: Maybe Bool, privacyShowChatPreviews :: Maybe Bool, privacySaveLastDraft :: Maybe Bool, privacyProtectScreen :: Maybe Bool, privacyMediaBlurRadius :: Maybe Int, notificationMode :: Maybe NotificationMode, notificationPreviewMode :: Maybe NotificationPreviewMode, webrtcPolicyRelay :: Maybe Bool, webrtcICEServers :: Maybe [Text], confirmRemoteSessions :: Maybe Bool, connectRemoteViaMulticast :: Maybe Bool, connectRemoteViaMulticastAuto :: Maybe Bool, developerTools :: Maybe Bool, confirmDBUpgrades :: Maybe Bool, androidCallOnLockScreen :: Maybe LockScreenCalls, iosCallKitEnabled :: Maybe Bool, iosCallKitCallsInRecents :: Maybe Bool, uiProfileImageCornerRadius :: Maybe Double, uiChatItemRoundness :: Maybe Double, uiChatItemTail :: Maybe Bool, uiColorScheme :: Maybe UIColorScheme, uiDarkColorScheme :: Maybe DarkColorScheme, uiCurrentThemeIds :: Maybe (Map ThemeColorScheme Text), uiThemes :: Maybe [UITheme], oneHandUI :: Maybe Bool, chatBottomBar :: Maybe Bool } deriving (Show) data NetworkProxy = NetworkProxy { host :: Text, port :: Int, auth :: NetworkProxyAuth, username :: Text, password :: Text } deriving (Show) data NetworkProxyAuth = NPAUsername | NPAIsolate deriving (Show) defaultAppSettings :: AppSettings defaultAppSettings = AppSettings { appPlatform = Nothing, networkConfig = Just defaultNetworkConfig, networkProxy = Nothing, privacyEncryptLocalFiles = Just True, privacyAskToApproveRelays = Just True, privacyAcceptImages = Just True, privacyLinkPreviews = Just True, privacyShowChatPreviews = Just True, privacySaveLastDraft = Just True, privacyProtectScreen = Just False, privacyMediaBlurRadius = Just 0, notificationMode = Just NMInstant, notificationPreviewMode = Just NPMMessage, webrtcPolicyRelay = Just True, webrtcICEServers = Just [], confirmRemoteSessions = Just False, connectRemoteViaMulticast = Just True, connectRemoteViaMulticastAuto = Just True, developerTools = Just False, confirmDBUpgrades = Just False, androidCallOnLockScreen = Just LSCShow, iosCallKitEnabled = Just True, iosCallKitCallsInRecents = Just False, uiProfileImageCornerRadius = Just 22.5, uiChatItemRoundness = Just 0.75, uiChatItemTail = Just True, uiColorScheme = Just UCSSystem, uiDarkColorScheme = Just DCSSimplex, uiCurrentThemeIds = Nothing, uiThemes = Nothing, oneHandUI = Just True, chatBottomBar = Just True } defaultParseAppSettings :: AppSettings defaultParseAppSettings = AppSettings { appPlatform = Nothing, networkConfig = Nothing, networkProxy = Nothing, privacyEncryptLocalFiles = Nothing, privacyAskToApproveRelays = Nothing, privacyAcceptImages = Nothing, privacyLinkPreviews = Nothing, privacyShowChatPreviews = Nothing, privacySaveLastDraft = Nothing, privacyProtectScreen = Nothing, privacyMediaBlurRadius = Nothing, notificationMode = Nothing, notificationPreviewMode = Nothing, webrtcPolicyRelay = Nothing, webrtcICEServers = Nothing, confirmRemoteSessions = Nothing, connectRemoteViaMulticast = Nothing, connectRemoteViaMulticastAuto = Nothing, developerTools = Nothing, confirmDBUpgrades = Nothing, androidCallOnLockScreen = Nothing, iosCallKitEnabled = Nothing, iosCallKitCallsInRecents = Nothing, uiProfileImageCornerRadius = Nothing, uiChatItemRoundness = Nothing, uiChatItemTail = Nothing, uiColorScheme = Nothing, uiDarkColorScheme = Nothing, uiCurrentThemeIds = Nothing, uiThemes = Nothing, oneHandUI = Nothing, chatBottomBar = Nothing } combineAppSettings :: AppSettings -> AppSettings -> AppSettings combineAppSettings platformDefaults storedSettings = AppSettings { appPlatform = p appPlatform, networkConfig = p networkConfig, networkProxy = p networkProxy, privacyEncryptLocalFiles = p privacyEncryptLocalFiles, privacyAskToApproveRelays = p privacyAskToApproveRelays, privacyAcceptImages = p privacyAcceptImages, privacyLinkPreviews = p privacyLinkPreviews, privacyShowChatPreviews = p privacyShowChatPreviews, privacySaveLastDraft = p privacySaveLastDraft, privacyProtectScreen = p privacyProtectScreen, privacyMediaBlurRadius = p privacyMediaBlurRadius, notificationMode = p notificationMode, notificationPreviewMode = p notificationPreviewMode, webrtcPolicyRelay = p webrtcPolicyRelay, webrtcICEServers = p webrtcICEServers, confirmRemoteSessions = p confirmRemoteSessions, connectRemoteViaMulticast = p connectRemoteViaMulticast, connectRemoteViaMulticastAuto = p connectRemoteViaMulticastAuto, developerTools = p developerTools, confirmDBUpgrades = p confirmDBUpgrades, iosCallKitEnabled = p iosCallKitEnabled, iosCallKitCallsInRecents = p iosCallKitCallsInRecents, androidCallOnLockScreen = p androidCallOnLockScreen, uiProfileImageCornerRadius = p uiProfileImageCornerRadius, uiChatItemRoundness = p uiChatItemRoundness, uiChatItemTail = p uiChatItemTail, uiColorScheme = p uiColorScheme, uiDarkColorScheme = p uiDarkColorScheme, uiCurrentThemeIds = p uiCurrentThemeIds, uiThemes = p uiThemes, oneHandUI = p oneHandUI, chatBottomBar = p chatBottomBar } where p :: (AppSettings -> Maybe a) -> Maybe a p sel = sel storedSettings <|> sel platformDefaults <|> sel defaultAppSettings $(JQ.deriveJSON (enumJSON $ dropPrefix "AP") ''AppPlatform) $(JQ.deriveJSON (enumJSON $ dropPrefix "NM") ''NotificationMode) $(JQ.deriveJSON (enumJSON $ dropPrefix "NPM") ''NotificationPreviewMode) $(JQ.deriveJSON (enumJSON $ dropPrefix "LSC") ''LockScreenCalls) $(JQ.deriveJSON (enumJSON $ dropPrefix "NPA") ''NetworkProxyAuth) $(JQ.deriveJSON defaultJSON ''NetworkProxy) $(JQ.deriveToJSON defaultJSON ''AppSettings) instance FromJSON AppSettings where parseJSON (J.Object v) = do appPlatform <- p "appPlatform" networkConfig <- p "networkConfig" networkProxy <- p "networkProxy" privacyEncryptLocalFiles <- p "privacyEncryptLocalFiles" privacyAskToApproveRelays <- p "privacyAskToApproveRelays" privacyAcceptImages <- p "privacyAcceptImages" privacyLinkPreviews <- p "privacyLinkPreviews" privacyShowChatPreviews <- p "privacyShowChatPreviews" privacySaveLastDraft <- p "privacySaveLastDraft" privacyProtectScreen <- p "privacyProtectScreen" privacyMediaBlurRadius <- p "privacyMediaBlurRadius" notificationMode <- p "notificationMode" notificationPreviewMode <- p "notificationPreviewMode" webrtcPolicyRelay <- p "webrtcPolicyRelay" webrtcICEServers <- p "webrtcICEServers" confirmRemoteSessions <- p "confirmRemoteSessions" connectRemoteViaMulticast <- p "connectRemoteViaMulticast" connectRemoteViaMulticastAuto <- p "connectRemoteViaMulticastAuto" developerTools <- p "developerTools" confirmDBUpgrades <- p "confirmDBUpgrades" iosCallKitEnabled <- p "iosCallKitEnabled" iosCallKitCallsInRecents <- p "iosCallKitCallsInRecents" androidCallOnLockScreen <- p "androidCallOnLockScreen" uiProfileImageCornerRadius <- p "uiProfileImageCornerRadius" uiChatItemRoundness <- p "uiChatItemRoundness" uiChatItemTail <- p "uiChatItemTail" uiColorScheme <- p "uiColorScheme" uiDarkColorScheme <- p "uiDarkColorScheme" uiCurrentThemeIds <- p "uiCurrentThemeIds" uiThemes <- p "uiThemes" oneHandUI <- p "oneHandUI" chatBottomBar <- p "chatBottomBar" pure AppSettings { appPlatform, networkConfig, networkProxy, privacyEncryptLocalFiles, privacyAskToApproveRelays, privacyAcceptImages, privacyLinkPreviews, privacyShowChatPreviews, privacySaveLastDraft, privacyProtectScreen, privacyMediaBlurRadius, notificationMode, notificationPreviewMode, webrtcPolicyRelay, webrtcICEServers, confirmRemoteSessions, connectRemoteViaMulticast, connectRemoteViaMulticastAuto, developerTools, confirmDBUpgrades, iosCallKitEnabled, iosCallKitCallsInRecents, androidCallOnLockScreen, uiProfileImageCornerRadius, uiChatItemRoundness, uiChatItemTail, uiColorScheme, uiDarkColorScheme, uiCurrentThemeIds, uiThemes, oneHandUI, chatBottomBar } where p key = v .:? key <|> pure Nothing parseJSON _ = pure defaultParseAppSettings readAppSettings :: FilePath -> Maybe AppSettings -> IO AppSettings readAppSettings f platformDefaults = combineAppSettings (fromMaybe defaultAppSettings platformDefaults) . fromMaybe defaultParseAppSettings <$> (J.decodeFileStrict f `catchAll_` pure Nothing)