{-# LANGUAGE OverloadedStrings #-} module Main(main, parseTask, serializeTask, getPriority, comparePriority, TaskMap) where import System.IO import System.Directory import Data.Text (Text, pack, unpack, isInfixOf, lines, unlines, strip) import qualified Data.Text.IO as TIO import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as BSC import Control.Monad (when) import Data.List (sortBy) import Data.Ord (comparing) import Data.Char (isAlpha) import qualified Data.Map as Map import Data.Function (on) todoFile :: FilePath todoFile = "todo.txt" type TaskMap = Map.Map Int Text main :: IO () main = do putStrLn "Welcome to the Haskell Todo App" putStrLn "1. Display tasks" putStrLn "2. Add task" putStrLn "3. Filter tasks by tag" putStrLn "4. Sort tasks by priority" putStrLn "5. Exit" putStr "Choose an option: " hFlush stdout option <- getLine case option of "1" -> displayTasks "2" -> addTask "3" -> filterTasksByTag "4" -> sortTasksByPriority "5" -> putStrLn "Goodbye!" _ -> putStrLn "Invalid option" >> main displayTasks :: IO () displayTasks = do exists <- doesFileExist todoFile if exists then do contents <- BSC.readFile todoFile let taskMap = parseTask (pack (BSC.unpack contents)) putStrLn "Tasks:" mapM_ (putStrLn . showTask) (Map.toList taskMap) else putStrLn "No tasks found." main addTask :: IO () addTask = do putStr "Enter the task: " hFlush stdout task <- getLine exists <- doesFileExist todoFile if exists then do contents <- BSC.readFile todoFile let taskMap = parseTask (pack (BSC.unpack contents)) newId = if Map.null taskMap then 1 else fst (Map.findMax taskMap) + 1 newTaskMap = Map.insert newId (pack task) taskMap BSC.writeFile todoFile (BSC.pack (unpack (serializeTask newTaskMap))) else BSC.writeFile todoFile (BSC.pack (task <> "\n")) putStrLn "Task added." main filterTasksByTag :: IO () filterTasksByTag = do putStr "Enter the tag to filter by (e.g., +GarageSale): " hFlush stdout tag <- getLine exists <- doesFileExist todoFile if exists then do contents <- TIO.readFile todoFile let taskMap = parseTask contents filteredTasks = Map.filter (isInfixOf (pack tag)) taskMap putStrLn "Filtered tasks:" mapM_ (putStrLn . showTask) (Map.toList filteredTasks) else putStrLn "No tasks found." main sortTasksByPriority :: IO () sortTasksByPriority = do exists <- doesFileExist todoFile if exists then do contents <- TIO.readFile todoFile let taskMap = parseTask contents sortedTasks = sortBy (comparePriority `on` snd) (Map.toList taskMap) putStrLn "Sorted tasks by priority:" mapM_ (putStrLn . showTask) sortedTasks else putStrLn "No tasks found." main comparePriority :: Text -> Text -> Ordering comparePriority t1 t2 = comparing getPriority t1 t2 getPriority :: Text -> Maybe Char getPriority t = case unpack (strip t) of ('(':p:')':_) | isAlpha p -> Just p _ -> Nothing parseTask :: Text -> TaskMap parseTask = Map.fromList . zip [1..] . Data.Text.lines serializeTask :: TaskMap -> Text serializeTask = Data.Text.unlines . map snd . Map.toList showTask :: (Int, Text) -> String showTask (_, task) = unpack task