48 Commits

Author SHA1 Message Date
Jonathan Lamothe
994087a0e6 version 0.11.0 2020-01-23 17:18:39 -05:00
Jonathan Lamothe
7fbeaac933 Merge pull request #66 from mtlstats/master-menu
Master menu
2020-01-22 21:53:09 -05:00
Jonathan Lamothe
de56f4f94d updated change log 2020-01-22 21:43:09 -05:00
Jonathan Lamothe
04ba17324e centre menus horizontally 2020-01-22 21:23:32 -05:00
Jonathan Lamothe
d6ae171dc8 pad menu selections to same width 2020-01-22 21:10:21 -05:00
Jonathan Lamothe
72b6f05700 changed menu style
...to be closer to the original program's menu style
2020-01-22 20:59:09 -05:00
Jonathan Lamothe
4c7a756c5e updated change log 2020-01-22 16:30:19 -05:00
Jonathan Lamothe
ea3ca4e578 Merge pull request #65 from mtlstats/title-screen
Title screen
2020-01-22 13:58:12 -05:00
Jonathan Lamothe
179a864cfa added header to title page 2020-01-22 13:48:34 -05:00
Jonathan Lamothe
f2b2ff3fef centred title screen 2020-01-22 13:43:58 -05:00
Jonathan Lamothe
9c2e2291c8 draw box around title 2020-01-22 08:49:13 -05:00
Jonathan Lamothe
abad72ce01 built basic title screen 2020-01-22 00:39:06 -05:00
Jonathan Lamothe
a9d4d3351f implemented title screen controller 2020-01-21 22:55:22 -05:00
Jonathan Lamothe
45aea607b2 added title screen logic branch 2020-01-21 22:20:01 -05:00
Jonathan Lamothe
be9d7d80bb updated change log 2020-01-16 22:16:20 -05:00
Jonathan Lamothe
683c36e2b6 Merge pull request #64 from mtlstats/edit-standings
Edit standings
2020-01-16 21:52:41 -05:00
Jonathan Lamothe
83c408cea2 implemented editing prompts 2020-01-16 21:46:35 -05:00
Jonathan Lamothe
dcbd68cdda implemented editHomeStandingsC and editAwayStandingsC 2020-01-16 21:10:14 -05:00
Jonathan Lamothe
717f2d5932 made standings table prettier 2020-01-16 19:58:07 -05:00
Jonathan Lamothe
d5de834510 implemented edit functions in Mtlstats.Actions.EditState module 2020-01-16 19:47:12 -05:00
Jonathan Lamothe
75a47ca852 implemented Mtlstats.Menu.EditStandings.subMenu 2020-01-16 17:54:05 -05:00
Jonathan Lamothe
d4de7c6f8b implemented editHomeStandings and editAwayStandings 2020-01-16 17:43:53 -05:00
Jonathan Lamothe
d50d055b0b implemented editHomeStandings and editAwayStandings 2020-01-16 17:17:24 -05:00
Jonathan Lamothe
9c7c295a4b implemented editAwayStandings 2020-01-16 15:00:08 -05:00
Jonathan Lamothe
49963277be implemented editHomeStandings 2020-01-16 12:42:33 -05:00
Jonathan Lamothe
264d9f81e2 moved editStandings to Mtlstats.Actions.EditStandings module 2020-01-16 00:03:31 -05:00
Jonathan Lamothe
6a0d1f7203 implemented editStandingsMenu 2020-01-15 23:21:37 -05:00
Jonathan Lamothe
18683c1c6e implemented Mtlstats.Control.EditStandings.valsFor 2020-01-15 01:05:45 -05:00
Jonathan Lamothe
107ed507e2 implemented Mtlstats.Control.EditStandings.header 2020-01-15 01:00:26 -05:00
Jonathan Lamothe
baf040deea implemented editStandingsC 2020-01-15 00:43:48 -05:00
Jonathan Lamothe
c3bac5e624 created Mtlstats.Control.EditStandings module 2020-01-15 00:34:45 -05:00
Jonathan Lamothe
119cb873eb implemented editStandings 2020-01-15 00:26:46 -05:00
Jonathan Lamothe
82603ba504 added "Edit Standings" to edit menu 2020-01-15 00:15:58 -05:00
Jonathan Lamothe
a909b9ba7a added EditStandings mode 2020-01-15 00:08:04 -05:00
Jonathan Lamothe
802bf7314e fixed formatting of change log 2020-01-14 23:33:39 -05:00
Jonathan Lamothe
a3124aca58 Merge pull request #63 from mtlstats/save-db
save a copy of the database on new season
2020-01-14 03:29:52 -05:00
Jonathan Lamothe
f113e46564 updated change log 2020-01-14 03:23:39 -05:00
Jonathan Lamothe
39646f3fa7 save a copy of the database on start of new season 2020-01-14 03:21:40 -05:00
Jonathan Lamothe
2bf8d15bd4 logic branch for database saving on new season 2020-01-14 02:42:30 -05:00
Jonathan Lamothe
3009a8f60c Merge pull request #62 from mtlstats/clear-rookies
clear rookies on new (regular) season
2020-01-11 02:39:41 -05:00
Jonathan Lamothe
3b4ce50ae8 clear rookies on new (regular) season 2020-01-11 02:30:09 -05:00
Jonathan Lamothe
fcfbcea72f Merge pull request #61 from mtlstats/active-col
Added active field to players/goalies
2020-01-11 01:59:51 -05:00
Jonathan Lamothe
d132ebd502 updated change log 2020-01-11 01:52:40 -05:00
Jonathan Lamothe
75cd253f3f allow user to toggle active flag for Player/Goalie 2020-01-11 01:49:27 -05:00
Jonathan Lamothe
063bebfbb5 test active field in JSON for Player/Goalie 2020-01-11 01:49:27 -05:00
Jonathan Lamothe
7923827d22 flag inactive goalies in goalieName 2020-01-11 01:49:27 -05:00
Jonathan Lamothe
461fb5d942 mark inactive players in playerName 2020-01-11 01:27:01 -05:00
Jonathan Lamothe
e38275aefe added active field to Player and Goalie 2020-01-11 01:21:16 -05:00
23 changed files with 912 additions and 151 deletions

View File

@@ -1,5 +1,13 @@
# Changelog for mtlstats # Changelog for mtlstats
## 0.11.0
- Added active flag to players/goalies
- Clear rookie flag on new (regular) season
- Save a copy of the database on new season
- Implemented game standings editing
- Added title screen
- Changed sytling of menus
## 0.10.0 ## 0.10.0
- Don't show player number zero in reports - Don't show player number zero in reports
- Fixed player/goalie name capitalisation on edit - Fixed player/goalie name capitalisation on edit
@@ -33,24 +41,20 @@
- Reset game standings on new season - Reset game standings on new season
## 0.5.0 ## 0.5.0
- Fixed player creation bug - Fixed player creation bug
- Prompt for goalie informaiton on game data entry - Prompt for goalie informaiton on game data entry
- Implemented player editing - Implemented player editing
## v0.4.0 ## v0.4.0
- Record penalty minutes - Record penalty minutes
- Calculate total game statistics - Calculate total game statistics
- Generate year-to-date statistics report - Generate year-to-date statistics report
## v0.3.0 ## v0.3.0
- Record goals and assists - Record goals and assists
- Track goals for and goals against - Track goals for and goals against
## v0.2.0 ## v0.2.0
- Overtime losses don't count in the loss column - Overtime losses don't count in the loss column
- Confirm game data with user before updating stats - Confirm game data with user before updating stats
- Implemented player creation - Implemented player creation

View File

@@ -1,5 +1,5 @@
name: mtlstats name: mtlstats
version: 0.10.0 version: 0.11.0
github: "mtlstats/mtlstats" github: "mtlstats/mtlstats"
license: GPL-3 license: GPL-3
author: "Jonathan Lamothe" author: "Jonathan Lamothe"

View File

