{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ViewPatterns #-}
module Navi.Services.Battery.Percentage.Toml
( BatteryPercentageToml (..),
BatteryPercentageNoteToml (..),
PercentageData (..),
)
where
import DBus.Notify (UrgencyLevel)
import Data.List.NonEmpty qualified as NE
import Data.Set (Set)
import Data.Set qualified as Set
import Data.Text qualified as T
import Navi.Data.NaviNote (Timeout, timeoutOptDecoder)
import Navi.Data.PollInterval (PollInterval, pollIntervalOptDecoder)
import Navi.Event.Toml
( ErrorNoteToml,
MultiRepeatEventToml (MultiSomeRepeatsToml),
errorNoteOptDecoder,
multiRepeatEventOptDecoder,
)
import Navi.Prelude
import Navi.Services.Battery.Common (batteryAppDecoder)
import Navi.Utils (urgencyLevelOptDecoder)
import Pythia.Data.Percentage (mkPercentage, _MkPercentage)
import Pythia.Data.Percentage qualified as Percentage
import Pythia.Services.Battery (BatteryApp, Percentage)
data PercentageData
=
PercentageExact Percentage
|
PercentageRange Percentage Percentage
deriving stock (Int -> PercentageData -> ShowS
[PercentageData] -> ShowS
PercentageData -> String
(Int -> PercentageData -> ShowS)
-> (PercentageData -> String)
-> ([PercentageData] -> ShowS)
-> Show PercentageData
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PercentageData -> ShowS
showsPrec :: Int -> PercentageData -> ShowS
$cshow :: PercentageData -> String
show :: PercentageData -> String
$cshowList :: [PercentageData] -> ShowS
showList :: [PercentageData] -> ShowS
Show)
instance Eq PercentageData where
PercentageData
x == :: PercentageData -> PercentageData -> Bool
== PercentageData
y = PercentageData -> Percentage
toPercentage PercentageData
x Percentage -> Percentage -> Bool
forall a. Eq a => a -> a -> Bool
== PercentageData -> Percentage
toPercentage PercentageData
y
instance Ord PercentageData where
PercentageData
x <= :: PercentageData -> PercentageData -> Bool
<= PercentageData
y = PercentageData -> Percentage
toPercentage PercentageData
x Percentage -> Percentage -> Bool
forall a. Ord a => a -> a -> Bool
<= PercentageData -> Percentage
toPercentage PercentageData
y
toPercentage :: PercentageData -> Percentage
toPercentage :: PercentageData -> Percentage
toPercentage (PercentageExact Percentage
p) = Percentage
p
toPercentage (PercentageRange Percentage
l Percentage
_) = Percentage
l
data BatteryPercentageNoteToml = MkBatteryPercentageNoteToml
{
BatteryPercentageNoteToml -> PercentageData
percentage :: PercentageData,
BatteryPercentageNoteToml -> Maybe UrgencyLevel
urgency :: Maybe UrgencyLevel,
BatteryPercentageNoteToml -> Maybe Timeout
mTimeout :: Maybe Timeout
}
deriving stock (BatteryPercentageNoteToml -> BatteryPercentageNoteToml -> Bool
(BatteryPercentageNoteToml -> BatteryPercentageNoteToml -> Bool)
-> (BatteryPercentageNoteToml -> BatteryPercentageNoteToml -> Bool)
-> Eq BatteryPercentageNoteToml
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BatteryPercentageNoteToml -> BatteryPercentageNoteToml -> Bool
== :: BatteryPercentageNoteToml -> BatteryPercentageNoteToml -> Bool
$c/= :: BatteryPercentageNoteToml -> BatteryPercentageNoteToml -> Bool
/= :: BatteryPercentageNoteToml -> BatteryPercentageNoteToml -> Bool
Eq, Int -> BatteryPercentageNoteToml -> ShowS
[BatteryPercentageNoteToml] -> ShowS
BatteryPercentageNoteToml -> String
(Int -> BatteryPercentageNoteToml -> ShowS)
-> (BatteryPercentageNoteToml -> String)
-> ([BatteryPercentageNoteToml] -> ShowS)
-> Show BatteryPercentageNoteToml
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BatteryPercentageNoteToml -> ShowS
showsPrec :: Int -> BatteryPercentageNoteToml -> ShowS
$cshow :: BatteryPercentageNoteToml -> String
show :: BatteryPercentageNoteToml -> String
$cshowList :: [BatteryPercentageNoteToml] -> ShowS
showList :: [BatteryPercentageNoteToml] -> ShowS
Show)
makeFieldLabelsNoPrefix ''BatteryPercentageNoteToml
instance DecodeTOML BatteryPercentageNoteToml where
tomlDecoder :: Decoder BatteryPercentageNoteToml
tomlDecoder = do
PercentageData
percentage <- Decoder PercentageData
percentageDataDecoder
Maybe Timeout
mTimeout <- Decoder (Maybe Timeout)
timeoutOptDecoder
Maybe UrgencyLevel
urgency <- Decoder (Maybe UrgencyLevel)
urgencyLevelOptDecoder
pure
$ MkBatteryPercentageNoteToml
{ PercentageData
percentage :: PercentageData
percentage :: PercentageData
percentage,
Maybe Timeout
mTimeout :: Maybe Timeout
mTimeout :: Maybe Timeout
mTimeout,
Maybe UrgencyLevel
urgency :: Maybe UrgencyLevel
urgency :: Maybe UrgencyLevel
urgency
}
percentageDataDecoder :: Decoder PercentageData
percentageDataDecoder :: Decoder PercentageData
percentageDataDecoder = do
Maybe PercentageData
mExact <- Decoder (Maybe PercentageData)
exactDecoder
Maybe PercentageData
mRange <- Decoder (Maybe PercentageData)
rangeDecoder
case (Maybe PercentageData
mExact, Maybe PercentageData
mRange) of
(Just PercentageData
exact, Maybe PercentageData
Nothing) -> PercentageData -> Decoder PercentageData
forall a. a -> Decoder a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure PercentageData
exact
(Maybe PercentageData
Nothing, Just PercentageData
range) -> PercentageData -> Decoder PercentageData
forall a. a -> Decoder a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure PercentageData
range
(Just PercentageData
_, Just PercentageData
_) -> String -> Decoder PercentageData
forall a. String -> Decoder a
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail String
"Expected 'percent' or ('lower' and 'upper'), not both!"
(Maybe PercentageData
Nothing, Maybe PercentageData
Nothing) -> String -> Decoder PercentageData
forall a. String -> Decoder a
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail String
"Expected 'percent' or ('lower' and 'upper'), received neither!"
exactDecoder :: Decoder (Maybe PercentageData)
exactDecoder :: Decoder (Maybe PercentageData)
exactDecoder = (Percentage -> PercentageData)
-> Maybe Percentage -> Maybe PercentageData
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap Percentage -> PercentageData
PercentageExact (Maybe Percentage -> Maybe PercentageData)
-> Decoder (Maybe Percentage) -> Decoder (Maybe PercentageData)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Decoder Percentage -> Text -> Decoder (Maybe Percentage)
forall a. Decoder a -> Text -> Decoder (Maybe a)
getFieldOptWith Decoder Percentage
percentageDecoder Text
"percent"
rangeDecoder :: Decoder (Maybe PercentageData)
rangeDecoder :: Decoder (Maybe PercentageData)
rangeDecoder = do
Maybe Percentage
mLow <- Decoder Percentage -> Text -> Decoder (Maybe Percentage)
forall a. Decoder a -> Text -> Decoder (Maybe a)
getFieldOptWith Decoder Percentage
percentageDecoder Text
"lower"
Maybe Percentage
mHigh <- Decoder Percentage -> Text -> Decoder (Maybe Percentage)
forall a. Decoder a -> Text -> Decoder (Maybe a)
getFieldOptWith Decoder Percentage
percentageDecoder Text
"upper"
case (Maybe Percentage
mLow, Maybe Percentage
mHigh) of
(Just Percentage
low, Just Percentage
high) -> do
let msg :: String
msg =
Text -> String
unpackText
(Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ [Text] -> Text
forall a. Monoid a => [a] -> a
mconcat
[ Text
"Percentage 'upper = ",
Percentage -> Text
forall a. Display a => a -> Text
display Percentage
high,
Text
"' < 'lower = ",
Percentage -> Text
forall a. Display a => a -> Text
display Percentage
low,
Text
"'."
]
Bool -> Decoder () -> Decoder ()
forall (f :: Type -> Type). Applicative f => Bool -> f () -> f ()
when (Percentage
high Percentage -> Percentage -> Bool
forall a. Ord a => a -> a -> Bool
< Percentage
low) (Decoder () -> Decoder ()) -> Decoder () -> Decoder ()
forall a b. (a -> b) -> a -> b
$ String -> Decoder ()
forall a. String -> Decoder a
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail String
msg
pure $ PercentageData -> Maybe PercentageData
forall a. a -> Maybe a
Just (PercentageData -> Maybe PercentageData)
-> PercentageData -> Maybe PercentageData
forall a b. (a -> b) -> a -> b
$ Percentage -> Percentage -> PercentageData
PercentageRange Percentage
low Percentage
high
(Maybe Percentage, Maybe Percentage)
_ -> Maybe PercentageData -> Decoder (Maybe PercentageData)
forall a. a -> Decoder a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Maybe PercentageData
forall a. Maybe a
Nothing
percentageDecoder :: Decoder Percentage
percentageDecoder :: Decoder Percentage
percentageDecoder =
Decoder Word8
forall a. DecodeTOML a => Decoder a
tomlDecoder Decoder Word8
-> (Word8 -> Decoder Percentage) -> Decoder Percentage
forall a b. Decoder a -> (a -> Decoder b) -> Decoder b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Word8
x ->
case Word8 -> Maybe Percentage
Percentage.mkPercentage Word8
x of
Just Percentage
n -> Percentage -> Decoder Percentage
forall a. a -> Decoder a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Percentage
n
Maybe Percentage
Nothing ->
String -> Decoder Percentage
forall a. String -> Decoder a
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail
(String -> Decoder Percentage) -> String -> Decoder Percentage
forall a b. (a -> b) -> a -> b
$ Text -> String
unpackText
(Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ [Text] -> Text
forall a. Monoid a => [a] -> a
mconcat
[ Text
"Unexpected percent: ",
Word8 -> Text
forall a. Show a => a -> Text
showt Word8
x,
Text
". Expected integer in [0, 100]."
]
data BatteryPercentageToml = MkBatteryPercentageToml
{
BatteryPercentageToml -> NonEmpty BatteryPercentageNoteToml
alerts :: NonEmpty BatteryPercentageNoteToml,
BatteryPercentageToml -> BatteryApp
app :: BatteryApp,
BatteryPercentageToml -> Maybe ErrorNoteToml
errorNote :: Maybe ErrorNoteToml,
BatteryPercentageToml -> Maybe PollInterval
pollInterval :: Maybe PollInterval,
BatteryPercentageToml -> Maybe (MultiRepeatEventToml Percentage)
repeatEvent :: Maybe (MultiRepeatEventToml Percentage)
}
deriving stock (BatteryPercentageToml -> BatteryPercentageToml -> Bool
(BatteryPercentageToml -> BatteryPercentageToml -> Bool)
-> (BatteryPercentageToml -> BatteryPercentageToml -> Bool)
-> Eq BatteryPercentageToml
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BatteryPercentageToml -> BatteryPercentageToml -> Bool
== :: BatteryPercentageToml -> BatteryPercentageToml -> Bool
$c/= :: BatteryPercentageToml -> BatteryPercentageToml -> Bool
/= :: BatteryPercentageToml -> BatteryPercentageToml -> Bool
Eq, Int -> BatteryPercentageToml -> ShowS
[BatteryPercentageToml] -> ShowS
BatteryPercentageToml -> String
(Int -> BatteryPercentageToml -> ShowS)
-> (BatteryPercentageToml -> String)
-> ([BatteryPercentageToml] -> ShowS)
-> Show BatteryPercentageToml
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BatteryPercentageToml -> ShowS
showsPrec :: Int -> BatteryPercentageToml -> ShowS
$cshow :: BatteryPercentageToml -> String
show :: BatteryPercentageToml -> String
$cshowList :: [BatteryPercentageToml] -> ShowS
showList :: [BatteryPercentageToml] -> ShowS
Show)
makeFieldLabelsNoPrefix ''BatteryPercentageToml
instance DecodeTOML BatteryPercentageToml where
tomlDecoder :: Decoder BatteryPercentageToml
tomlDecoder = do
NonEmpty BatteryPercentageNoteToml
alerts <- Decoder (NonEmpty BatteryPercentageNoteToml)
-> Text -> Decoder (NonEmpty BatteryPercentageNoteToml)
forall a. Decoder a -> Text -> Decoder a
getFieldWith Decoder (NonEmpty BatteryPercentageNoteToml)
forall a. DecodeTOML a => Decoder a
tomlDecoder Text
"alert"
BatteryApp
app <- Decoder BatteryApp -> Text -> Decoder BatteryApp
forall a. Decoder a -> Text -> Decoder a
getFieldWith Decoder BatteryApp
batteryAppDecoder Text
"app"
Maybe ErrorNoteToml
errorNote <- Decoder (Maybe ErrorNoteToml)
errorNoteOptDecoder
Maybe PollInterval
pollInterval <- Decoder (Maybe PollInterval)
pollIntervalOptDecoder
Maybe (MultiRepeatEventToml Percentage)
repeatEvent <- (Value -> DecodeM Percentage)
-> Decoder (Maybe (MultiRepeatEventToml Percentage))
forall a.
Ord a =>
(Value -> DecodeM a) -> Decoder (Maybe (MultiRepeatEventToml a))
multiRepeatEventOptDecoder Value -> DecodeM Percentage
decodePercentage
case Maybe (MultiRepeatEventToml Percentage)
repeatEvent of
Just (MultiSomeRepeatsToml Set Percentage
percentRefs) -> do
let alertsPercents :: Set Percentage
alertsPercents = NonEmpty BatteryPercentageNoteToml -> Set Percentage
mkAlertPercents NonEmpty BatteryPercentageNoteToml
alerts
d :: Set Percentage
d = Set Percentage -> Set Percentage -> Set Percentage
forall a. Ord a => Set a -> Set a -> Set a
Set.difference Set Percentage
percentRefs Set Percentage
alertsPercents
msg :: String
msg =
[String] -> String
forall a. Monoid a => [a] -> a
mconcat
[ String
"Found repeat-events that referenced non-extant alert ",
String
"percentages. All references should correspond to an alert ",
String
"'percent' or 'lower': ",
Set Percentage -> String
showSet Set Percentage
d
]
Bool -> Decoder () -> Decoder ()
forall (f :: Type -> Type). Applicative f => Bool -> f () -> f ()
unless (Set Percentage -> Bool
forall a. Set a -> Bool
Set.null Set Percentage
d) (Decoder () -> Decoder ()) -> Decoder () -> Decoder ()
forall a b. (a -> b) -> a -> b
$ String -> Decoder ()
forall a. String -> Decoder a
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail String
msg
Maybe (MultiRepeatEventToml Percentage)
_ -> () -> Decoder ()
forall a. a -> Decoder a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure ()
pure
$ MkBatteryPercentageToml
{ NonEmpty BatteryPercentageNoteToml
alerts :: NonEmpty BatteryPercentageNoteToml
alerts :: NonEmpty BatteryPercentageNoteToml
alerts,
BatteryApp
app :: BatteryApp
app :: BatteryApp
app,
Maybe ErrorNoteToml
errorNote :: Maybe ErrorNoteToml
errorNote :: Maybe ErrorNoteToml
errorNote,
Maybe PollInterval
pollInterval :: Maybe PollInterval
pollInterval :: Maybe PollInterval
pollInterval,
Maybe (MultiRepeatEventToml Percentage)
repeatEvent :: Maybe (MultiRepeatEventToml Percentage)
repeatEvent :: Maybe (MultiRepeatEventToml Percentage)
repeatEvent
}
where
decodePercentage :: Value -> DecodeM Percentage
decodePercentage (Integer Integer
s) = case Word8 -> Maybe Percentage
mkPercentage (Integer -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
s) of
Just Percentage
p -> Percentage -> DecodeM Percentage
forall a. a -> DecodeM a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Percentage
p
Maybe Percentage
Nothing -> String -> DecodeM Percentage
forall a. String -> DecodeM a
forall (m :: Type -> Type) a. MonadFail m => String -> m a
fail (String -> DecodeM Percentage) -> String -> DecodeM Percentage
forall a b. (a -> b) -> a -> b
$ String
"Failed to parse percentage: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Integer -> String
forall a. Show a => a -> String
show Integer
s
decodePercentage Value
other = Value -> DecodeM Percentage
forall a. Value -> DecodeM a
typeMismatch Value
other
mkAlertPercents :: NonEmpty BatteryPercentageNoteToml -> Set Percentage
mkAlertPercents :: NonEmpty BatteryPercentageNoteToml -> Set Percentage
mkAlertPercents =
[Percentage] -> Set Percentage
forall a. Ord a => [a] -> Set a
Set.fromList
([Percentage] -> Set Percentage)
-> (NonEmpty BatteryPercentageNoteToml -> [Percentage])
-> NonEmpty BatteryPercentageNoteToml
-> Set Percentage
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. NonEmpty Percentage -> [Percentage]
forall a. NonEmpty a -> [a]
NE.toList
(NonEmpty Percentage -> [Percentage])
-> (NonEmpty BatteryPercentageNoteToml -> NonEmpty Percentage)
-> NonEmpty BatteryPercentageNoteToml
-> [Percentage]
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (BatteryPercentageNoteToml -> Percentage)
-> NonEmpty BatteryPercentageNoteToml -> NonEmpty Percentage
forall a b. (a -> b) -> NonEmpty a -> NonEmpty b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap (PercentageData -> Percentage
toPercentage (PercentageData -> Percentage)
-> (BatteryPercentageNoteToml -> PercentageData)
-> BatteryPercentageNoteToml
-> Percentage
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Optic' A_Lens NoIx BatteryPercentageNoteToml PercentageData
-> BatteryPercentageNoteToml -> PercentageData
forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view Optic' A_Lens NoIx BatteryPercentageNoteToml PercentageData
#percentage)
showSet :: Set Percentage -> String
showSet :: Set Percentage -> String
showSet =
Text -> String
unpackText
(Text -> String)
-> (Set Percentage -> Text) -> Set Percentage -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
".")
(Text -> Text)
-> (Set Percentage -> Text) -> Set Percentage -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Text -> [Text] -> Text
T.intercalate Text
", "
([Text] -> Text)
-> (Set Percentage -> [Text]) -> Set Percentage -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Percentage -> Text) -> [Percentage] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap (Word8 -> Text
forall a. Show a => a -> Text
showt (Word8 -> Text) -> (Percentage -> Word8) -> Percentage -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Optic' A_ReversedPrism NoIx Percentage Word8 -> Percentage -> Word8
forall k (is :: IxList) s a.
Is k A_Getter =>
Optic' k is s a -> s -> a
view Optic' A_ReversedPrism NoIx Percentage Word8
_MkPercentage)
([Percentage] -> [Text])
-> (Set Percentage -> [Percentage]) -> Set Percentage -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Set Percentage -> [Percentage]
forall a. Set a -> [a]
Set.toList