diff --git a/app/Persistence.hs b/app/Persistence.hs index c4b0998..3007ab8 100644 --- a/app/Persistence.hs +++ b/app/Persistence.hs @@ -1,4 +1,40 @@ -module Persistence where +module Persistence + ( saveLastRead + , loadLastRead + ) where --- TODO: Add book state persistence +import System.Directory (getXdgDirectory, XdgDirectory(XdgData), createDirectoryIfMissing) +import System.FilePath (()) +import qualified Data.Text as T +import qualified Data.Text.IO as TIO +import Control.Exception (try, SomeException) +import Text.Read (readMaybe) +saveLastRead :: FilePath -> Int -> IO () +saveLastRead bPath chapterIdx = do + dataDir <- getXdgDirectory XdgData "svitak" + createDirectoryIfMissing True dataDir + + let configFile = dataDir "last_read.txt" + -- Line 1 = Path, Line 2 = Index + let content = T.pack bPath <> T.pack "\n" <> T.pack (show chapterIdx) + + TIO.writeFile configFile content + putStrLn $ "Progress saved to: " ++ configFile + +loadLastRead :: IO (Maybe (FilePath, Int)) +loadLastRead = do + dataDir <- getXdgDirectory XdgData "svitak" + let configFile = dataDir "last_read.txt" + + result <- try (TIO.readFile configFile) :: IO (Either SomeException T.Text) + + case result of + Left _ -> pure Nothing + Right content -> do + let linesOfFile = T.lines content + case linesOfFile of + [path, idxStr] + | Just idx <- readMaybe (T.unpack idxStr) -> + pure $ Just (T.unpack path, idx) + _ -> pure Nothing diff --git a/app/UI.hs b/app/UI.hs index 892a44b..3916db1 100644 --- a/app/UI.hs +++ b/app/UI.hs @@ -12,7 +12,8 @@ import Control.Monad.Reader (runReaderT) import Data.IORef (newIORef, readIORef, writeIORef) import Text.HTML.TagSoup (renderTags) -import EpubParser (EpubEnv, resolveSpine, getChapter) +import EpubParser (EpubEnv, resolveSpine, getChapter, bookPath) +import Persistence (saveLastRead, loadLastRead) runApp :: EpubEnv -> IO () runApp env = do @@ -20,7 +21,7 @@ runApp env = do app <- Gtk.applicationNew (Just "com.svitak.reader.v2") [] _ <- Gtk.on app #activate $ do - putStrLn "DEBUG: App Activated" + putStrLn "App Activated" -- Setup window window <- Gtk.applicationWindowNew app @@ -34,30 +35,40 @@ runApp env = do -- Get the spine spine <- runReaderT resolveSpine env let totalChapters = length spine - putStrLn $ "DEBUG: Spine loaded. Total chapters: " ++ show totalChapters + 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 $ "DEBUG: Loading Chapter " ++ show (safeIdx + 1) + 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:///") - -- Load the first chapter - loadChapter 0 + -- 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