svitak/app/UI.hs
Marko Andjelic fab1d6b84c Add persistence module
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
2026-01-26 08:32:20 +00:00

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 ()