This will allow us to save the last chapter the user read, thus making it easier to track progress. Implement persistence module saveLastRead saves the chapter after each new one is read and writes it to xdgdata
97 lines
3.3 KiB
Haskell
97 lines
3.3 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.WebKit as WebKit
|
|
import qualified GI.Gtk.Enums as GtkEnums
|
|
|
|
import Control.Monad.Reader (runReaderT)
|
|
import Data.IORef (newIORef, readIORef, writeIORef)
|
|
import Text.HTML.TagSoup (renderTags)
|
|
|
|
import EpubParser (EpubEnv, resolveSpine, getChapter, bookPath)
|
|
import Persistence (saveLastRead, loadLastRead)
|
|
|
|
runApp :: EpubEnv -> IO ()
|
|
runApp env = do
|
|
|
|
app <- Gtk.applicationNew (Just "com.svitak.reader.v2") []
|
|
|
|
_ <- Gtk.on app #activate $ do
|
|
putStrLn "App Activated"
|
|
|
|
-- Setup window
|
|
window <- Gtk.applicationWindowNew app
|
|
Gtk.windowSetTitle window (Just "Svitak")
|
|
Gtk.windowSetDefaultSize window 800 600
|
|
|
|
-- Setup webview
|
|
webView <- WebKit.webViewNew
|
|
Gtk.windowSetChild window (Just webView)
|
|
|
|
-- Get the spine
|
|
spine <- runReaderT resolveSpine env
|
|
let totalChapters = length spine
|
|
putStrLn $ "Spine loaded. Total chapters: " ++ show totalChapters
|
|
|
|
if totalChapters == 0
|
|
then putStrLn "ERROR: This book has no chapters!"
|
|
else do
|
|
currentIndex <- newIORef 0
|
|
|
|
let loadChapter index = do
|
|
let maxIdx = totalChapters - 1
|
|
let safeIdx = max 0 (min index maxIdx)
|
|
|
|
-- Save state after every chapter
|
|
writeIORef currentIndex safeIdx
|
|
putStrLn $ "Loading Chapter " ++ show (safeIdx + 1)
|
|
saveLastRead (bookPath env) safeIdx
|
|
|
|
let filename = spine !! safeIdx
|
|
tags <- runReaderT (getChapter filename) env
|
|
|
|
let htmlContent = renderTags tags
|
|
|
|
-- Load HTML
|
|
WebKit.webViewLoadHtml webView htmlContent (Just "file:///")
|
|
|
|
-- If there's no state saved then load the first chapter
|
|
maybeSaved <- loadLastRead
|
|
|
|
case maybeSaved of
|
|
Just (path, index)
|
|
| path == bookPath env -> loadChapter index
|
|
| otherwise -> loadChapter 0
|
|
|
|
Nothing -> loadChapter 0
|
|
|
|
|
|
-- Setup keyboard input
|
|
keyController <- Gtk.eventControllerKeyNew
|
|
|
|
Gtk.eventControllerSetPropagationPhase keyController GtkEnums.PropagationPhaseCapture
|
|
|
|
_ <- Gtk.on keyController #keyPressed $ \keyval _ _ -> do
|
|
curr <- readIORef currentIndex
|
|
case keyval of
|
|
Gdk.KEY_Right -> do
|
|
putStrLn "KEY: -> Next"
|
|
loadChapter (curr + 1)
|
|
return True
|
|
Gdk.KEY_Left -> do
|
|
putStrLn "KEY: <- Prev"
|
|
loadChapter (curr - 1)
|
|
return True
|
|
_ -> return False
|
|
|
|
Gtk.widgetAddController window keyController
|
|
|
|
#present window
|
|
putStrLn "DEBUG: Window presented"
|
|
|
|
_ <- Gio.applicationRun app Nothing
|
|
pure ()
|