99 lines
3.8 KiB
Haskell
99 lines
3.8 KiB
Haskell
{-# LANGUAGE OverloadedStrings, OverloadedLabels #-}
|
|
|
|
module UI (runApp) where
|
|
|
|
import qualified GI.Gtk as Gtk
|
|
import qualified GI.Gdk as Gdk
|
|
import qualified GI.Gio as Gio
|
|
import qualified GI.GLib as GLib
|
|
import qualified GI.GLib.Constants as GLibConst
|
|
import qualified GI.WebKit as WebKit
|
|
import qualified GI.Gtk.Enums as GtkEnums
|
|
import qualified Data.Text as T
|
|
|
|
import Data.List (find)
|
|
import Data.GI.Base (AttrOp(..))
|
|
import Control.Monad.Reader (runReaderT)
|
|
import Control.Concurrent.STM (newTVarIO, readTVar, atomically, modifyTVar)
|
|
import Control.Concurrent.Async (async)
|
|
import Codec.Epub.Data.Metadata (metaTitles, titleType, titleText)
|
|
import EpubParser (EpubEnv(..), resolveSpine, getChapter)
|
|
import Persistence (saveLastRead, loadLastRead)
|
|
import State (AppState(..), ChapterView(..), initialState, prepareView)
|
|
|
|
runApp :: EpubEnv -> IO ()
|
|
runApp env' = do
|
|
app <- Gtk.applicationNew (Just "com.svitak.reader.v2") []
|
|
|
|
_ <- Gtk.on app #activate $ do
|
|
|
|
stateTVar <- newTVarIO (initialState env')
|
|
|
|
window <- Gtk.applicationWindowNew app
|
|
webView <- WebKit.webViewNew
|
|
Gtk.set window [ #defaultWidth := 800, #defaultHeight := 600, #child := webView ]
|
|
|
|
-- load all chapters on another thread
|
|
let loadChapter index = do
|
|
st <- atomically $ readTVar stateTVar
|
|
case prepareView st index of
|
|
Nothing -> pure ()
|
|
Just view -> do
|
|
Gtk.set window [ #title := viewTitle view ]
|
|
WebKit.webViewLoadHtml webView (viewHtml view) Nothing
|
|
|
|
atomically $ modifyTVar stateTVar $ \s -> s { cIdx = viewIdx view}
|
|
_ <- async $ saveLastRead (bookPath env') (viewIdx view)
|
|
pure ()
|
|
|
|
-- keyboard handling
|
|
keyCtrl <- Gtk.eventControllerKeyNew
|
|
Gtk.eventControllerSetPropagationPhase keyCtrl GtkEnums.PropagationPhaseCapture
|
|
|
|
_ <- Gtk.on keyCtrl #keyPressed $ \keyval _ _ -> do
|
|
stNow <- atomically $ readTVar stateTVar
|
|
case keyval of
|
|
Gdk.KEY_Right -> loadChapter (cIdx stNow + 1) >> pure True
|
|
Gdk.KEY_Left -> loadChapter (cIdx stNow - 1) >> pure True
|
|
Gdk.KEY_equal -> do
|
|
let newZ = zoomlvl stNow + 0.1
|
|
atomically $ modifyTVar stateTVar $ \s -> s { zoomlvl = newZ }
|
|
WebKit.webViewSetZoomLevel webView newZ
|
|
pure True
|
|
Gdk.KEY_minus -> do
|
|
let newZ = max 0.1 (zoomlvl stNow - 0.1)
|
|
atomically $ modifyTVar stateTVar $ \s -> s { zoomlvl = newZ }
|
|
WebKit.webViewSetZoomLevel webView newZ
|
|
pure True
|
|
_ -> pure False
|
|
|
|
Gtk.widgetAddController window keyCtrl
|
|
#present window
|
|
|
|
-- start eager parse
|
|
_ <- async $ do
|
|
ispine <- runReaderT resolveSpine env'
|
|
allChapters <- runReaderT (mapM getChapter ispine) env'
|
|
|
|
let titles = metaTitles (eMetadata env')
|
|
let rawT = case find (\t -> titleType t == Just "main") titles of
|
|
Just t -> titleText t
|
|
Nothing -> if null titles then "Unknown" else titleText (head titles)
|
|
|
|
atomically $ modifyTVar stateTVar $ \s -> s
|
|
{ cSpine = ispine
|
|
, cAllChapters = allChapters
|
|
, bTitle = T.pack rawT
|
|
}
|
|
|
|
_ <- GLib.idleAdd GLibConst.PRIORITY_DEFAULT $ do
|
|
maybeSaved <- loadLastRead
|
|
case maybeSaved of
|
|
Just (path, idx) | path == bookPath env' -> loadChapter idx
|
|
_ -> loadChapter 0
|
|
pure False
|
|
pure ()
|
|
pure ()
|
|
|
|
_ <- Gio.applicationRun app Nothing
|
|
pure ()
|