@@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
module Mtlstats.Actions module Mtlstats.Actions
( startNewSeason ( startNewSeason
, resetYtd , resetYtd
, clearRookies
, resetStandings , resetStandings
, startNewGame , startNewGame
, addChar , addChar
@@ -42,18 +43,29 @@ module Mtlstats.Actions
, backHome , backHome
, scrollUp , scrollUp
, scrollDown , scrollDown
, saveDatabase
) where ) where
import Control.Monad.Trans.State (modify) import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.State (gets, modify)
import Data.Aeson (encodeFile)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Lens.Micro ((^.), (&), (.~), (%~)) import Lens.Micro ((^.), (&), (.~), (%~))
import System.EasyFile
( createDirectoryIfMissing
, getAppUserDataDirectory
, (</>)
)
import Mtlstats.Config
import Mtlstats.Types import Mtlstats.Types
import Mtlstats.Util import Mtlstats.Util
-- | Starts a new season -- | Starts a new season
startNewSeason :: ProgState -> ProgState startNewSeason :: ProgState -> ProgState
startNewSeason = (progMode .~ NewSeason) . (database . dbGames .~ 0) startNewSeason
= (progMode .~ NewSeason False)
. (database.dbGames .~ 0)
-- | Resets all players year-to-date stats -- | Resets all players year-to-date stats
resetYtd :: ProgState -> ProgState resetYtd :: ProgState -> ProgState
@@ -61,6 +73,12 @@ resetYtd
= (database . dbPlayers %~ map (pYtd .~ newPlayerStats)) = (database . dbPlayers %~ map (pYtd .~ newPlayerStats))
. (database . dbGoalies %~ map (gYtd .~ newGoalieStats)) . (database . dbGoalies %~ map (gYtd .~ newGoalieStats))
-- | Clears the rookie flag from all players/goalies
clearRookies :: ProgState -> ProgState
clearRookies = database
%~ (dbPlayers %~ map (pRookie .~ False))
. (dbGoalies %~ map (gRookie .~ False))
-- | Resets game standings -- | Resets game standings
resetStandings :: ProgState -> ProgState resetStandings :: ProgState -> ProgState
resetStandings = database resetStandings = database
@@ -189,3 +207,13 @@ scrollUp = scrollOffset %~ max 0 . pred
-- | Scrolls the display down -- | Scrolls the display down
scrollDown :: ProgState -> ProgState scrollDown :: ProgState -> ProgState
scrollDown = scrollOffset %~ succ scrollDown = scrollOffset %~ succ
-- | Saves the database
saveDatabase :: String -> Action ()
saveDatabase fn = do
db <- gets (^.database)
liftIO $ do
dir <- getAppUserDataDirectory appName
let dbFile = dir </> fn
createDirectoryIfMissing True dir
encodeFile dbFile db

View File

@@ -0,0 +1,70 @@
{- |
mtlstats
Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-}
module Mtlstats.Actions.EditStandings
( editStandings
, editHomeStandings
, editAwayStandings
, editWins
, editLosses
, editOvertime
, editGoalsFor
, editGoalsAgainst
) where
import Lens.Micro ((.~))
import Mtlstats.Types
-- | Enters edit standings mode
editStandings :: ProgState -> ProgState
editStandings = progMode .~ EditStandings ESMMenu
-- | Edits the home standings
editHomeStandings :: ProgState -> ProgState
editHomeStandings = progMode .~ EditStandings (ESMHome ESMSubMenu)
-- | Edits the road standings
editAwayStandings :: ProgState -> ProgState
editAwayStandings = progMode .~ EditStandings (ESMAway ESMSubMenu)
-- | Changes to edit wins mode
editWins :: ProgState -> ProgState
editWins = doEdit ESMEditWins
-- | Changes to edit losses mode
editLosses :: ProgState -> ProgState
editLosses = doEdit ESMEditLosses
-- | Changes to edit overtime mode
editOvertime :: ProgState -> ProgState
editOvertime = doEdit ESMEditOvertime
-- | Changes to edit goals for mode
editGoalsFor :: ProgState -> ProgState
editGoalsFor = doEdit ESMEditGoalsFor
-- | Changes to edit goals against mode
editGoalsAgainst :: ProgState -> ProgState
editGoalsAgainst = doEdit ESMEditGoalsAgainst
doEdit :: ESMSubMode -> ProgState -> ProgState
doEdit = (progMode.editStandingsModeL.esmSubModeL .~)

View File

@@ -29,8 +29,10 @@ import Lens.Micro.Extras (view)
import qualified UI.NCurses as C import qualified UI.NCurses as C
import Mtlstats.Actions import Mtlstats.Actions
import Mtlstats.Control.TitleScreen
import Mtlstats.Control.EditGoalie import Mtlstats.Control.EditGoalie
import Mtlstats.Control.EditPlayer import Mtlstats.Control.EditPlayer
import Mtlstats.Control.EditStandings
import Mtlstats.Control.NewGame import Mtlstats.Control.NewGame
import Mtlstats.Handlers import Mtlstats.Handlers
import Mtlstats.Menu import Mtlstats.Menu
@@ -41,10 +43,11 @@ import Mtlstats.Types
-- run -- run
dispatch :: ProgState -> Controller dispatch :: ProgState -> Controller
dispatch s = case s^.progMode of dispatch s = case s^.progMode of
MainMenu -> mainMenuC TitleScreen -> titleScreenC
NewSeason -> newSeasonC MainMenu -> mainMenuC
NewGame gs -> newGameC gs NewSeason flag -> newSeasonC flag
EditMenu -> editMenuC NewGame gs -> newGameC gs
EditMenu -> editMenuC
CreatePlayer cps CreatePlayer cps
| null $ cps^.cpsNumber -> getPlayerNumC | null $ cps^.cpsNumber -> getPlayerNumC
| null $ cps^.cpsName -> getPlayerNameC | null $ cps^.cpsName -> getPlayerNameC
@@ -54,8 +57,9 @@ dispatch s = case s^.progMode of
| null $ cgs^.cgsNumber -> getGoalieNumC | null $ cgs^.cgsNumber -> getGoalieNumC
| null $ cgs^.cgsName -> getGoalieNameC | null $ cgs^.cgsName -> getGoalieNameC
| otherwise -> confirmCreateGoalieC | otherwise -> confirmCreateGoalieC
EditPlayer eps -> editPlayerC eps EditPlayer eps -> editPlayerC eps
EditGoalie egs -> editGoalieC egs EditGoalie egs -> editGoalieC egs
(EditStandings esm) -> editStandingsC esm
mainMenuC :: Controller mainMenuC :: Controller
mainMenuC = Controller mainMenuC = Controller
@@ -63,13 +67,9 @@ mainMenuC = Controller
, handleController = menuHandler mainMenu , handleController = menuHandler mainMenu
} }
newSeasonC :: Controller newSeasonC :: Bool -> Controller
newSeasonC = Controller newSeasonC False = promptController newSeasonPrompt
{ drawController = const $ drawMenu newSeasonMenu newSeasonC True = menuController newSeasonMenu
, handleController = \e -> do
menuHandler newSeasonMenu e
return True
}
editMenuC :: Controller editMenuC :: Controller
editMenuC = menuController editMenu editMenuC = menuController editMenu

View File

