packages feed

twitter-0.1: Twitter.hs

module Main where

import GUI.Terminal
import Twitter.Client hiding (getTweets)
import qualified Twitter.Client as Client
import Control.Monad.State
import Commands
import State
import System.Console.Readline hiding (message)
import System.IO
import Data.List (intercalate)
import Data.Maybe (maybeToList)
import System.Directory (getHomeDirectory, doesFileExist)
import System.FilePath (combine)

initialState :: AppState
initialState = AppState [] 0 0 (80,25) NormalMode ""

main = do
  g <- geometry
  homeDir <- getHomeDirectory
  let filename = combine homeDir ".twitter"
  exists <- doesFileExist filename
  if not exists
     then showAuthError
     else do authorization <- readFile filename
             s <- refresh $ initialState {geom = g, auth = takeWhile (/= '\n') authorization}
             hSetBuffering stdin NoBuffering
             mainLoop s

showAuthError = putStrLn "Please create a file in your home-directory called .twitter with the contents username:password"

mainLoop :: AppState -> IO ()
mainLoop initState = do
  let (output, state) = runState drawScreen initState
      (width, height) = geom state
  putStrLn output
  putStr $ move 0 height
  putStr hideCursor
  case mode state of
       NormalMode  -> do let tweet = activeTweet state
                         putStr $ intercalate " | " $ [ show $ time tweet
                                                      , "@" ++ (screenName . user) tweet
                                                      ] ++ maybeToList (url $ user tweet)
  
                         putStr $ move 0 (height)
                         input <- getChar
                         processChar input state
       InsertMode  -> do putStr showCursor
                         input <- readline "say: "
                         processInsert input state
       CommandMode -> do putStr showCursor
                         input <- readline ":"
                         processCommand input state

drawScreen :: State AppState String
drawScreen = do
  tweets' <- getTweets
  let tweets = zip tweets' [0..]
  formattedTweets <- mapM formatTweet tweets
  return $ clear ++ header ++ unlines formattedTweets

header = []

quit = putStr (clear ++ showCursor ++ color Reset)

formatTweet (tweet, idx) = 
  do
    activeIdx <- getActiveTweet
    let
      name' = (name . user) tweet
      msg  = message tweet
      time' = time tweet
      active = activeIdx == idx
      (start_active, end_active) | active = (color Blue_bg, color Reset_bg)
                                 | otherwise = ([], [])
    return $ start_active ++ color Cyan_b ++ name' ++ color Reset_b 
             ++ ": " ++ msg ++ end_active

processCommand (Just "q") state = quit
processCommand _ state = mainLoop (normal state)

normal state = state {mode=NormalMode}

processInsert Nothing state = mainLoop $ normal state
processInsert (Just "") state = mainLoop $ normal state
processInsert (Just input) state = do
  when (length input > 140) $ do
    putStrLn "Your input exceeds 140 characters."
    getChar >> return ()

  addHistory input
  say (auth state) input
  state' <- refresh state
  mainLoop $ normal state'

processChar input state = 
  case charToCmd input of
       Up      -> mod $ modifyActiveTweet (\x -> x - 1)
       Down    -> mod $ modifyActiveTweet (+1) 
       Reply   -> putStrLn "TODO" >> getLine >> mainLoop state
       First   -> mod $ setActiveTweet 0
       Last    -> mod $ do tw <- getTweets
                           setActiveTweet (length tw - 1)
       Refresh -> refresh state >>= mainLoop
       Unknown -> mainLoop state
       Insert  -> mod $ setMode InsertMode
       Command -> mod $ setMode CommandMode
   where mod f = mainLoop $ execState f state

refresh :: AppState -> IO AppState
refresh s = do maybeTw <- Client.getTweets (auth s)
               case maybeTw of
                    Just tw -> return $ s {tweets = tw}
                    _       -> return s


activeTweet state = tweets state !! (active_tweet state)