Support a FlashCard before showing the notes that comprise a chord

My much anticipated feature: first prompt the user for a name of a chord, then
show the user that chord.

Cascading changes:
I changed the "Tap to practice" overlayButton's opacity from 30% to 100% because
pausing when showFlashCard is True causes the two piece

TIL:
You can batch Elm Subscriptions using the Sub.batch function.

What I haven't learned yet:
How to best handle rotating screens for mobile devices (i.e. portrait
vs. landscape modes). In time...

What's left?
- Support sound
- Support a fine-tune section of the preferences
- Support tablet and web browser variants
- Ask users for the "I chord" instead of asking "C major Root position"
- More styling (of course)
This commit is contained in:
William Carroll 2020-04-19 15:32:20 +01:00
parent f92fe97aff
commit d134db700f
5 changed files with 66 additions and 5 deletions

View file

@ -0,0 +1,42 @@
module FlashCard exposing (render)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Responsive
import State
import Tailwind
import Theory
render :
{ chord : Theory.Chord
, visible : Bool
}
-> Html State.Msg
render { chord, visible } =
let
classes =
[ "bg-white"
, "fixed"
, "top-0"
, "left-0"
, "z-30"
, "w-screen"
, "h-screen"
, Tailwind.if_ visible "opacity-100" "opacity-0"
]
in
button
[ classes |> Tailwind.use |> class ]
[ h1
[ [ "text-center"
, "transform"
, "-rotate-90"
, Responsive.h1
]
|> Tailwind.use
|> class
]
[ text (Theory.viewChord chord) ]
]

View file

@ -16,7 +16,10 @@ subscriptions model =
Sub.none Sub.none
else else
Time.every (model.tempo |> Misc.bpmToMilliseconds |> toFloat) (\_ -> State.NextChord) Sub.batch
[ Time.every (model.tempo * 2 |> Misc.bpmToMilliseconds |> toFloat) (\_ -> State.ToggleFlashCard)
, Time.every (model.tempo |> Misc.bpmToMilliseconds |> toFloat) (\_ -> State.NextChord)
]
view : State.Model -> Html State.Msg view : State.Model -> Html State.Msg

View file

@ -1,5 +1,6 @@
module Practice exposing (render) module Practice exposing (render)
import FlashCard
import Html exposing (..) import Html exposing (..)
import Html.Attributes exposing (..) import Html.Attributes exposing (..)
import Html.Events exposing (..) import Html.Events exposing (..)
@ -13,7 +14,7 @@ import UI
openPreferences : Html State.Msg openPreferences : Html State.Msg
openPreferences = openPreferences =
button button
[ class "w-48 h-48 absolute left-0 top-0 z-40" [ class "w-48 h-48 absolute left-0 top-0 z-50"
, onClick (State.SetView State.Preferences) , onClick (State.SetView State.Preferences)
] ]
[ Icon.cog ] [ Icon.cog ]
@ -36,6 +37,15 @@ render model =
, handleClick = handleClick , handleClick = handleClick
, isVisible = model.isPaused , isVisible = model.isPaused
} }
, case model.selectedChord of
Just chord ->
FlashCard.render
{ chord = chord
, visible = model.showFlashCard
}
Nothing ->
span [] []
, Piano.render , Piano.render
{ chord = model.selectedChord { chord = model.selectedChord
, firstNote = model.firstNote , firstNote = model.firstNote

View file

@ -18,6 +18,7 @@ type Msg
| DoNothing | DoNothing
| SetPracticeMode PracticeMode | SetPracticeMode PracticeMode
| SetView View | SetView View
| ToggleFlashCard
type View type View
@ -46,6 +47,7 @@ type alias Model =
, lastNote : Theory.Note , lastNote : Theory.Note
, practiceMode : PracticeMode , practiceMode : PracticeMode
, view : View , view : View
, showFlashCard : Bool
} }
@ -92,10 +94,11 @@ init =
, whitelistedKeys = keys , whitelistedKeys = keys
, selectedChord = Nothing , selectedChord = Nothing
, isPaused = True , isPaused = True
, tempo = 20 , tempo = 10
, firstNote = firstNote , firstNote = firstNote
, lastNote = lastNote , lastNote = lastNote
, view = Overview , view = Overview
, showFlashCard = True
} }
@ -251,3 +254,6 @@ update msg model =
} }
, Cmd.none , Cmd.none
) )
ToggleFlashCard ->
( { model | showFlashCard = not model.showFlashCard }, Cmd.none )

View file

@ -132,7 +132,7 @@ overlayButton { label, handleClick, isVisible } =
, "top-0" , "top-0"
, "left-0" , "left-0"
, "block" , "block"
, "z-30" , "z-40"
, "w-screen" , "w-screen"
, "h-screen" , "h-screen"
, Tailwind.if_ isVisible "opacity-100" "opacity-0" , Tailwind.if_ isVisible "opacity-100" "opacity-0"
@ -140,7 +140,7 @@ overlayButton { label, handleClick, isVisible } =
in in
button button
[ classes |> Tailwind.use |> class [ classes |> Tailwind.use |> class
, style "background-color" "rgba(0,0,0,0.30)" , style "background-color" "rgba(0,0,0,1.0)"
, onClick handleClick , onClick handleClick
] ]
[ h1 [ h1