@@ -0,0 +1,87 @@
{- |
mtlstats
Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-}
{-# LANGUAGE LambdaCase #-}
module Mtlstats.Control.EditStandings (editStandingsC) where
import Lens.Micro ((^.))
import qualified UI.NCurses as C
import Mtlstats.Format
import Mtlstats.Menu
import Mtlstats.Menu.EditStandings
import Mtlstats.Prompt
import Mtlstats.Prompt.EditStandings
import Mtlstats.Types
import Mtlstats.Types.Menu
-- | Controller for the edit standings menu
editStandingsC :: EditStandingsMode -> Controller
editStandingsC = \case
ESMMenu -> menuControllerWith header editStandingsMenu
ESMHome m -> editHomeStandingsC m
ESMAway m -> editAwayStandingsC m
editHomeStandingsC :: ESMSubMode -> Controller
editHomeStandingsC = \case
ESMSubMenu -> menuC editHomeStandingsMenu
ESMEditWins -> promptC editHomeWinsPrompt
ESMEditLosses -> promptC editHomeLossesPrompt
ESMEditOvertime -> promptC editHomeOvertimePrompt
ESMEditGoalsFor -> promptC editHomeGoalsForPrompt
ESMEditGoalsAgainst -> promptC editHomeGoalsAgainstPrompt
editAwayStandingsC :: ESMSubMode -> Controller
editAwayStandingsC = \case
ESMSubMenu -> menuC editAwayStandingsMenu
ESMEditWins -> promptC editAwayWinsPrompt
ESMEditLosses -> promptC editAwayLossesPrompt
ESMEditOvertime -> promptC editAwayOvertimePrompt
ESMEditGoalsFor -> promptC editAwayGoalsForPrompt
ESMEditGoalsAgainst -> promptC editAwayGoalsAgainstPrompt
menuC :: Menu () -> Controller
menuC = menuControllerWith header
promptC :: Prompt -> Controller
promptC = promptControllerWith header
header :: ProgState -> C.Update ()
header = do
db <- (^.database)
let
home = db^.dbHomeGameStats
away = db^.dbAwayGameStats
table = numTable [" W", " L", " OT", " GF", " GA"]
[ ( "HOME", valsFor home )
, ( "ROAD", valsFor away )
]
return $ C.drawString $ unlines $ table ++ [""]
valsFor :: GameStats -> [Int]
valsFor gs =
[ gs^.gmsWins
, gs^.gmsLosses
, gs^.gmsOvertime
, gs^.gmsGoalsFor
, gs^.gmsGoalsAgainst
]

View File

@@ -0,0 +1,142 @@
{- |
mtlstats
Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-}
{-# LANGUAGE LambdaCase #-}
module Mtlstats.Control.TitleScreen (titleScreenC) where
import Control.Monad.Trans.State (modify)
import Data.Char (chr)
import qualified UI.NCurses as C
import Mtlstats.Actions
import Mtlstats.Format
import Mtlstats.Types
titleScreenC :: Controller
titleScreenC = Controller
{ drawController = const $ do
(_, cols) <- C.windowSize
C.drawString $ unlines $ map (centre $ fromIntegral $ pred cols)
$ [ ""
, "MONTREAL CANADIENS STATISTICS"
]
++ titleText
++ [ ""
, "Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe"
, "<rheal.lamothe@gmail.com>"
, ""
, "Press any key to continue..."
]
return C.CursorInvisible
, handleController = \case
C.EventCharacter _ -> modify backHome >> return True
C.EventSpecialKey _ -> modify backHome >> return True
_ -> return True
}
titleText :: [String]
titleText = box $ map (map blockify) $ foldl joinBlocks (repeat "")
[chM, chT, chL, chS, chT, chA, chT, chS]
box :: [String] -> [String]
box strs
= [[tl] ++ replicate width horiz ++ [tr]]
++ map (\str -> [vert] ++ str ++ [vert]) strs
++ [[bl] ++ replicate width horiz ++ [br]]
where
width = length $ head strs
tl = chr 0x2554
tr = chr 0x2557
bl = chr 0x255a
br = chr 0x255d
horiz = chr 0x2550
vert = chr 0x2551
blockify :: Char -> Char
blockify = \case
'#' -> chr 0x2588
'>' -> chr 0x2590
'<' -> chr 0x258c
ch -> ch
joinBlocks :: [String] -> [String] -> [String]
joinBlocks = zipWith (++)
chM :: [String]
chM =
[ "##< >##"
, ">## ##<"
, ">##< >##<"
, ">### ###<"
, ">#######<"
, ">#<###>#<"
, ">#<>#<>#<"
, "##< >##"
]
chT :: [String]
chT =
[ ">########<"
, ">## ## ##<"
, ">#< ## >#<"
, " ## "
, " ## "
, " ## "
, " ## "
, " >##< "
]
chL :: [String]
chL =
[ "### "
, ">#< "
, ">#< "
, ">#< "
, ">#< "
, ">#< ##"
, ">#< >##"
, "#######"
]
chS :: [String]
chS =
[ " #####< "
, ">#< ## "
, "## "
, " #####< "
, " >#<"
, " ##"
, ">#< >#<"
, " ###### "
]
chA :: [String]
chA =
[ " >##< "
, " ## "
, " >##< "
, " #### "
, " >#<>#< "
, " ###### "
, ">#< >#<"
, "### ###"
]

View File

@@ -51,8 +51,12 @@ goalieDetails g = let
goalieName :: Goalie -> String goalieName :: Goalie -> String
goalieName g = let goalieName g = let
prefix = if g^.gActive
then ""
else "*"
suffix = if g^.gRookie suffix = if g^.gRookie
then "*" then "*"
else "" else ""
in g^.gName ++ suffix in prefix ++ g^.gName ++ suffix

View File

@@ -49,8 +49,12 @@ playerDetails p = unlines $ top ++ [""] ++ table
playerName :: Player -> String playerName :: Player -> String
playerName p = let playerName p = let
prefix = if p^.pActive
then ""
else "*"
suffix = if p^.pRookie suffix = if p^.pRookie
then "*" then "*"
else "" else ""
in p^.pName ++ suffix in prefix ++ p^.pName ++ suffix

View File

@@ -35,24 +35,18 @@ module Mtlstats.Menu (
editMenu editMenu
) where ) where
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.State (gets, modify) import Control.Monad.Trans.State (gets, modify)
import Data.Aeson (encodeFile)
import Data.Char (toUpper) import Data.Char (toUpper)
import qualified Data.Map as M import qualified Data.Map as M
import Data.Maybe (mapMaybe) import Data.Maybe (mapMaybe)
import Lens.Micro ((^.), (?~)) import Lens.Micro ((^.), (?~))
import Lens.Micro.Extras (view)
import System.EasyFile
( createDirectoryIfMissing
, getAppUserDataDirectory
, (</>)
)
import qualified UI.NCurses as C import qualified UI.NCurses as C
import Mtlstats.Actions import Mtlstats.Actions
import qualified Mtlstats.Actions.NewGame.GoalieInput as GI import qualified Mtlstats.Actions.NewGame.GoalieInput as GI
import Mtlstats.Actions.EditStandings
import Mtlstats.Config import Mtlstats.Config
import Mtlstats.Format
import Mtlstats.Types import Mtlstats.Types
import Mtlstats.Types.Menu import Mtlstats.Types.Menu
import Mtlstats.Util import Mtlstats.Util
@@ -96,7 +90,11 @@ menuStateController menuFunc = Controller
-- | The draw function for a 'Menu' -- | The draw function for a 'Menu'
drawMenu :: Menu a -> C.Update C.CursorMode drawMenu :: Menu a -> C.Update C.CursorMode
drawMenu m = do drawMenu m = do
C.drawString $ show m (_, cols) <- C.windowSize
let
width = fromIntegral $ pred cols
menuText = map (centre width) $ lines $ show m
C.drawString $ unlines menuText
return C.CursorInvisible return C.CursorInvisible
-- | The event handler for a 'Menu' -- | The event handler for a 'Menu'
@@ -109,61 +107,56 @@ menuHandler m _ = return $ m^.menuDefault
-- | The main menu -- | The main menu
mainMenu :: Menu Bool mainMenu :: Menu Bool
mainMenu = Menu "*** MAIN MENU ***" True mainMenu = Menu "MASTER MENU" True
[ MenuItem '1' "New Season" $ [ MenuItem 'A' "NEW SEASON" $
modify startNewSeason >> return True modify startNewSeason >> return True
, MenuItem '2' "New Game" $ , MenuItem 'B' "NEW GAME" $
modify startNewGame >> return True modify startNewGame >> return True
, MenuItem '3' "Edit" $ , MenuItem 'C' "EDIT MENU" $
modify edit >> return True modify edit >> return True
, MenuItem 'X' "Exit" $ do , MenuItem 'E' "EXIT" $
db <- gets $ view database saveDatabase dbFname >> return False
liftIO $ do
dir <- getAppUserDataDirectory appName
let dbFile = dir </> dbFname
createDirectoryIfMissing True dir
encodeFile dbFile db
return False
] ]
-- | The new season menu -- | The new season menu
newSeasonMenu :: Menu () newSeasonMenu :: Menu ()
newSeasonMenu = Menu "*** SEASON TYPE ***" () newSeasonMenu = Menu "SEASON TYPE" ()
[ MenuItem 'R' "Regular Season" $ modify [ MenuItem 'R' "REGULAR SEASON" $ modify
$ resetYtd $ resetYtd
. clearRookies
. resetStandings . resetStandings
. startNewGame . startNewGame
, MenuItem 'P' "Playoffs" $ modify , MenuItem 'P' "PLAYOFFS" $ modify
$ resetStandings $ resetStandings
. startNewGame . startNewGame
] ]
-- | Requests the month in which the game took place -- | Requests the month in which the game took place
gameMonthMenu :: Menu () gameMonthMenu :: Menu ()
gameMonthMenu = Menu "Month:" () $ map gameMonthMenu = Menu "MONTH:" () $ map
(\(ch, name, val) -> (\(ch, name, val) ->
MenuItem ch name $ MenuItem ch name $
modify $ progMode.gameStateL.gameMonth ?~ val) modify $ progMode.gameStateL.gameMonth ?~ val)
[ ( 'A', "January", 1 ) [ ( 'A', "JANUARY", 1 )
, ( 'B', "February", 2 ) , ( 'B', "FEBRUARY", 2 )
, ( 'C', "March", 3 ) , ( 'C', "MARCH", 3 )
, ( 'D', "April", 4 ) , ( 'D', "APRIL", 4 )
, ( 'E', "May", 5 ) , ( 'E', "MAY", 5 )
, ( 'F', "June", 6 ) , ( 'F', "JUNE", 6 )
, ( 'G', "July", 7 ) , ( 'G', "JULY", 7 )
, ( 'H', "August", 8 ) , ( 'H', "AUGUST", 8 )
, ( 'I', "September", 9 ) , ( 'I', "SEPTEMBER", 9 )
, ( 'J', "October", 10 ) , ( 'J', "OCTOBER", 10 )
, ( 'K', "November", 11 ) , ( 'K', "NOVEMBER", 11 )
, ( 'L', "December", 12 ) , ( 'L', "DECEMBER", 12 )
] ]
-- | The game type menu (home/away) -- | The game type menu (home/away)
gameTypeMenu :: Menu () gameTypeMenu :: Menu ()
gameTypeMenu = Menu "Game type:" () gameTypeMenu = Menu "GAME TYPE:" ()
[ MenuItem '1' "Home Game" $ [ MenuItem 'H' "HOME GAME" $
modify $ progMode.gameStateL.gameType ?~ HomeGame modify $ progMode.gameStateL.gameType ?~ HomeGame
, MenuItem '2' "Away Game" $ , MenuItem 'A' "AWAY GAME" $
modify $ progMode.gameStateL.gameType ?~ AwayGame modify $ progMode.gameStateL.gameType ?~ AwayGame
] ]
@@ -184,15 +177,17 @@ gameGoalieMenu s = let
-- | The edit menu -- | The edit menu
editMenu :: Menu () editMenu :: Menu ()
editMenu = Menu "*** EDIT ***" () editMenu = Menu "EDIT MENU" ()
[ MenuItem '1' "Create Player" $ [ MenuItem 'A' "CREATE PLAYER" $
modify createPlayer modify createPlayer
, MenuItem '2' "Create Goalie" $ , MenuItem 'B' "CREATE GOALIE" $
modify createGoalie modify createGoalie
, MenuItem '3' "Edit Player" $ , MenuItem 'C' "EDIT PLAYER" $
modify editPlayer modify editPlayer
, MenuItem '4' "Edit Goalie" $ , MenuItem 'D' "EDIT GOALIE" $
modify editGoalie modify editGoalie
, MenuItem 'R' "Return to Main Menu" $ , MenuItem 'E' "EDIT STANDINGS" $
modify editStandings
, MenuItem 'R' "RETURN TO MAIN MENU" $
modify backHome modify backHome
] ]

View File

@@ -34,51 +34,53 @@ import Mtlstats.Types.Menu
-- | The 'Goalie' edit menu -- | The 'Goalie' edit menu
editGoalieMenu :: Menu () editGoalieMenu :: Menu ()
editGoalieMenu = Menu "*** EDIT GOALTENDER ***" () $ map editGoalieMenu = Menu "EDIT GOALTENDER" () $ map
(\(ch, label, action) -> MenuItem ch label $ modify action) (\(ch, label, action) -> MenuItem ch label $ modify action)
-- key, label, value -- key, label, value
[ ( '1', "Edit number", set EGNumber ) [ ( 'A', "EDIT NUMBER", set EGNumber )
, ( '2', "Edit name", set EGName ) , ( 'B', "EDIT NAME", set EGName )
, ( '3', "Toggle rookie flag", toggle ) , ( 'C', "TOGGLE ROOKIE FLAG", toggleRookie )
, ( '4', "Edit YTD stats", set EGYtd ) , ( 'D', "TOGGLE ACTIVE FLAG", toggleActive )
, ( '5', "Edit Lifetime stats", set EGLifetime ) , ( 'E', "EDIT YTD STATS", set EGYtd )
, ( 'R', "Return to Edit Menu", edit ) , ( 'F', "EDIT LIFETIME STATS", set EGLifetime )
, ( 'R', "RETURN TO EDIT MENU", edit )
] ]
where where
set mode = progMode.editGoalieStateL.egsMode .~ mode set mode = progMode.editGoalieStateL.egsMode .~ mode
toggle = editSelectedGoalie (gRookie %~ not) toggleRookie = editSelectedGoalie (gRookie %~ not)
toggleActive = editSelectedGoalie (gActive %~ not)
-- | The 'Goalie' YTD edit menu -- | The 'Goalie' YTD edit menu
editGoalieYtdMenu :: Menu () editGoalieYtdMenu :: Menu ()
editGoalieYtdMenu = editMenu "*** EDIT GOALTENDER YEAR-TO-DATE ***" editGoalieYtdMenu = editMenu "EDIT GOALTENDER YEAR-TO-DATE"
-- key, label, value -- key, label, value
[ ( '1', "Edit all YTD stats", EGYtdGames True ) [ ( 'A', "EDIT ALL YTD STATS", EGYtdGames True )
, ( '2', "Edit YTD games", EGYtdGames False ) , ( 'B', "EDIT YTD GAMES", EGYtdGames False )
, ( '3', "Edit YTD minutes", EGYtdMins False ) , ( 'C', "EDIT YTD MINUTES", EGYtdMins False )
, ( '4', "Edit YTD goals", EGYtdGoals False ) , ( 'D', "EDIT YTD GOALS", EGYtdGoals False )
, ( '5', "Edit YTD shutouts", EGYtdShutouts False ) , ( 'E', "EDIT YTD SHUTOUTS", EGYtdShutouts False )
, ( '6', "Edit YTD wins", EGYtdWins False ) , ( 'F', "EDIT YTD WINS", EGYtdWins False )
, ( '7', "Edit YTD losses", EGYtdLosses False ) , ( 'G', "EDIT YTD LOSSES", EGYtdLosses False )
, ( '8', "Edit YTD ties", EGYtdTies ) , ( 'H', "EDIT YTD TIES", EGYtdTies )
, ( 'R', "Return to edit menu", EGMenu ) , ( 'R', "RETURN TO EDIT MENU", EGMenu )
] ]
-- | The 'Goalie' lifetime edit menu -- | The 'Goalie' lifetime edit menu
editGoalieLtMenu :: Menu () editGoalieLtMenu :: Menu ()
editGoalieLtMenu = editMenu editGoalieLtMenu = editMenu
"*** EDIT GOALTENDER LIFETIME ***" "EDIT GOALTENDER LIFETIME"
-- key, label, value -- key, label, value
[ ( '1', "Edit all lifetime stats", EGLtGames True ) [ ( 'A', "EDIT ALL LIFETIME STATS", EGLtGames True )
, ( '2', "Edit lifetime games", EGLtGames False ) , ( 'B', "EDIT LIFETIME GAMES", EGLtGames False )
, ( '3', "Edit lifetime minutes", EGLtMins False ) , ( 'C', "EDIT LIFETIME MINUTES", EGLtMins False )
, ( '4', "Edit lifetime goals", EGLtGoals False ) , ( 'D', "EDIT LIFETIME GOALS", EGLtGoals False )
, ( '5', "Edit lifetime shutouts", EGLtShutouts False ) , ( 'E', "EDIT LIFETIME SHUTOUTS", EGLtShutouts False )
, ( '6', "Edit lifetime wins", EGLtWins False ) , ( 'F', "EDIT LIFETIME WINS", EGLtWins False )
, ( '7', "Edit lifetime losses", EGLtLosses False ) , ( 'G', "EDIT LIFETIME LOSSES", EGLtLosses False )
, ( '8', "Edit lifetime ties", EGLtTies ) , ( 'H', "EDIT LIFETIME TIES", EGLtTies )
, ( 'R', "Return to edit menu", EGMenu ) , ( 'R', "RETURN TO EDIT MENU", EGMenu )
] ]
editMenu :: String -> [(Char, String, EditGoalieMode)] -> Menu () editMenu :: String -> [(Char, String, EditGoalieMode)] -> Menu ()

View File

@@ -34,45 +34,47 @@ import Mtlstats.Types.Menu
-- | The 'Player' edit menu -- | The 'Player' edit menu
editPlayerMenu :: Menu () editPlayerMenu :: Menu ()
editPlayerMenu = Menu "*** EDIT PLAYER ***" () $ map editPlayerMenu = Menu "EDIT PLAYER" () $ map
(\(ch, label, action) -> MenuItem ch label $ modify action) (\(ch, label, action) -> MenuItem ch label $ modify action)
-- key, label, value -- key, label, value
[ ( '1', "Edit number", set EPNumber ) [ ( 'A', "EDIT NUMBER", set EPNumber )
, ( '2', "Edit name", set EPName ) , ( 'B', "EDIT NAME", set EPName )
, ( '3', "Edit position", set EPPosition ) , ( 'C', "EDIT POSITION", set EPPosition )
, ( '4', "Toggle rookie flag", toggle ) , ( 'D', "TOGGLE ROOKIE FLAG", toggleRookie )
, ( '5', "Edit YTD stats", set EPYtd ) , ( 'E', "TOGGLE ACTIVE FLAG", toggleActive )
, ( '6', "Edit lifetime stats", set EPLifetime ) , ( 'F', "EDIT YTD STATS", set EPYtd )
, ( 'R', "Return to Edit Menu", edit ) , ( 'G', "EDIT LIFETIME STATS", set EPLifetime )
, ( 'R', "RETURN TO EDIT MENU", edit )
] ]
where where
set mode = progMode.editPlayerStateL.epsMode .~ mode set mode = progMode.editPlayerStateL.epsMode .~ mode
toggle = editSelectedPlayer $ pRookie %~ not toggleRookie = editSelectedPlayer $ pRookie %~ not
toggleActive = editSelectedPlayer $ pActive %~ not
-- | The 'Player' YTD stats edit menu -- | The 'Player' YTD stats edit menu
editPlayerYtdMenu :: Menu () editPlayerYtdMenu :: Menu ()
editPlayerYtdMenu = editMenu editPlayerYtdMenu = editMenu
"*** EDIT PLAYER YEAR-TO-DATE ***" "EDIT PLAYER YEAR-TO-DATE"
-- key, label, value -- key, label, value
[ ( '1', "Edit all YTD stats", EPYtdGoals True ) [ ( 'A', "EDIT ALL YTD STATS", EPYtdGoals True )
, ( '2', "Edit YTD goals", EPYtdGoals False ) , ( 'B', "EDIT YTD GOALS", EPYtdGoals False )
, ( '3', "Edit YTD assists", EPYtdAssists False ) , ( 'C', "EDIT YTD ASSISTS", EPYtdAssists False )
, ( '4', "Edit YTD penalty mins", EPYtdPMin ) , ( 'D', "EDIT YTD PENALTY MINS", EPYtdPMin )
, ( 'R', "Return to player edit menu", EPMenu ) , ( 'R', "RETURN TO PLAYER EDIT MENU", EPMenu )
] ]
-- | The 'Player' lifetime stats edit menu -- | The 'Player' lifetime stats edit menu
editPlayerLtMenu :: Menu () editPlayerLtMenu :: Menu ()
editPlayerLtMenu = editMenu editPlayerLtMenu = editMenu
"*** EDIT PLAYER LIFETIME ***" "EDIT PLAYER LIFETIME"
-- key, label, value -- key, label, value
[ ( '1', "Edit all lifetime stats", EPLtGoals True ) [ ( 'A', "EDIT ALL LIFETIME STATS", EPLtGoals True )
, ( '2', "Edit lifetime goals", EPLtGoals False ) , ( 'B', "EDIT LIFETIME GOALS", EPLtGoals False )
, ( '3', "Edit lifetime assits", EPLtAssists False ) , ( 'C', "EDIT LIFETIME ASSITS", EPLtAssists False )
, ( '4', "Edit lifetime penalty mins", EPLtPMin ) , ( 'D', "EDIT LIFETIME PENALTY MINS", EPLtPMin )
, ( 'R', "Return to edit player menu", EPMenu ) , ( 'R', "RETURN TO EDIT PLAYER MENU", EPMenu )
] ]
editMenu :: String -> [(Char, String, EditPlayerMode)] -> Menu () editMenu :: String -> [(Char, String, EditPlayerMode)] -> Menu ()

View File

@@ -0,0 +1,64 @@
{- |
mtlstats
Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-}
module Mtlstats.Menu.EditStandings
( editStandingsMenu
, editHomeStandingsMenu
, editAwayStandingsMenu
) where
import Control.Monad.Trans.State (modify)
import Mtlstats.Actions
import Mtlstats.Actions.EditStandings
import Mtlstats.Types.Menu
editStandingsMenu :: Menu ()
editStandingsMenu = Menu "EDIT STANDINGS" ()
[ MenuItem 'A' "EDIT HOME STANDINGS" $
modify editHomeStandings
, MenuItem 'B' "EDIT ROAD STANDINGS" $
modify editAwayStandings
, MenuItem 'R' "RETURN TO MAIN MENU" $
modify backHome
]
editHomeStandingsMenu :: Menu ()
editHomeStandingsMenu = subMenu "HOME"
editAwayStandingsMenu :: Menu ()
editAwayStandingsMenu = subMenu "ROAD"
subMenu :: String -> Menu ()
subMenu str = Menu (str ++ " STANDINGS") ()
[ MenuItem 'W' "EDIT WINS" $
modify editWins
, MenuItem 'L' "EDIT LOSSES" $
modify editLosses
, MenuItem 'O' "EDIT OVERTIME GAMES" $
modify editOvertime
, MenuItem 'F' "EDIT GOALS FOR" $
modify editGoalsFor
, MenuItem 'A' "EDIT GOALS AGAINST" $
modify editGoalsAgainst
, MenuItem 'R' "RETURN TO EDIT STANDINGS MENU" $
modify editStandings
]

View File

@@ -34,6 +34,7 @@ module Mtlstats.Prompt (
numPromptWithFallback, numPromptWithFallback,
selectPrompt, selectPrompt,
-- * Individual prompts -- * Individual prompts
newSeasonPrompt,
playerNumPrompt, playerNumPrompt,
playerNamePrompt, playerNamePrompt,
playerPosPrompt, playerPosPrompt,
@@ -47,7 +48,7 @@ module Mtlstats.Prompt (
import Control.Monad (when) import Control.Monad (when)
import Control.Monad.Extra (whenJust) import Control.Monad.Extra (whenJust)
import Control.Monad.Trans.State (gets, modify) import Control.Monad.Trans.State (gets, modify)
import Data.Char (isDigit, toUpper) import Data.Char (isAlphaNum, isDigit, toUpper)
import Lens.Micro ((^.), (&), (.~), (?~), (%~)) import Lens.Micro ((^.), (&), (.~), (?~), (%~))
import Lens.Micro.Extras (view) import Lens.Micro.Extras (view)
import Text.Read (readMaybe) import Text.Read (readMaybe)
@@ -167,6 +168,22 @@ numPromptWithFallback pStr fallback act = Prompt
, promptSpecialKey = const $ return () , promptSpecialKey = const $ return ()
} }
-- | Prompts the user for a filename to save a backup of the database
-- to
newSeasonPrompt :: Prompt
newSeasonPrompt = prompt
{ promptProcessChar = \ch str -> if isAlphaNum ch
then str ++ [toUpper ch]
else str
}
where
prompt = strPrompt "Filename to save database: " $ \fn ->
if null fn
then modify backHome
else do
saveDatabase $ fn ++ ".json"
modify $ progMode .~ NewSeason True
-- | Builds a selection prompt -- | Builds a selection prompt
selectPrompt :: SelectParams a -> Prompt selectPrompt :: SelectParams a -> Prompt
selectPrompt params = Prompt selectPrompt params = Prompt

View File

@@ -0,0 +1,89 @@
{- |
mtlstats
Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-}
module Mtlstats.Prompt.EditStandings
( editHomeWinsPrompt
, editHomeLossesPrompt
, editHomeOvertimePrompt
, editHomeGoalsForPrompt
, editHomeGoalsAgainstPrompt
, editAwayWinsPrompt
, editAwayLossesPrompt
, editAwayOvertimePrompt
, editAwayGoalsForPrompt
, editAwayGoalsAgainstPrompt
) where
import Control.Monad.Trans.State (modify)
import Lens.Micro ((.~), (%~))
import Mtlstats.Prompt
import Mtlstats.Types
editHomeWinsPrompt :: Prompt
editHomeWinsPrompt =
mkPrompt "Home wins: " (dbHomeGameStats.gmsWins .~)
editHomeLossesPrompt :: Prompt
editHomeLossesPrompt =
mkPrompt "Home losses: " (dbHomeGameStats.gmsLosses .~)
editHomeOvertimePrompt :: Prompt
editHomeOvertimePrompt =
mkPrompt "Home overtime games: " (dbHomeGameStats.gmsOvertime .~)
editHomeGoalsForPrompt :: Prompt
editHomeGoalsForPrompt =
mkPrompt "Home goals for: " (dbHomeGameStats.gmsGoalsFor .~)
editHomeGoalsAgainstPrompt :: Prompt
editHomeGoalsAgainstPrompt =
mkPrompt "Home goals against: " (dbHomeGameStats.gmsGoalsAgainst .~)
editAwayWinsPrompt :: Prompt
editAwayWinsPrompt =
mkPrompt "Road wins: " (dbAwayGameStats.gmsWins .~)
editAwayLossesPrompt :: Prompt
editAwayLossesPrompt =
mkPrompt "Road losses: " (dbAwayGameStats.gmsLosses .~)
editAwayOvertimePrompt :: Prompt
editAwayOvertimePrompt =
mkPrompt "Road overtime games: " (dbAwayGameStats.gmsOvertime .~)
editAwayGoalsForPrompt :: Prompt
editAwayGoalsForPrompt =
mkPrompt "Road goals for: " (dbAwayGameStats.gmsGoalsFor .~)
editAwayGoalsAgainstPrompt :: Prompt
editAwayGoalsAgainstPrompt =
mkPrompt "Road goals against: " (dbAwayGameStats.gmsGoalsAgainst .~)
mkPrompt :: String -> (Int -> Database -> Database) -> Prompt
mkPrompt pStr f = numPromptWithFallback pStr
(modify subMenu)
(\n -> modify
$ (database %~ f n)
. subMenu)
subMenu :: ProgState -> ProgState
subMenu = progMode.editStandingsModeL.esmSubModeL .~ ESMSubMenu

View File

@@ -35,6 +35,8 @@ module Mtlstats.Types (
EditPlayerMode (..), EditPlayerMode (..),
EditGoalieState (..), EditGoalieState (..),
EditGoalieMode (..), EditGoalieMode (..),
EditStandingsMode (..),
ESMSubMode (..),
Database (..), Database (..),
Player (..), Player (..),
PlayerStats (..), PlayerStats (..),
@@ -56,6 +58,9 @@ module Mtlstats.Types (
createGoalieStateL, createGoalieStateL,
editPlayerStateL, editPlayerStateL,
editGoalieStateL, editGoalieStateL,
editStandingsModeL,
-- ** EditStandingsMode Lenses
esmSubModeL,
-- ** GameState Lenses -- ** GameState Lenses
gameYear, gameYear,
gameMonth, gameMonth,
@@ -107,6 +112,7 @@ module Mtlstats.Types (
pName, pName,
pPosition, pPosition,
pRookie, pRookie,
pActive,
pYtd, pYtd,
pLifetime, pLifetime,
-- ** PlayerStats Lenses -- ** PlayerStats Lenses
@@ -117,6 +123,7 @@ module Mtlstats.Types (
gNumber, gNumber,
gName, gName,
gRookie, gRookie,
gActive,
gYtd, gYtd,
gLifetime, gLifetime,
-- ** GoalieStats Lenses -- ** GoalieStats Lenses
@@ -229,24 +236,28 @@ data ProgState = ProgState
-- | The program mode -- | The program mode
data ProgMode data ProgMode
= MainMenu = TitleScreen
| NewSeason | MainMenu
| NewSeason Bool
| NewGame GameState | NewGame GameState
| EditMenu | EditMenu
| CreatePlayer CreatePlayerState | CreatePlayer CreatePlayerState
| CreateGoalie CreateGoalieState | CreateGoalie CreateGoalieState
| EditPlayer EditPlayerState | EditPlayer EditPlayerState
| EditGoalie EditGoalieState | EditGoalie EditGoalieState
| EditStandings EditStandingsMode
instance Show ProgMode where instance Show ProgMode where
show MainMenu = "MainMenu" show TitleScreen = "TitleScreen"
show NewSeason = "NewSeason" show MainMenu = "MainMenu"
show (NewGame _) = "NewGame" show (NewSeason _) = "NewSeason"
show EditMenu = "EditMenu" show (NewGame _) = "NewGame"
show (CreatePlayer _) = "CreatePlayer" show EditMenu = "EditMenu"
show (CreateGoalie _) = "CreateGoalie" show (CreatePlayer _) = "CreatePlayer"
show (EditPlayer _) = "EditPlayer" show (CreateGoalie _) = "CreateGoalie"
show (EditGoalie _) = "EditGoalie" show (EditPlayer _) = "EditPlayer"
show (EditGoalie _) = "EditGoalie"
show (EditStandings _) = "EditStandings"
-- | The game state -- | The game state
data GameState = GameState data GameState = GameState
@@ -387,6 +398,23 @@ data EditGoalieMode
| EGLtTies | EGLtTies
deriving (Eq, Show) deriving (Eq, Show)
-- | Represents the standings edit mode
data EditStandingsMode
= ESMMenu
| ESMHome ESMSubMode
| ESMAway ESMSubMode
deriving (Eq, Show)
-- | Represents the standings edit sub-mode
data ESMSubMode
= ESMSubMenu
| ESMEditWins
| ESMEditLosses
| ESMEditOvertime
| ESMEditGoalsFor
| ESMEditGoalsAgainst
deriving (Eq, Show)
-- | Represents the database -- | Represents the database
data Database = Database data Database = Database
{ _dbPlayers :: [Player] { _dbPlayers :: [Player]
@@ -411,6 +439,8 @@ data Player = Player
-- ^ The player's position -- ^ The player's position
, _pRookie :: Bool , _pRookie :: Bool
-- ^ Indicates that the player is a rookie -- ^ Indicates that the player is a rookie
, _pActive :: Bool
-- ^ Indicates that the player is active
, _pYtd :: PlayerStats , _pYtd :: PlayerStats
-- ^ The Player's year-to-date stats -- ^ The Player's year-to-date stats
, _pLifetime :: PlayerStats , _pLifetime :: PlayerStats
@@ -435,6 +465,8 @@ data Goalie = Goalie
-- ^ The goalie's name -- ^ The goalie's name
, _gRookie :: Bool , _gRookie :: Bool
-- ^ Indicates that the goalie is a rookie -- ^ Indicates that the goalie is a rookie
, _gActive :: Bool
-- ^ Indicates that the goalie is active
, _gYtd :: GoalieStats , _gYtd :: GoalieStats
-- ^ The goalie's year-to-date stats -- ^ The goalie's year-to-date stats
, _gLifetime :: GoalieStats , _gLifetime :: GoalieStats
@@ -555,23 +587,26 @@ instance FromJSON Player where
<*> v .: "name" <*> v .: "name"
<*> v .: "position" <*> v .: "position"
<*> v .:? "rookie" .!= False <*> v .:? "rookie" .!= False
<*> v .:? "active" .!= True
<*> v .:? "ytd" .!= newPlayerStats <*> v .:? "ytd" .!= newPlayerStats
<*> v .:? "lifetime" .!= newPlayerStats <*> v .:? "lifetime" .!= newPlayerStats
instance ToJSON Player where instance ToJSON Player where
toJSON (Player num name pos rk ytd lt) = object toJSON (Player num name pos rk act ytd lt) = object
[ "number" .= num [ "number" .= num
, "name" .= name , "name" .= name
, "position" .= pos , "position" .= pos
, "rookie" .= rk , "rookie" .= rk
, "active" .= act
, "ytd" .= ytd , "ytd" .= ytd
, "lifetime" .= lt , "lifetime" .= lt
] ]
toEncoding (Player num name pos rk ytd lt) = pairs $ toEncoding (Player num name pos rk act ytd lt) = pairs $
"number" .= num <> "number" .= num <>
"name" .= name <> "name" .= name <>
"position" .= pos <> "position" .= pos <>
"rookie" .= rk <> "rookie" .= rk <>
"active" .= act <>
"ytd" .= ytd <> "ytd" .= ytd <>
"lifetime" .= lt "lifetime" .= lt
@@ -597,21 +632,24 @@ instance FromJSON Goalie where
<$> v .: "number" <$> v .: "number"
<*> v .: "name" <*> v .: "name"
<*> v .:? "rookie" .!= False <*> v .:? "rookie" .!= False
<*> v .:? "active" .!= True
<*> v .:? "ytd" .!= newGoalieStats <*> v .:? "ytd" .!= newGoalieStats
<*> v .:? "lifetime" .!= newGoalieStats <*> v .:? "lifetime" .!= newGoalieStats
instance ToJSON Goalie where instance ToJSON Goalie where
toJSON (Goalie num name rk ytd lt) = object toJSON (Goalie num name rk act ytd lt) = object
[ "number" .= num [ "number" .= num
, "name" .= name , "name" .= name
, "ytd" .= ytd , "ytd" .= ytd
, "rookie" .= rk , "rookie" .= rk
, "active" .= act
, "lifetime" .= lt , "lifetime" .= lt
] ]
toEncoding (Goalie num name rk ytd lt) = pairs $ toEncoding (Goalie num name rk act ytd lt) = pairs $
"number" .= num <> "number" .= num <>
"name" .= name <> "name" .= name <>
"rookie" .= rk <> "rookie" .= rk <>
"active" .= act <>
"ytd" .= ytd <> "ytd" .= ytd <>
"lifetime" .= lt "lifetime" .= lt
@@ -702,11 +740,29 @@ editGoalieStateL = lens
_ -> newEditGoalieState) _ -> newEditGoalieState)
(\_ egs -> EditGoalie egs) (\_ egs -> EditGoalie egs)
editStandingsModeL :: Lens' ProgMode EditStandingsMode
editStandingsModeL = lens
(\case
EditStandings esm -> esm
_ -> ESMMenu)
(\_ esm -> EditStandings esm)
esmSubModeL :: Lens' EditStandingsMode ESMSubMode
esmSubModeL = lens
(\case
ESMMenu -> ESMSubMenu
ESMHome m -> m
ESMAway m -> m)
(\mode subMode -> case mode of
ESMMenu -> ESMMenu
ESMHome _ -> ESMHome subMode
ESMAway _ -> ESMAway subMode)
-- | Constructor for a 'ProgState' -- | Constructor for a 'ProgState'
newProgState :: ProgState newProgState :: ProgState
newProgState = ProgState newProgState = ProgState
{ _database = newDatabase { _database = newDatabase
, _progMode = MainMenu , _progMode = TitleScreen
, _inputBuffer = "" , _inputBuffer = ""
, _scrollOffset = 0 , _scrollOffset = 0
} }
@@ -795,6 +851,7 @@ newPlayer num name pos = Player
, _pName = name , _pName = name
, _pPosition = pos , _pPosition = pos
, _pRookie = True , _pRookie = True
, _pActive = True
, _pYtd = newPlayerStats , _pYtd = newPlayerStats
, _pLifetime = newPlayerStats , _pLifetime = newPlayerStats
} }
@@ -818,6 +875,7 @@ newGoalie num name = Goalie
{ _gNumber = num { _gNumber = num
, _gName = name , _gName = name
, _gRookie = True , _gRookie = True
, _gActive = True
, _gYtd = newGoalieStats , _gYtd = newGoalieStats
, _gLifetime = newGoalieStats , _gLifetime = newGoalieStats
} }

View File

@@ -39,6 +39,7 @@ module Mtlstats.Types.Menu (
import Lens.Micro ((^.)) import Lens.Micro ((^.))
import Lens.Micro.TH (makeLenses) import Lens.Micro.TH (makeLenses)
import Mtlstats.Format
import Mtlstats.Types import Mtlstats.Types
-- | Defines a menu -- | Defines a menu
@@ -65,8 +66,15 @@ makeLenses ''Menu
makeLenses ''MenuItem makeLenses ''MenuItem
instance Show (Menu a) where instance Show (Menu a) where
show m = m ^. menuTitle ++ "\n" ++ items show m = unlines
where items = unlines $ map show $ m ^. menuItems $ [ m^.menuTitle
, ""
]
++ body
where
body = map (left width) items
width = maximum $ map length items
items = map show $ m^.menuItems
instance Show (MenuItem a) where instance Show (MenuItem a) where
show i = [i ^. miKey] ++ ") " ++ i ^. miDescription show i = [i ^. miKey] ++ ": " ++ i ^. miDescription

View File

@@ -0,0 +1,83 @@
{-
mtlstats
Copyright (C) 1984, 1985, 2019, 2020 Rhéal Lamothe
<rheal.lamothe@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-}
{-# LANGUAGE LambdaCase #-}
module Actions.EditStandingsSpec (spec) where
import Lens.Micro ((^.), (&), (.~))
import Test.Hspec
( Spec
, context
, describe
, it
, shouldBe
, shouldSatisfy
)
import Mtlstats.Actions.EditStandings
import Mtlstats.Types
spec :: Spec
spec = describe "EditStandings" $ do
mapM_
(\(label, f, expected) -> describe label $ do
let
ps = newProgState
ps' = f ps
it "should set progMode to EditStandings" $
ps'^.progMode `shouldSatisfy` \case
(EditStandings _) -> True
_ -> False
it ("should set editStandingsMode to " ++ show expected) $
ps'^.progMode.editStandingsModeL `shouldBe` expected)
-- label, function, expected mode
[ ( "editStandings", editStandings, ESMMenu )
, ( "editHomeStandings", editHomeStandings, ESMHome ESMSubMenu )
, ( "editAwayStandings", editAwayStandings, ESMAway ESMSubMenu )
]
mapM_
(\(label, f, expected) -> describe label $ do
mapM_
(\prefix -> context ("mode: " ++ show (prefix ESMSubMenu)) $ let
ps = newProgState & progMode.editStandingsModeL .~ prefix ESMSubMenu
ps' = f ps
in it ("should set the mode to " ++ show expected) $
ps'^.progMode.editStandingsModeL `shouldBe` prefix expected)
[ESMHome, ESMAway]
context "mode: ESMMenu" $ let
ps = newProgState & progMode.editStandingsModeL .~ ESMMenu
ps' = f ps
in it "should not change the mode" $
ps'^.progMode.editStandingsModeL `shouldBe` ESMMenu)
-- label, function, expected
[ ( "editWins", editWins, ESMEditWins )
, ( "editLosses", editLosses, ESMEditLosses )
, ( "editOvertime", editOvertime, ESMEditOvertime )
, ( "editGoalsFor", editGoalsFor, ESMEditGoalsFor )
, ( "editGoalsAgainst", editGoalsAgainst, ESMEditGoalsAgainst )
]

View File

@@ -24,7 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
module ActionsSpec (spec) where module ActionsSpec (spec) where
import Control.Monad (replicateM) import Control.Monad (replicateM)
import Lens.Micro ((^.), (&), (.~), (?~)) import Lens.Micro ((^.), (&), (.~), (?~), (%~))
import Test.Hspec import Test.Hspec
( Spec ( Spec
, context , context
@@ -39,6 +39,7 @@ import Mtlstats.Actions
import Mtlstats.Types import Mtlstats.Types
import qualified Actions.NewGameSpec as NewGame import qualified Actions.NewGameSpec as NewGame
import qualified Actions.EditStandingsSpec as EditStandings
import qualified TypesSpec as TS import qualified TypesSpec as TS
spec :: Spec spec :: Spec
@@ -46,6 +47,7 @@ spec = describe "Mtlstats.Actions" $ do
startNewSeasonSpec startNewSeasonSpec
startNewGameSpec startNewGameSpec
resetYtdSpec resetYtdSpec
clearRookiesSpec
resetStandingsSpec resetStandingsSpec
addCharSpec addCharSpec
removeCharSpec removeCharSpec
@@ -64,6 +66,7 @@ spec = describe "Mtlstats.Actions" $ do
scrollUpSpec scrollUpSpec
scrollDownSpec scrollDownSpec
NewGame.spec NewGame.spec
EditStandings.spec
startNewSeasonSpec :: Spec startNewSeasonSpec :: Spec
startNewSeasonSpec = describe "startNewSeason" $ do startNewSeasonSpec = describe "startNewSeason" $ do
@@ -129,6 +132,45 @@ resetYtdSpec = describe "resetYtd" $
lt ^. gsTies `shouldNotBe` 0) $ lt ^. gsTies `shouldNotBe` 0) $
s ^. database . dbGoalies s ^. database . dbGoalies
clearRookiesSpec :: Spec
clearRookiesSpec = describe "clearRookies" $ do
let
players =
[ newPlayer 1 "Joe" "centre" & pRookie .~ True
, newPlayer 2 "Bob" "centre" & pRookie .~ False
]
goalies =
[ newGoalie 3 "Bill" & gRookie .~ True
, newGoalie 4 "Doug" & gRookie .~ False
]
ps = newProgState
& database
%~ (dbPlayers .~ players)
. (dbGoalies .~ goalies)
ps' = clearRookies ps
context "Players" $ mapM_
(\p -> let
name = p^.pName
rFlag = p^.pRookie
in context name $
it "should not be a rookie" $
rFlag `shouldBe` False)
(ps'^.database.dbPlayers)
context "Goalies" $ mapM_
(\g -> let
name = g^.gName
rFlag = g^.gRookie
in context name $
it "should not be a rookie" $
rFlag `shouldBe` False)
(ps'^.database.dbGoalies)
resetStandingsSpec :: Spec resetStandingsSpec :: Spec
resetStandingsSpec = describe "resetStandings" $ do resetStandingsSpec = describe "resetStandings" $ do
let let

View File

@@ -76,10 +76,16 @@ goalieNameSpec = describe "goalieName" $ mapM_
it ("should be " ++ expected) $ it ("should be " ++ expected) $
goalieName g `shouldBe` expected) goalieName g `shouldBe` expected)
-- label, goalie, expected -- label, goalie, expected
[ ( "rookie", goalie True, "foo*" ) [ ( "rookie", rookie, "foo*" )
, ( "non-rookie", goalie False, "foo" ) , ( "non-rookie", active, "foo" )
, ( "retired", retired, "*foo" )
] ]
where where
goalie r = newGoalie 1 "foo" & gRookie .~ r rookie = goalie True True
active = goalie False True
retired = goalie False False
goalie r a = newGoalie 1 "foo"
& gRookie .~ r
& gActive .~ a

View File

@@ -71,9 +71,13 @@ playerNameSpec = describe "playerName" $ mapM_
-- label, player, expected -- label, player, expected
[ ( "rookie", rookie, "foo*" ) [ ( "rookie", rookie, "foo*" )
, ( "non-rookie", nonRookie, "foo" ) , ( "non-rookie", nonRookie, "foo" )
, ( "retired", retired, "*foo" )
] ]
where where
rookie = player True rookie = player True True
nonRookie = player False nonRookie = player False True
player r = newPlayer 1 "foo" "centre" & pRookie .~ r retired = player False False
player r a = newPlayer 1 "foo" "centre"
& pRookie .~ r
& pActive .~ a

View File

@@ -37,11 +37,11 @@ showSpec :: Spec
showSpec = describe "show" $ showSpec = describe "show" $
it "should display correctly" $ let it "should display correctly" $ let
menu = Menu "Foo" () menu = Menu "Foo" ()
[ MenuItem '1' "Item 1" $ return () [ MenuItem '1' "foo" $ return ()
, MenuItem '2' "Item 2" $ return () , MenuItem '2' "bar baz" $ return ()
] ]
expected = expected =
"Foo\n\ "Foo\n\n\
\1) Item 1\n\ \1: foo \n\
\2) Item 2\n" \2: bar baz\n"
in show menu `shouldBe` expected in show menu `shouldBe` expected

View File

@@ -58,6 +58,8 @@ spec = describe "Mtlstats.Types" $ do
createGoalieStateLSpec createGoalieStateLSpec
editPlayerStateLSpec editPlayerStateLSpec
editGoalieStateLSpec editGoalieStateLSpec
editStandingsModeLSpec
esmSubModeLSpec
teamScoreSpec teamScoreSpec
otherScoreSpec otherScoreSpec
homeTeamSpec homeTeamSpec
@@ -191,6 +193,47 @@ editGoalieStateLSpec = describe "editGoalieStateL" $
egs2 = newEditGoalieState egs2 = newEditGoalieState
& egsSelectedGoalie ?~ 2 & egsSelectedGoalie ?~ 2
editStandingsModeLSpec :: Spec
editStandingsModeLSpec = describe "editStandingsModeL" $
lensSpec editStandingsModeL
-- getters
[ ( "missing mode", MainMenu, menu )
, ( "with mode", EditStandings home, home )
]
-- setters
[ ( "set mode", MainMenu, home )
, ( "change mode", EditStandings home, away )
]
where
menu = ESMMenu
home = ESMHome ESMSubMenu
away = ESMAway ESMSubMenu
esmSubModeLSpec :: Spec
esmSubModeLSpec = describe "esmSubModeL" $ do
context "getters" $ mapM_
(\(label, mode, expected) -> context label $
it ("should be " ++ show expected) $
mode^.esmSubModeL `shouldBe` expected)
-- label, mode, expected
[ ( "no state", ESMMenu, ESMSubMenu )
, ( "with state", ESMHome ESMEditWins, ESMEditWins )
]
context "setters" $ mapM_
(\(label, mode, expected) -> context label $
it ("should be " ++ show expected) $ let
mode' = mode & esmSubModeL .~ ESMEditWins
in mode' `shouldBe` expected)
-- label, mode, expected
[ ( "no state", ESMMenu, ESMMenu )
, ( "home mode", ESMHome ESMSubMenu, ESMHome ESMEditWins )
, ( "away mode", ESMAway ESMSubMenu, ESMAway ESMEditWins )
]
teamScoreSpec :: Spec teamScoreSpec :: Spec
teamScoreSpec = describe "teamScore" $ do teamScoreSpec = describe "teamScore" $ do
let let
@@ -281,6 +324,7 @@ playerJSON = Object $ HM.fromList
, ( "name", toJSON ("Joe" :: String) ) , ( "name", toJSON ("Joe" :: String) )
, ( "position", toJSON ("centre" :: String) ) , ( "position", toJSON ("centre" :: String) )
, ( "rookie", toJSON False ) , ( "rookie", toJSON False )
, ( "active", toJSON True )
, ( "ytd", playerStatsJSON 1 ) , ( "ytd", playerStatsJSON 1 )
, ( "lifetime", playerStatsJSON 2 ) , ( "lifetime", playerStatsJSON 2 )
] ]
@@ -309,6 +353,7 @@ goalieJSON = Object $ HM.fromList
[ ( "number", toJSON (1 :: Int) ) [ ( "number", toJSON (1 :: Int) )
, ( "name", toJSON ("Joe" :: String ) ) , ( "name", toJSON ("Joe" :: String ) )
, ( "rookie", toJSON False ) , ( "rookie", toJSON False )
, ( "active", toJSON True )
, ( "ytd", goalieStatsJSON 1 ) , ( "ytd", goalieStatsJSON 1 )
, ( "lifetime", goalieStatsJSON 2 ) , ( "lifetime", goalieStatsJSON 2 )
] ]
@@ -848,6 +893,7 @@ makePlayer = Player
<*> makeName <*> makeName
<*> makeName <*> makeName
<*> makeBool <*> makeBool
<*> makeBool
<*> makePlayerStats <*> makePlayerStats
<*> makePlayerStats <*> makePlayerStats
@@ -857,6 +903,7 @@ makeGoalie = Goalie
<$> makeNum <$> makeNum
<*> makeName <*> makeName
<*> makeBool <*> makeBool
<*> makeBool
<*> makeGoalieStats <*> makeGoalieStats
<*> makeGoalieStats <*> makeGoalieStats
@@ -953,3 +1000,8 @@ instance Comparable CreateGoalieState where
describe "cgsName" $ describe "cgsName" $
it ("should be " ++ expected^.cgsName) $ it ("should be " ++ expected^.cgsName) $
actual^.cgsName `shouldBe` expected^.cgsName actual^.cgsName `shouldBe` expected^.cgsName
instance Comparable EditStandingsMode where
compareTest actual expected =
it ("should be " ++ show expected) $
actual `shouldBe` expected