{-# Language MultiParamTypeClasses, BangPatterns, TemplateHaskell #-}
module Client.State.Window
(
Window(..)
, winMessages
, winUnread
, winTotal
, winMention
, winMarker
, winHideMeta
, WindowLine(..)
, wlSummary
, wlText
, wlPrefix
, wlImage
, wlFullImage
, wlImportance
, wlTimestamp
, WindowLineImportance(..)
, emptyWindow
, addToWindow
, windowSeen
, windowActivate
, windowDeactivate
, PackedTime
, packZonedTime
, unpackUTCTime
, unpackTimeOfDay
) where
import Client.Image.PackedImage
import Client.Message
import Control.Lens
import Control.Monad ((<$!>))
import Data.Text.Lazy (Text)
import Data.Time
import Data.Word
import Data.Bits
data WindowLine = WindowLine
{ _wlSummary :: !IrcSummary
, _wlPrefix :: !Image'
, _wlImage :: !Image'
, _wlFullImage :: !Image'
, _wlImportance :: !WindowLineImportance
, _wlTimestamp :: {-# UNPACK #-} !PackedTime
}
newtype PackedTime = PackedTime Word64
data WindowLines
= {-# UNPACK #-} !WindowLine :- WindowLines
| Nil
data Window = Window
{ _winMessages :: !WindowLines
, _winMarker :: !(Maybe Int)
, _winUnread :: !Int
, _winTotal :: !Int
, _winMention :: !WindowLineImportance
, _winHideMeta :: !Bool
}
data ActivityLevel = NoActivity | NormalActivity | HighActivity
deriving (Eq, Ord, Read, Show)
data WindowLineImportance
= WLBoring
| WLNormal
| WLImportant
deriving (Eq, Ord, Show, Read)
makeLenses ''Window
makeLenses ''WindowLine
wlText :: Getter WindowLine Text
wlText = wlFullImage . to imageText
emptyWindow :: Window
emptyWindow = Window
{ _winMessages = Nil
, _winMarker = Nothing
, _winUnread = 0
, _winTotal = 0
, _winMention = WLBoring
, _winHideMeta = False
}
addToWindow :: WindowLine -> Window -> Window
addToWindow !msg !win = Window
{ _winMessages = msg :- view winMessages win
, _winTotal = view winTotal win + 1
, _winMarker = (+1) <$!> view winMarker win
, _winUnread = if view wlImportance msg == WLBoring
then view winUnread win
else view winUnread win + 1
, _winMention = max (view winMention win) (view wlImportance msg)
, _winHideMeta = view winHideMeta win
}
windowSeen :: Window -> Window
windowSeen = set winUnread 0
. set winMention WLBoring
windowActivate :: Window -> Window
windowActivate win
| view winUnread win == 0 = set winMarker Nothing win
| otherwise = win
windowDeactivate :: Window -> Window
windowDeactivate = set winMarker (Just 0)
instance Each WindowLines WindowLines WindowLine WindowLine where
each _ Nil = pure Nil
each f (x :- xs) = (:-) <$> f x <*> each f xs
field :: Num a => PackedTime -> Int -> Int -> a
field (PackedTime x) off sz = fromIntegral ((x `shiftR` off) .&. (2^sz-1))
{-# INLINE field #-}
packField :: Int -> Int -> Word64
packField off val = fromIntegral val `shiftL` off
packZonedTime :: ZonedTime -> PackedTime
packZonedTime (ZonedTime (LocalTime (ModifiedJulianDay d) (TimeOfDay h m s)) z)
= PackedTime
$ packField 17 h .|.
packField 11 m .|.
packField 5 (floor s) .|.
packField 22 (fromInteger d) .|.
packField 0 (timeZoneMinutes z `div` 60 + 12)
unpackTimeOfDay :: PackedTime -> TimeOfDay
unpackTimeOfDay !x = TimeOfDay h m s
where
h = field x 17 5
m = field x 11 6
s = field x 5 6
unpackLocalTime :: PackedTime -> LocalTime
unpackLocalTime !x = LocalTime d t
where
d = ModifiedJulianDay (field x 22 42)
t = unpackTimeOfDay x
unpackUTCTime :: PackedTime -> UTCTime
unpackUTCTime = zonedTimeToUTC . unpackZonedTime
unpackZonedTime :: PackedTime -> ZonedTime
unpackZonedTime !x = ZonedTime t z
where
z = minutesToTimeZone ((field x 0 5 - 12) * 60)
t = unpackLocalTime x