quarantimer 1.20200326 → 1.20200422
raw patch · 6 files changed
+84/−37 lines, 6 filesdep ~servant-luciddep ~warpdep ~warp-tls
Dependency ranges changed: servant-lucid, warp, warp-tls
Files
- CHANGELOG +9/−0
- TODO +21/−1
- quarantimer.cabal +5/−4
- quarantimer.hs +24/−18
- stack.yaml +5/−0
- static/js.js +20/−14
CHANGELOG view
@@ -1,3 +1,12 @@+quarantimer (1.20200422) unstable; urgency=medium++ * When time for surface is not known, as with masks, say that it's not,+ instead of using a 1 year timeout.+ * Added a stack.yaml file so it can be built using stack with a known+ working set of packages.++ -- Joey Hess <id@joeyh.name> Wed, 22 Apr 2020 11:49:50 -0400+ quarantimer (1.20200326) unstable; urgency=medium * Incorportated new research from
TODO view
@@ -1,7 +1,27 @@+* Timeline gets cluttered up with old items over time, and sometimes+ there are several expired short timers before an active long one,+ making it hard to notice it.++ Might be best to split into two lists of active and expired.+ However, that can't be done in the haskell as it stands now; would need+ to be done in the js.++* If two devices are displaying the same page, an add by one is not seen by+ the other one until the page is reloaded.++* Switch to an AJAX display where the js queries the server for a list of+ items and then builds up the display? That would allow solving both+ the cluttered timeline and multi-device update.++ Alternatively, the js could make a long poll to the server, which replies+ when it wants to update the display, and the js then just reloads the+ page. This keeps the js smaller, and it also might replace the hourly+ polling for a changed session id.+ * Check if the MediaDevices API is not suported and fall back to file upload. * Expire old images after some reasonable amount of time. This can be done- with just a find command.+ with just a find command. Or the js could hide them. * Add systemd service file and Makefile to install it better. * Improve CSS. (Patches welcome on this one.) * The javascript could let things be added in offline mode, and sync up
quarantimer.cabal view
@@ -1,5 +1,5 @@ Name: quarantimer-Version: 1.20200326+Version: 1.20200422 Cabal-Version: >= 1.8 Maintainer: Joey Hess <id@joeyh.name> Author: Joey Hess@@ -20,6 +20,7 @@ CHANGELOG static/js.js static/style.css+ stack.yaml Executable quarantimer Main-Is: quarantimer.hs@@ -29,14 +30,14 @@ , servant (>= 0.15 && < 0.18) , servant-server (>= 0.15 && < 0.18) , servant-client (>= 0.15 && < 0.18)- , servant-lucid (== 0.9.0.1)+ , servant-lucid (== 0.9.*) , servant-multipart (== 0.11.*) , lucid (== 2.9.12) , aeson (>= 1.4.2 && < 1.5) , wai (== 3.2.*) , wai-extra- , warp (== 3.2.*)- , warp-tls (== 3.2.*)+ , warp+ , warp-tls , uuid (== 1.3.*) , bytestring , text
quarantimer.hs view
@@ -68,7 +68,7 @@ { thingSurface :: Surface , thingPhoto :: UrlString , thingQuarantineStarted :: UTCTime- , thingSecondsUntilSafe :: Integer+ , thingSecondsUntilSafe :: Maybe Integer } deriving (ToJSON, Generic) @@ -76,7 +76,7 @@ { surfaceID :: SurfaceID , surfaceDesc :: T.Text , surfaceIcon :: UrlString- , surfaceSecondsUntilSafe :: Integer+ , surfaceSecondsUntilSafe :: Maybe Integer , surfaceDeprecated :: Bool } deriving (ToJSON, Generic)@@ -186,12 +186,17 @@ [ class_ "photo" , src_ (T.pack (thingPhoto thing)) ]- let timer = T.pack $ show $- thingSecondsUntilSafe thing- span_ - [ class_ "timer"- , title_ timer- ] (toHtml timer)+ case thingSecondsUntilSafe thing of+ Just s -> do+ let timer = T.pack $ show s+ span_ + [ class_ "timer"+ , title_ timer+ ] (toHtml timer)+ Nothing -> do+ span_ + [ class_ "unknowntimer"+ ] "It is not known how long covid-19 remains on this surface." br_ [] br_ [] @@ -315,19 +320,19 @@ -- https://www.nejm.org/doi/10.1056/NEJMc2004973 [ Surface (SurfaceID 1) "cardboard" (staticFileUrl "cardboard.jpg")- (hours 24) False+ (Just (hours 24)) False -- https://doi.org/10.1101/2020.03.15.20036673 -- tissue and printing paper , Surface (SurfaceID 4) "paper" (staticFileUrl "paper.jpg")- (hours 3) False+ (Just (hours 3)) False -- https://doi.org/10.1101/2020.03.15.20036673 , Surface (SurfaceID 5) "cloth" (staticFileUrl "cloth.jpg")- (days 2) False+ (Just (days 2)) False , Surface (SurfaceID 2) "plastic" (staticFileUrl "plastic.jpg")- (hours 72) False+ (Just (hours 72)) False -- https://doi.org/10.1101/2020.03.15.20036673 -- 7 days for stainless steel --@@ -339,17 +344,16 @@ -- not.. , Surface (SurfaceID 3) "metal" (staticFileUrl "metal.jpg")- (days 7) False+ (Just (days 7)) False -- https://doi.org/10.1101/2020.03.15.20036673 -- found virus after 7 days in outer layer of surgical mask.- -- Unknown how long it lasts, and they should be discarded or- -- sterilized, so use 1 year as the timeout.+ -- Unknown how long it lasts. , Surface (SurfaceID 6) "surgical mask" (staticFileUrl "mask.jpg")- (days 365) False+ Nothing False , Surface (SurfaceID 0) "other" (staticFileUrl "other.jpg")- (hours 72) + (Just (hours 72)) True -- do not offer as a selection any more ] where@@ -425,7 +429,9 @@ mtime <- getModificationTime (userdir </> f) now <- getCurrentTime let secsold = max 0 (floor (diffUTCTime now mtime))- let ts = surfaceSecondsUntilSafe s - secsold+ let ts = case surfaceSecondsUntilSafe s of+ Nothing -> Nothing+ Just ss -> Just (ss - secsold) return $ Just $ Thing { thingSurface = s , thingPhoto = staticUserFileUrl user f
+ stack.yaml view
@@ -0,0 +1,5 @@+packages:+- '.'+extra-deps:+- sandi-0.5@sha256:b278d072ca717706ea38f9bd646e023f7f2576a778fb43565b434f93638849aa+resolver: lts-14.27
static/js.js view
@@ -17,9 +17,11 @@ things[i].img = img; var timer = elt.getElementsByClassName("timer")[0]; things[i].timer = timer;- var n = parseInt(timer.attributes.title.value);- var d = loaddate + (n * 1000);- things[i].enddate = d;+ if (timer != null) {+ var n = parseInt(timer.attributes.title.value);+ var d = loaddate + (n * 1000);+ things[i].enddate = d;+ } } animate();@@ -97,18 +99,22 @@ for (var i = 0; i < things.length; i++) { var img = things[i].img; var timer = things[i].timer;- var diff = (things[i].enddate - now) / 1e3;- var h=(diff/60/60)>>0;- var m=(diff/60 - h*60)>>0;- if (diff > 0) {- img.className = "infected";- timer.innerHTML = "quarantine ends in " +- displayUnit(h,"hour") + " " +- displayUnit(m,"minute")+ if (things[i].enddate != null) {+ var diff = (things[i].enddate - now) / 1e3;+ var h=(diff/60/60)>>0;+ var m=(diff/60 - h*60)>>0;+ if (diff > 0) {+ img.className = "infected";+ timer.innerHTML = "quarantine ends in " ++ displayUnit(h,"hour") + " " ++ displayUnit(m,"minute")+ } else {+ img.className = "safe";+ timer.innerHTML = "quarantine completed " ++ displayUnit((h*-1),"hour") + " ago"+ } } else {- img.className = "safe";- timer.innerHTML = "quarantine completed " +- displayUnit((h*-1),"hour") + " ago"+ img.className = "infected"; } }