diff options
author | Andrew Cady <d@cryptonomic.net> | 2022-09-15 11:10:29 -0400 |
---|---|---|
committer | Andrew Cady <d@cryptonomic.net> | 2022-09-15 11:10:29 -0400 |
commit | f818e356797da77b9bdc8167f6828d9362d44834 (patch) | |
tree | 4dafbe62c0a5c55427abe7b80be2e50a4e31f9fa | |
parent | 6e10d8246eabad813b45a2e444250985a6dd79f8 (diff) |
implement time warp
-rwxr-xr-x | countdown.hs | 42 |
1 files changed, 26 insertions, 16 deletions
diff --git a/countdown.hs b/countdown.hs index ffe7af0..57788c5 100755 --- a/countdown.hs +++ b/countdown.hs | |||
@@ -75,8 +75,9 @@ data CustomEvent = TimeChanged UTCTime deriving Show | |||
75 | 75 | ||
76 | data St = | 76 | data St = |
77 | St { _stLastBrickEvent :: Maybe (BrickEvent () CustomEvent) | 77 | St { _stLastBrickEvent :: Maybe (BrickEvent () CustomEvent) |
78 | , _stCurrentTime :: UTCTime | 78 | , _stClockTime :: UTCTime |
79 | , _stNextEvent :: Maybe UTCTime | 79 | , _stDisplayTime :: UTCTime |
80 | , _stNextEvent :: Maybe UTCTime | ||
80 | } | 81 | } |
81 | 82 | ||
82 | makeLenses ''St | 83 | makeLenses ''St |
@@ -117,7 +118,7 @@ drawUI st = [a] | |||
117 | <=> | 118 | <=> |
118 | (str "\n") | 119 | (str "\n") |
119 | <=> | 120 | <=> |
120 | (countdownWidget $ utcToZonedTime zone $ st ^. stCurrentTime) | 121 | (countdownWidget $ utcToZonedTime zone $ st ^. stDisplayTime) |
121 | 122 | ||
122 | countdownWidget :: ZonedTime -> Widget n | 123 | countdownWidget :: ZonedTime -> Widget n |
123 | countdownWidget t = | 124 | countdownWidget t = |
@@ -158,27 +159,41 @@ countdownWidget t = | |||
158 | yearElapsed = (zonedTimeToLocalTime t) `diffLocalTime` (zonedTimeToLocalTime $ yearStart t) | 159 | yearElapsed = (zonedTimeToLocalTime t) `diffLocalTime` (zonedTimeToLocalTime $ yearStart t) |
159 | 160 | ||
160 | daysLeft = numDays - dayNum | 161 | daysLeft = numDays - dayNum |
161 | secondsLeft = toSeconds $ yearLength - yearElapsed | 162 | secondsLeft = toSeconds $ yearLength - yearElapsed :: Int |
162 | toSeconds dt = nominalDiffTimeToSeconds dt `div'` 1 :: Int | 163 | toSeconds = floor . nominalDiffTimeToSeconds |
163 | x // y = fromRational $ toRational x / toRational y :: Double | 164 | x // y = fromRational $ toRational x / toRational y :: Double |
164 | progressLabel = printf "%.6F%%" (100 * (yearElapsed // yearLength)) | 165 | progressLabel = printf "%.6F%%" (100 * (yearElapsed // yearLength)) |
165 | 166 | ||
166 | commas :: Integral i => i -> Text | 167 | commas :: Integral i => i -> Text |
167 | commas = prettyI (Just ',') . fromIntegral | 168 | commas = prettyI (Just ',') . fromIntegral |
168 | 169 | ||
170 | microsecondsUntil :: Integral i => UTCTime -> UTCTime -> i | ||
171 | microsecondsUntil now later = floor $ nominalDiffTimeToSeconds $ (later `diffUTCTime` now) * 1000 * 1000 | ||
172 | |||
173 | nextWholeSecond :: UTCTime -> UTCTime | ||
174 | nextWholeSecond (UTCTime day dayTime) = (UTCTime day dayTime') | ||
175 | where | ||
176 | dayTime' = secondsToDiffTime $ floor dayTime + 1 | ||
177 | |||
178 | threadDelayUntil :: UTCTime -> UTCTime -> IO () | ||
179 | threadDelayUntil now t = threadDelay $ microsecondsUntil now t | ||
180 | |||
169 | queueNextEvent :: MonadIO m => BChan CustomEvent -> UTCTime -> m () | 181 | queueNextEvent :: MonadIO m => BChan CustomEvent -> UTCTime -> m () |
170 | queueNextEvent chan now = liftIO . void . forkIO $ do | 182 | queueNextEvent chan now = liftIO . void . forkIO $ do |
171 | threadDelay $ microsecondsUntilNextSecond now | 183 | threadDelayUntil now (nextWholeSecond now) |
172 | getCurrentTime >>= writeBChan chan . TimeChanged | 184 | getCurrentTime >>= writeBChan chan . TimeChanged |
173 | 185 | ||
174 | handleEvent :: BChan CustomEvent -> St -> BrickEvent () CustomEvent -> EventM () (Next St) | 186 | handleEvent :: BChan CustomEvent -> St -> BrickEvent () CustomEvent -> EventM () (Next St) |
175 | handleEvent chan st e = | 187 | handleEvent chan st e = |
176 | case e of | 188 | case e of |
177 | VtyEvent (V.EvKey V.KEsc []) -> halt st | 189 | VtyEvent (V.EvKey V.KEsc []) -> halt st |
178 | VtyEvent _ -> cont st | 190 | VtyEvent (V.EvKey V.KPageUp []) -> cont $ st & stDisplayTime %~ (addUTCTime lengthOfDay) |
191 | VtyEvent (V.EvKey V.KPageDown []) -> cont $ st & stDisplayTime %~ (addUTCTime (-lengthOfDay)) | ||
192 | VtyEvent _ -> cont st | ||
179 | AppEvent (TimeChanged now) -> do | 193 | AppEvent (TimeChanged now) -> do |
180 | queueNextEvent chan now | 194 | queueNextEvent chan now |
181 | cont $ st & stCurrentTime .~ now | 195 | let oldTime = st ^. stClockTime |
196 | cont $ st & stClockTime .~ now & stDisplayTime %~ (addUTCTime (now `diffUTCTime` oldTime)) | ||
182 | _ -> cont st | 197 | _ -> cont st |
183 | where | 198 | where |
184 | cont s = do | 199 | cont s = do |
@@ -187,7 +202,8 @@ handleEvent chan st e = | |||
187 | initialState :: UTCTime -> St | 202 | initialState :: UTCTime -> St |
188 | initialState t = | 203 | initialState t = |
189 | St { _stLastBrickEvent = Nothing | 204 | St { _stLastBrickEvent = Nothing |
190 | , _stCurrentTime = t | 205 | , _stClockTime = t |
206 | , _stDisplayTime = t | ||
191 | , _stNextEvent = Nothing | 207 | , _stNextEvent = Nothing |
192 | } | 208 | } |
193 | 209 | ||
@@ -232,12 +248,6 @@ theApp chan = | |||
232 | zone :: TimeZone | 248 | zone :: TimeZone |
233 | zone = unsafePerformIO getCurrentTimeZone | 249 | zone = unsafePerformIO getCurrentTimeZone |
234 | 250 | ||
235 | microsecondsUntilNextSecond :: Integral i => UTCTime -> i | ||
236 | microsecondsUntilNextSecond now = (1000 * 1000 * remainingInCurrentSecond) `div'` 1 | ||
237 | where | ||
238 | todSecNow = todSec $ localTimeOfDay $ utcToLocalTime zone now | ||
239 | remainingInCurrentSecond = 1 - (todSecNow `mod'` 1) | ||
240 | |||
241 | main :: IO () | 251 | main :: IO () |
242 | main = do | 252 | main = do |
243 | chan <- newBChan 10 | 253 | chan <- newBChan 10 |