Refactor spike
This commit makes it easier to transfer information across screensmain
parent
3b370138aa
commit
85790d4e7b
2
elm.json
2
elm.json
|
@ -14,6 +14,7 @@
|
|||
"icidasset/elm-material-icons": "11.0.0",
|
||||
"kudzu-forest/elm-constant-time-queue": "1.4.0",
|
||||
"mdgriffith/elm-ui": "1.1.8",
|
||||
"micahhahn/elm-safe-recursion": "2.0.0",
|
||||
"noordstar/elm-iddict": "1.0.1",
|
||||
"noordstar/elm-matrix-sdk-beta": "3.6.0",
|
||||
"noordstar/elm-palette": "1.0.0"
|
||||
|
@ -31,7 +32,6 @@
|
|||
"elm/virtual-dom": "1.0.3",
|
||||
"elm-community/intdict": "3.1.0",
|
||||
"fredcy/elm-parseint": "2.0.1",
|
||||
"micahhahn/elm-safe-recursion": "2.0.0",
|
||||
"miniBill/elm-fast-dict": "1.2.1",
|
||||
"noahzgordon/elm-color-extra": "1.0.2",
|
||||
"turboMaCk/queue": "1.1.0"
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
module Items.ItemPicker exposing (..)
|
||||
|
||||
import Iddict exposing (Iddict)
|
||||
import Element exposing (Element)
|
||||
import Layout
|
||||
import Material.Icons
|
||||
import Color exposing (Color)
|
||||
|
||||
-- MODEL
|
||||
|
||||
type alias Model a =
|
||||
{ hover : Maybe Int
|
||||
, items : Iddict a
|
||||
}
|
||||
|
||||
type Msg = OnHover Int | OnHoverOut Int
|
||||
|
||||
init : Iddict a -> Model a
|
||||
init iddict =
|
||||
{ hover = Nothing, items = iddict }
|
||||
|
||||
-- UPDATE
|
||||
|
||||
update : Msg -> Model a -> Model a
|
||||
update msg model =
|
||||
case msg of
|
||||
OnHover i ->
|
||||
{ model | hover = Just i }
|
||||
|
||||
OnHoverOut i ->
|
||||
if model.hover == Just i then
|
||||
{ model | hover = Nothing }
|
||||
else
|
||||
model
|
||||
|
||||
updateContent : (Iddict a -> Iddict a) -> Model a -> Model a
|
||||
updateContent f model =
|
||||
{ model | items = f model.items }
|
||||
|
||||
-- VIEW
|
||||
|
||||
{-| Extract the original data set out of the item picker.
|
||||
-}
|
||||
extract : Model a -> Iddict a
|
||||
extract = .items
|
||||
|
||||
{-| Display the item picker. Note that the item should not be wider than 360px.
|
||||
-}
|
||||
view :
|
||||
{ colorMenu : Color
|
||||
, colorText : Color
|
||||
, height : Int
|
||||
, model : Model a
|
||||
, toText : Int -> a -> String
|
||||
, toTitle : Int -> a -> String
|
||||
, onAddNew : Maybe msg
|
||||
, onClick : Int -> msg
|
||||
, width : Int
|
||||
} -> Element msg
|
||||
view data =
|
||||
Layout.sideList
|
||||
{ color = data.colorMenu
|
||||
, items =
|
||||
data.model.items
|
||||
|> Iddict.toList
|
||||
|> List.map
|
||||
(\( iid, item ) ->
|
||||
Layout.itemWithSubtext
|
||||
{ color = data.colorText
|
||||
, leftIcon = always Element.none
|
||||
, onPress = Just (data.onClick iid)
|
||||
, rightIcon = Layout.iconAsIcon Material.Icons.launch
|
||||
, text = data.toText iid item
|
||||
, title = data.toTitle iid item
|
||||
}
|
||||
)
|
||||
|> (\items ->
|
||||
case data.onAddNew of
|
||||
Nothing ->
|
||||
items
|
||||
|
||||
Just onAddNew ->
|
||||
List.append items
|
||||
[ Layout.itemWithSubtext
|
||||
{ color = data.colorText
|
||||
, leftIcon = Layout.iconAsIcon Material.Icons.add_circle
|
||||
, onPress = Just onAddNew
|
||||
, rightIcon = always Element.none
|
||||
, text = "Click here"
|
||||
, title = "Add new"
|
||||
}
|
||||
]
|
||||
)
|
||||
, width = data.width
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
module Items.LoginScreen exposing (..)
|
||||
module Items.LoginView exposing (..)
|
||||
{-| The Login screen allows the user to log in, as well as view a short display
|
||||
of what to expect from the Matrix client.
|
||||
-}
|
|
@ -0,0 +1,63 @@
|
|||
module Items.VaultList exposing (..)
|
||||
{-| # Vault list
|
||||
|
||||
The vault list contains a list of stored vaults that can be picked from.
|
||||
-}
|
||||
|
||||
import Iddict exposing (Iddict)
|
||||
import Matrix
|
||||
|
||||
-- MODEL
|
||||
|
||||
type alias Model = Iddict VaultBlock
|
||||
|
||||
type Msg
|
||||
= AddVault { name : String, vault : Matrix.Vault }
|
||||
| OnVaultUpdate Int Matrix.VaultUpdate
|
||||
|
||||
type alias VaultBlock =
|
||||
{ logs : List { channel : String, content : String }
|
||||
, name : String
|
||||
, vault : Matrix.Vault
|
||||
}
|
||||
|
||||
init : Model
|
||||
init = Iddict.empty
|
||||
|
||||
-- UPDATE
|
||||
|
||||
addVault : { name : String, vault : Matrix.Vault } -> Model -> Model
|
||||
addVault =
|
||||
AddVault >> update
|
||||
|
||||
insertVaultUpdate : Int -> Matrix.VaultUpdate -> Model -> Model
|
||||
insertVaultUpdate i vu =
|
||||
update (OnVaultUpdate i vu)
|
||||
|
||||
update : Msg -> Model -> Model
|
||||
update msg model =
|
||||
case msg of
|
||||
AddVault { name, vault } ->
|
||||
Iddict.insert { name = name, logs = [], vault = vault } model
|
||||
|> Tuple.second
|
||||
|
||||
OnVaultUpdate i vu ->
|
||||
Iddict.update i
|
||||
(Maybe.map
|
||||
(\block ->
|
||||
{ block
|
||||
| logs =
|
||||
List.append (Matrix.logs vu) block.logs
|
||||
|> List.take 500
|
||||
, vault = Matrix.update vu block.vault
|
||||
}
|
||||
)
|
||||
)
|
||||
model
|
||||
|
||||
-- VIEW
|
||||
|
||||
getVault : Int -> Model -> Maybe Matrix.Vault
|
||||
getVault i model =
|
||||
Iddict.get i model |> Maybe.map .vault
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
module Items.VaultPicker exposing (..)
|
||||
|
||||
import Color exposing (Color)
|
||||
import Element exposing (Element)
|
||||
import Iddict exposing (Iddict)
|
||||
import Material.Icons
|
||||
import Matrix
|
||||
import Layout
|
||||
|
||||
-- MODEL
|
||||
|
||||
type alias Model =
|
||||
{ hover : Maybe Int, vaults : Iddict NamedVault }
|
||||
|
||||
type alias NamedVault = { name : String, vault : Matrix.Vault }
|
||||
|
||||
type Msg
|
||||
= AddVault String Matrix.Vault
|
||||
| OnHover Int
|
||||
| OnHoverOut Int
|
||||
| OnRemoveVault Int
|
||||
|
||||
init : List NamedVault -> Model
|
||||
init items =
|
||||
{ hover = Nothing
|
||||
, vaults =
|
||||
items
|
||||
|> List.indexedMap Tuple.pair
|
||||
|> Iddict.fromList
|
||||
}
|
||||
|
||||
-- UPDATE
|
||||
|
||||
addVault : NamedVault -> Model -> Model
|
||||
addVault data =
|
||||
AddVault data.name data.vault |> update
|
||||
|
||||
update : Msg -> Model -> Model
|
||||
update msg model =
|
||||
case msg of
|
||||
AddVault name vault ->
|
||||
{ model
|
||||
| vaults =
|
||||
model.vaults
|
||||
|> Iddict.insert { name = name, vault = vault }
|
||||
|> Tuple.second
|
||||
}
|
||||
|
||||
OnHover i ->
|
||||
{ model | hover = Just i }
|
||||
|
||||
OnHoverOut i ->
|
||||
case model.hover of
|
||||
Just h ->
|
||||
if i == h then
|
||||
{ model | hover = Nothing }
|
||||
else
|
||||
model
|
||||
|
||||
Nothing ->
|
||||
model
|
||||
|
||||
OnRemoveVault i ->
|
||||
{ model | vaults = Iddict.remove i model.vaults }
|
||||
|
||||
-- VIEW
|
||||
|
||||
getVault : Int -> Model -> Maybe Matrix.Vault
|
||||
getVault i model =
|
||||
Iddict.get i model.vaults |> Maybe.map .vault
|
||||
|
||||
view :
|
||||
{ colorItem : Color
|
||||
, colorList : Color
|
||||
, model : Model
|
||||
, onAddVault : msg
|
||||
, onSelectVault : Int -> msg
|
||||
, width : Int
|
||||
} -> Element msg
|
||||
view data =
|
||||
Layout.sideList
|
||||
{ color = data.colorList
|
||||
, items =
|
||||
data.model.vaults
|
||||
|> Iddict.toList
|
||||
|> List.map
|
||||
(\(vid, { name, vault }) ->
|
||||
Layout.itemWithSubtext
|
||||
{ color = data.colorItem
|
||||
, leftIcon = always Element.none
|
||||
, onPress = Just (data.onSelectVault vid)
|
||||
, rightIcon = Layout.iconAsIcon Material.Icons.launch
|
||||
, text = name
|
||||
, title = "Vault #" ++ String.fromInt vid
|
||||
}
|
||||
)
|
||||
|> (\items ->
|
||||
[ Layout.itemWithSubtext
|
||||
{ color = data.colorItem
|
||||
, leftIcon = Layout.iconAsIcon Material.Icons.add_circle
|
||||
, onPress = Just data.onAddVault
|
||||
, rightIcon = always Element.none
|
||||
, text = "Click here"
|
||||
, title = "Add new"
|
||||
}
|
||||
]
|
||||
|> List.append items
|
||||
)
|
||||
|
||||
}
|
||||
|> Element.el
|
||||
[ Element.width (Element.px data.width) ]
|
|
@ -1,170 +0,0 @@
|
|||
module Items.VaultScreen exposing (..)
|
||||
|
||||
import Color exposing (Color)
|
||||
import Element exposing (Element)
|
||||
import Layout
|
||||
import Matrix
|
||||
import Matrix.Room
|
||||
import Queue exposing (Queue)
|
||||
|
||||
-- MODEL
|
||||
|
||||
type alias Model =
|
||||
{ recentLogs : Queue { channel : String, content : String }
|
||||
, screen : Screen
|
||||
}
|
||||
|
||||
type Msg
|
||||
= OnSwitchScreen Screen
|
||||
| OnVaultUpdate Matrix.VaultUpdate
|
||||
|
||||
type Screen
|
||||
= LandingScreen
|
||||
| Room String
|
||||
|
||||
init : Model
|
||||
init =
|
||||
{ recentLogs = Queue.empty
|
||||
, screen = LandingScreen
|
||||
}
|
||||
|
||||
maxItemsInRecentLogsQueue : Int
|
||||
maxItemsInRecentLogsQueue = 100
|
||||
|
||||
-- UPDATE
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
OnSwitchScreen screen ->
|
||||
( { model | screen = screen }, Cmd.none )
|
||||
|
||||
OnVaultUpdate vu ->
|
||||
( { model
|
||||
| recentLogs =
|
||||
model.recentLogs
|
||||
|> addItemsToQueue (Matrix.logs vu)
|
||||
|> stripQueueToSize maxItemsInRecentLogsQueue
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
addItemsToQueue : List a -> Queue a -> Queue a
|
||||
addItemsToQueue items queue =
|
||||
List.foldl Queue.enqueue queue items
|
||||
|
||||
stripQueueToSize : Int -> Queue a -> Queue a
|
||||
stripQueueToSize i queue =
|
||||
if Queue.length queue > i then
|
||||
stripQueueToSize i (Queue.dequeue queue)
|
||||
else
|
||||
queue
|
||||
|
||||
-- VIEW
|
||||
|
||||
view :
|
||||
{ colorSelectedRoom : Color
|
||||
, colorText : Color
|
||||
, height : Int
|
||||
, model : Model
|
||||
, onVaultUpdate : Matrix.VaultUpdate -> msg
|
||||
, vault : Matrix.Vault
|
||||
, toMsg : Msg -> msg
|
||||
, width : Int
|
||||
} -> Element msg
|
||||
view data =
|
||||
viewScreen
|
||||
{ colorSelectedRoom = data.colorSelectedRoom
|
||||
, colorText = data.colorText
|
||||
, height = data.height
|
||||
, model = data.model
|
||||
, onVaultUpdate = data.onVaultUpdate
|
||||
, vault = data.vault
|
||||
, screen = data.model.screen
|
||||
, toMsg = data.toMsg
|
||||
, width = data.width
|
||||
}
|
||||
|
||||
viewScreen :
|
||||
{ colorSelectedRoom : Color
|
||||
, colorText : Color
|
||||
, height : Int
|
||||
, model : Model
|
||||
, onVaultUpdate : Matrix.VaultUpdate -> msg
|
||||
, vault : Matrix.Vault
|
||||
, screen : Screen
|
||||
, toMsg : Msg -> msg
|
||||
, width : Int
|
||||
} -> Element msg
|
||||
viewScreen data =
|
||||
case data.screen of
|
||||
LandingScreen ->
|
||||
Element.wrappedRow
|
||||
[ Element.height (Element.px data.height)
|
||||
, Element.width (Element.px data.width)
|
||||
]
|
||||
[ viewRoomList
|
||||
{ colorSelected = data.colorSelectedRoom
|
||||
, colorText = data.colorText
|
||||
, rooms = Matrix.rooms data.vault
|
||||
, toMsg = data.toMsg
|
||||
}
|
||||
]
|
||||
|
||||
Room roomId ->
|
||||
case Matrix.fromRoomId roomId data.vault of
|
||||
Just room ->
|
||||
viewRoom
|
||||
{ height = data.height
|
||||
, model = room
|
||||
, toMsg = data.toMsg
|
||||
, width = data.width
|
||||
}
|
||||
|
||||
Nothing ->
|
||||
viewScreen { data | screen = LandingScreen }
|
||||
|
||||
|
||||
viewRoom :
|
||||
{ height : Int
|
||||
, model : Matrix.Room.Room
|
||||
, toMsg : Msg -> msg
|
||||
, width : Int
|
||||
} -> Element msg
|
||||
viewRoom data =
|
||||
[ Matrix.Room.name data.model
|
||||
|> Maybe.withDefault "Nameless room"
|
||||
|> Element.text
|
||||
]
|
||||
|> Element.column []
|
||||
|
||||
viewRoomList :
|
||||
{ colorSelected : Color
|
||||
, colorText : Color
|
||||
, rooms : List Matrix.Room.Room
|
||||
, toMsg : Msg -> msg
|
||||
} -> Element msg
|
||||
viewRoomList data =
|
||||
Layout.sideList
|
||||
{ color = data.colorSelected
|
||||
, items =
|
||||
data.rooms
|
||||
|> List.map
|
||||
(\room ->
|
||||
Layout.itemWithSubtext
|
||||
{ color = data.colorText
|
||||
, leftIcon = always Element.none -- TODO: Add room image
|
||||
, onPress =
|
||||
Matrix.Room.roomId room
|
||||
|> Room
|
||||
|> OnSwitchScreen
|
||||
|> data.toMsg
|
||||
|> Just
|
||||
, rightIcon = always Element.none -- TODO: Choose icon?
|
||||
, text = Matrix.Room.roomId room
|
||||
, title =
|
||||
Matrix.Room.name room
|
||||
|> Maybe.withDefault "Nameless room"
|
||||
}
|
||||
)
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
module Items.WelcomeScreen exposing (..)
|
||||
|
||||
import Color exposing (Color)
|
||||
import Element exposing (Element)
|
||||
import Element.Background
|
||||
import Items.FlavorPicker as FlavorPicker
|
||||
import Items.Introduction as Intro
|
||||
import Items.LoginScreen as Login
|
||||
import Items.VaultPicker as VaultPicker
|
||||
import Matrix
|
||||
import Theme
|
||||
|
||||
-- MODEL
|
||||
|
||||
type alias Model =
|
||||
{ loginView : Maybe Login.Model
|
||||
, vaultView : VaultPicker.Model
|
||||
}
|
||||
|
||||
type Msg
|
||||
= OnAddVault
|
||||
| OnLoginView Login.Msg
|
||||
| OnSubmitVault { name : String, vault : Matrix.Vault }
|
||||
| OnVaultView VaultPicker.Msg
|
||||
|
||||
init : List { name : String, vault : Matrix.Vault } -> Model
|
||||
init vaults =
|
||||
{ loginView = Nothing
|
||||
, vaultView = VaultPicker.init vaults
|
||||
}
|
||||
|
||||
-- UPDATE
|
||||
|
||||
update : Msg -> Model -> Model
|
||||
update msg model =
|
||||
case msg of
|
||||
OnAddVault ->
|
||||
case model.loginView of
|
||||
Just _ ->
|
||||
model
|
||||
|
||||
Nothing ->
|
||||
{ model | loginView = Just Login.init }
|
||||
|
||||
OnLoginView m ->
|
||||
{ model
|
||||
| loginView = Maybe.map (Login.update m) model.loginView
|
||||
}
|
||||
|
||||
OnSubmitVault vault ->
|
||||
{ model
|
||||
| loginView = Nothing
|
||||
, vaultView = VaultPicker.addVault vault model.vaultView
|
||||
}
|
||||
|
||||
OnVaultView m ->
|
||||
{ model
|
||||
| vaultView = VaultPicker.update m model.vaultView
|
||||
}
|
||||
|
||||
-- VIEW
|
||||
|
||||
getVault : Int -> Model -> Maybe Matrix.Vault
|
||||
getVault i model =
|
||||
VaultPicker.getVault i model.vaultView
|
||||
|
||||
view :
|
||||
{ colorBackground : Color
|
||||
, colorBackground2 : Color
|
||||
, colorMain : Color
|
||||
, colorMenu : Color
|
||||
, colorText : Color
|
||||
, colorTextField : Color
|
||||
, height : Int
|
||||
, flavor : Theme.Flavor
|
||||
, model : Model
|
||||
, onFlavorPick : Theme.Flavor -> msg
|
||||
, onSelectVault : Int -> msg
|
||||
, toMsg : Msg -> msg
|
||||
, width : Int
|
||||
} -> Element msg
|
||||
view data =
|
||||
let
|
||||
goesVertical = 2 * data.width <= 3 * data.height
|
||||
direction = if goesVertical then Element.column else Element.row
|
||||
width = if goesVertical then data.width else data.width // 2
|
||||
height = if goesVertical then data.height // 2 else data.height
|
||||
in
|
||||
case data.model.loginView of
|
||||
Just m ->
|
||||
direction
|
||||
[ Element.height (Element.px data.height)
|
||||
, Element.width (Element.px data.width)
|
||||
]
|
||||
[ viewIntroduction
|
||||
{ colorBackground = data.colorBackground
|
||||
, colorItem = data.colorText
|
||||
, colorList = data.colorMenu
|
||||
, height = height
|
||||
, model = data.model.vaultView
|
||||
, onSelectVault = data.onSelectVault
|
||||
, toMsg = data.toMsg
|
||||
, width = width
|
||||
}
|
||||
, Login.view
|
||||
{ colorBackground = data.colorBackground2
|
||||
, colorMain = data.colorMain
|
||||
, colorMenu = data.colorMenu
|
||||
, colorText = data.colorText
|
||||
, colorTextField = data.colorTextField
|
||||
, height = height
|
||||
, flavor = data.flavor
|
||||
, model = m
|
||||
, onFlavorPick = data.onFlavorPick
|
||||
, onSubmit = \vault -> OnSubmitVault { name = "New Vault", vault = vault } |> data.toMsg
|
||||
, toMsg = OnLoginView >> data.toMsg
|
||||
, width = width
|
||||
}
|
||||
]
|
||||
|
||||
Nothing ->
|
||||
viewIntroduction
|
||||
{ colorBackground = data.colorBackground
|
||||
, colorItem = data.colorText
|
||||
, colorList = data.colorMenu
|
||||
, height = data.height
|
||||
, model = data.model.vaultView
|
||||
, onSelectVault = data.onSelectVault
|
||||
, toMsg = data.toMsg
|
||||
, width = data.width
|
||||
}
|
||||
|> Element.el
|
||||
[ Element.Background.color (Theme.toElmUiColor data.colorBackground)
|
||||
, Element.inFront
|
||||
( FlavorPicker.view
|
||||
{ height = 30
|
||||
, flavor = data.flavor
|
||||
, onClick = data.onFlavorPick
|
||||
, themeIcon = always data.colorText
|
||||
, width = 30
|
||||
}
|
||||
|> Element.el [ Element.alignRight ]
|
||||
|> Element.el [ Element.padding 10, Element.width Element.fill ]
|
||||
)
|
||||
]
|
||||
|
||||
viewIntroduction :
|
||||
{ colorBackground : Color
|
||||
, colorItem : Color
|
||||
, colorList : Color
|
||||
, height : Int
|
||||
, model : VaultPicker.Model
|
||||
, onSelectVault : Int -> msg
|
||||
, toMsg : Msg -> msg
|
||||
, width : Int
|
||||
} -> Element msg
|
||||
viewIntroduction data =
|
||||
[ Intro.view
|
||||
{ colorBackground = data.colorBackground
|
||||
, width = data.width
|
||||
}
|
||||
, VaultPicker.view
|
||||
{ colorItem = data.colorItem
|
||||
, colorList = data.colorList
|
||||
, onAddVault = data.toMsg OnAddVault
|
||||
, onSelectVault = data.onSelectVault
|
||||
, model = data.model
|
||||
, width = Basics.min 360 (4 * data.width // 5)
|
||||
}
|
||||
|> Element.el
|
||||
[ Element.centerX
|
||||
]
|
||||
]
|
||||
|> Element.column
|
||||
[ Element.height (Element.px data.height)
|
||||
, Element.scrollbarY
|
||||
, Element.width (Element.px data.width)
|
||||
]
|
|
@ -1,5 +1,5 @@
|
|||
module Layout exposing
|
||||
( tab
|
||||
( tab, twoBlocks
|
||||
, iconAsElement, iconAsIcon
|
||||
, containedButton, outlinedButton, textButton, sideList
|
||||
, textInput, passwordInput
|
||||
|
@ -15,6 +15,10 @@ The layout module exposes some boilerplate functions that have produce a
|
|||
beautiful Material design Elm webpage.
|
||||
|
||||
|
||||
## Screen layout
|
||||
|
||||
@docs twoBlocks
|
||||
|
||||
## Elements
|
||||
|
||||
@docs tab
|
||||
|
@ -197,14 +201,19 @@ singlePalette { primary, onPrimary } =
|
|||
}
|
||||
}
|
||||
|
||||
sideList : { color : Color, items : List (Widget.Item msg) }-> Element msg
|
||||
sideList : { color : Color, items : List (Widget.Item msg), width : Int }-> Element msg
|
||||
sideList data =
|
||||
let
|
||||
width px = Element.width (Element.px px)
|
||||
in
|
||||
Widget.itemList
|
||||
( { primary = data.color, onPrimary = data.color }
|
||||
|> singlePalette
|
||||
|> Material.sideSheet
|
||||
)
|
||||
data.items
|
||||
|> Element.el [ Element.centerX, width (Basics.min 360 data.width) ]
|
||||
|> Element.el [ width data.width ]
|
||||
|
||||
{-| A tab selector that always has an item selected.
|
||||
-}
|
||||
|
@ -275,3 +284,27 @@ textInput data =
|
|||
, label = data.label
|
||||
, onChange = data.onChange
|
||||
}
|
||||
|
||||
{-| Two blocks either next to each other or below each other, depending on the
|
||||
screen shape.
|
||||
-}
|
||||
twoBlocks :
|
||||
{ height : Int
|
||||
, el1 : { height : Int, width : Int } -> Element msg
|
||||
, el2 : { height : Int, width : Int } -> Element msg
|
||||
, width : Int
|
||||
} -> Element msg
|
||||
twoBlocks data =
|
||||
let
|
||||
goesVertical = 2 * data.width <= 3 * data.height
|
||||
direction = if goesVertical then Element.column else Element.row
|
||||
width = if goesVertical then data.width else data.width // 2
|
||||
height = if goesVertical then data.height // 2 else data.height
|
||||
in
|
||||
direction
|
||||
[ Element.height (Element.px data.height)
|
||||
, Element.width (Element.px data.width)
|
||||
]
|
||||
[ data.el1 { height = height, width = width }
|
||||
, data.el2 { height = height, width = width }
|
||||
]
|
||||
|
|
182
src/Main.elm
182
src/Main.elm
|
@ -7,11 +7,12 @@ import Element exposing (Element)
|
|||
import Element.Background
|
||||
import Task
|
||||
import Theme
|
||||
import Items.LoginScreen as LoginScreen
|
||||
import Items.VaultScreen as VaultScreen
|
||||
import Items.WelcomeScreen as WelcomeScreen
|
||||
import Items.VaultList as VaultList
|
||||
import Screen.Welcome as WelcomeScreen
|
||||
import Screen.Vault as VaultScreen
|
||||
import Element.Font
|
||||
import Items.VaultScreen as VaultScreen
|
||||
import Recursion
|
||||
import Matrix
|
||||
|
||||
|
||||
main : Program () Model Msg
|
||||
|
@ -36,25 +37,26 @@ type alias Model =
|
|||
}
|
||||
|
||||
type Screen
|
||||
= ScreenLogin LoginScreen.Model
|
||||
| ScreenWelcome WelcomeScreen.Model
|
||||
| ScreenVault WelcomeScreen.Model Int VaultScreen.Model
|
||||
= ScreenWelcome WelcomeScreen.Model
|
||||
| ScreenVault Vaults Int VaultScreen.Model
|
||||
|
||||
type Msg
|
||||
= OnScreenLogin LoginScreen.Msg
|
||||
| OnScreenVault Int VaultScreen.Msg
|
||||
= OnScreenVault Int VaultScreen.Msg
|
||||
| OnScreenWelcome WelcomeScreen.Msg
|
||||
| OnSelectVault Int
|
||||
| OnSelectVault Vaults Int
|
||||
| OnVaultUpdate Int Matrix.VaultUpdate
|
||||
| Pass
|
||||
| ScreenSize { height : Int, width : Int }
|
||||
| SetFlavor Theme.Flavor
|
||||
|
||||
type alias Vaults = VaultList.Model
|
||||
|
||||
|
||||
init : () -> ( Model, Cmd Msg )
|
||||
init () =
|
||||
( { flavor = Theme.Latte
|
||||
, height = 480
|
||||
, screen = ScreenWelcome (WelcomeScreen.init [])
|
||||
, screen = ScreenWelcome WelcomeScreen.init
|
||||
, width = 720
|
||||
}
|
||||
, Browser.Dom.getViewport
|
||||
|
@ -75,26 +77,14 @@ init () =
|
|||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
OnScreenLogin m ->
|
||||
case model.screen of
|
||||
ScreenLogin mdl ->
|
||||
case LoginScreen.update m mdl of
|
||||
newMdl ->
|
||||
( { model | screen = ScreenLogin newMdl }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
_ ->
|
||||
( model, Cmd.none )
|
||||
|
||||
OnScreenVault i m ->
|
||||
case model.screen of
|
||||
ScreenVault welcomeMdl j mdl ->
|
||||
if i == j then
|
||||
case VaultScreen.update m mdl of
|
||||
( newMdl, cmd ) ->
|
||||
newMdl ->
|
||||
( { model | screen = ScreenVault welcomeMdl i newMdl }
|
||||
, Cmd.map (OnScreenVault i) cmd
|
||||
, Cmd.none
|
||||
)
|
||||
else
|
||||
( model, Cmd.none )
|
||||
|
@ -114,23 +104,35 @@ update msg model =
|
|||
_ ->
|
||||
( model, Cmd.none )
|
||||
|
||||
OnSelectVault i ->
|
||||
case model.screen of
|
||||
ScreenVault welcomeMdl j _ ->
|
||||
if i == j then
|
||||
( model, Cmd.none )
|
||||
else
|
||||
( { model | screen = ScreenVault welcomeMdl i VaultScreen.init }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
ScreenWelcome mdl ->
|
||||
( { model | screen = ScreenVault mdl i VaultScreen.init }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
_ ->
|
||||
( model, Cmd.none )
|
||||
OnSelectVault vaults i ->
|
||||
( { model
|
||||
| screen =
|
||||
case model.screen of
|
||||
ScreenWelcome _ ->
|
||||
ScreenVault vaults i VaultScreen.init
|
||||
|
||||
ScreenVault _ j old ->
|
||||
if i == j then
|
||||
ScreenVault vaults j old
|
||||
else
|
||||
ScreenVault vaults i VaultScreen.init
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
OnVaultUpdate i vu ->
|
||||
( { model
|
||||
| screen =
|
||||
case model.screen of
|
||||
ScreenWelcome mdl ->
|
||||
WelcomeScreen.updateVault i vu mdl
|
||||
|> ScreenWelcome
|
||||
|
||||
ScreenVault vaults j mdl ->
|
||||
ScreenVault (VaultList.insertVaultUpdate i vu vaults) j mdl
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
Pass ->
|
||||
( model, Cmd.none )
|
||||
|
@ -174,54 +176,54 @@ view model =
|
|||
|
||||
viewScreen : Model -> Element Msg
|
||||
viewScreen model =
|
||||
case model.screen of
|
||||
ScreenLogin mdl ->
|
||||
LoginScreen.view
|
||||
{ colorBackground = Theme.base model.flavor
|
||||
, colorMain = Theme.mauve model.flavor
|
||||
, colorMenu = Theme.mantle model.flavor
|
||||
, colorText = Theme.text model.flavor
|
||||
, colorTextField = Theme.surface0 model.flavor
|
||||
, flavor = model.flavor
|
||||
, height = model.height
|
||||
, model = mdl
|
||||
, onFlavorPick = SetFlavor
|
||||
, onSubmit = always Pass
|
||||
, toMsg = OnScreenLogin
|
||||
, width = model.width
|
||||
}
|
||||
|
||||
ScreenVault welcomeMdl i mdl ->
|
||||
case WelcomeScreen.getVault i welcomeMdl of
|
||||
Just vault ->
|
||||
VaultScreen.view
|
||||
{ colorSelectedRoom = Theme.mantle model.flavor
|
||||
, colorText = Theme.text model.flavor
|
||||
, height = model.height
|
||||
, model = mdl
|
||||
, onVaultUpdate = always Pass
|
||||
, toMsg = OnScreenVault i
|
||||
, vault = vault
|
||||
, width = model.width
|
||||
}
|
||||
let
|
||||
colorBackground = Theme.base model.flavor
|
||||
colorBackground2 = Theme.mantle model.flavor
|
||||
colorMain = Theme.mauve model.flavor
|
||||
colorSurface0 = Theme.surface0 model.flavor
|
||||
colorSurface1 = Theme.surface1 model.flavor
|
||||
colorText = Theme.text model.flavor
|
||||
in
|
||||
Recursion.runRecursion
|
||||
(\screen ->
|
||||
case screen of
|
||||
ScreenVault vaults i mdl ->
|
||||
case VaultList.getVault i vaults of
|
||||
Just vault ->
|
||||
VaultScreen.view
|
||||
{ colorBackground = colorBackground
|
||||
, colorText = colorText
|
||||
, height = model.height
|
||||
, model = mdl
|
||||
, onVaultUpdate = OnVaultUpdate i
|
||||
, toMsg = OnScreenVault i
|
||||
, vault = vault
|
||||
, width = model.width
|
||||
}
|
||||
|> Recursion.base
|
||||
|
||||
Nothing ->
|
||||
viewScreen { model | screen = ScreenWelcome welcomeMdl }
|
||||
Nothing ->
|
||||
WelcomeScreen.fromVaults vaults
|
||||
|> ScreenWelcome
|
||||
|> Recursion.recurse
|
||||
|
||||
ScreenWelcome mdl ->
|
||||
WelcomeScreen.view
|
||||
{ colorBackground = Theme.base model.flavor
|
||||
, colorBackground2 = Theme.mantle model.flavor
|
||||
, colorMain = Theme.mauve model.flavor
|
||||
, colorMenu = Theme.surface0 model.flavor
|
||||
, colorText = Theme.text model.flavor
|
||||
, colorTextField = Theme.surface1 model.flavor
|
||||
, flavor = model.flavor
|
||||
, height = model.height
|
||||
, model = mdl
|
||||
, onFlavorPick = SetFlavor
|
||||
, onSelectVault = OnSelectVault
|
||||
, toMsg = OnScreenWelcome
|
||||
, width = model.width
|
||||
}
|
||||
ScreenWelcome mdl ->
|
||||
WelcomeScreen.view
|
||||
{ colorBackground = colorBackground
|
||||
, colorBackground2 = colorBackground2
|
||||
, colorMain = colorMain
|
||||
, colorMenu = colorSurface0
|
||||
, colorText = colorText
|
||||
, colorTextField = colorSurface1
|
||||
, flavor = model.flavor
|
||||
, height = model.height
|
||||
, model = mdl
|
||||
, onFlavorPick = SetFlavor
|
||||
, onSelectVault = OnSelectVault
|
||||
, toMsg = OnScreenWelcome
|
||||
, width = model.width
|
||||
}
|
||||
|> Recursion.base
|
||||
)
|
||||
model.screen
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
module Screen.Vault exposing (..)
|
||||
|
||||
import Color exposing (Color)
|
||||
import Element exposing (Element)
|
||||
import Matrix
|
||||
|
||||
-- MODEL
|
||||
|
||||
type alias Model = ()
|
||||
|
||||
type alias Msg = ()
|
||||
|
||||
init : Model
|
||||
init = ()
|
||||
|
||||
-- UPDATE
|
||||
|
||||
update : Msg -> Model -> Model
|
||||
update msg model =
|
||||
case msg of
|
||||
() ->
|
||||
model
|
||||
|
||||
-- VIEW
|
||||
|
||||
view :
|
||||
{ colorBackground : Color
|
||||
, colorText : Color
|
||||
, height : Int
|
||||
, model : Model
|
||||
, onVaultUpdate : Matrix.VaultUpdate -> msg
|
||||
, toMsg : Msg -> msg
|
||||
, vault : Matrix.Vault
|
||||
, width : Int
|
||||
} -> Element msg
|
||||
view data =
|
||||
Element.none
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
module Screen.Welcome exposing (..)
|
||||
|
||||
import Color exposing (Color)
|
||||
import Items.Introduction as Introduction
|
||||
import Items.ItemPicker as ItemPicker
|
||||
import Items.VaultList as VaultList
|
||||
import Matrix
|
||||
import Items.LoginView as LoginView
|
||||
import Element exposing (Element)
|
||||
import Layout
|
||||
import Matrix.Settings
|
||||
import Theme
|
||||
|
||||
-- MODEL
|
||||
|
||||
type alias Model =
|
||||
{ login : Maybe LoginView.Model
|
||||
, vaults : ItemPicker.Model VaultList.VaultBlock
|
||||
}
|
||||
|
||||
type Msg
|
||||
= OnAddNew
|
||||
| OnLogin LoginView.Msg
|
||||
| OnSubmitVault { name : String, vault : Matrix.Vault }
|
||||
| OnVaultUpdate Int Matrix.VaultUpdate
|
||||
| OnVaults ItemPicker.Msg
|
||||
|
||||
init : Model
|
||||
init =
|
||||
{ login = Nothing -- Just LoginView.init
|
||||
, vaults = ItemPicker.init VaultList.init
|
||||
}
|
||||
|
||||
fromVaults : VaultList.Model -> Model
|
||||
fromVaults items =
|
||||
{ login = Nothing
|
||||
, vaults = ItemPicker.init items
|
||||
}
|
||||
|
||||
-- UPDATE
|
||||
|
||||
update : Msg -> Model -> Model
|
||||
update msg model =
|
||||
case msg of
|
||||
OnAddNew ->
|
||||
{ model | login = Just LoginView.init }
|
||||
|
||||
OnLogin m ->
|
||||
{ model | login = Maybe.map (LoginView.update m) model.login }
|
||||
|
||||
OnSubmitVault block ->
|
||||
{ login = Nothing
|
||||
, vaults = ItemPicker.updateContent (VaultList.addVault block) model.vaults
|
||||
}
|
||||
|
||||
OnVaultUpdate i vu ->
|
||||
{ model | vaults = ItemPicker.updateContent (VaultList.insertVaultUpdate i vu) model.vaults }
|
||||
|
||||
OnVaults m ->
|
||||
{ model | vaults = ItemPicker.update m model.vaults }
|
||||
|
||||
updateVault : Int -> Matrix.VaultUpdate -> Model -> Model
|
||||
updateVault i vu =
|
||||
update (OnVaultUpdate i vu)
|
||||
|
||||
-- VIEW
|
||||
|
||||
view :
|
||||
{ colorBackground : Color
|
||||
, colorBackground2 : Color
|
||||
, colorMain : Color
|
||||
, colorMenu : Color
|
||||
, colorText : Color
|
||||
, colorTextField : Color
|
||||
, flavor : Theme.Flavor
|
||||
, height : Int
|
||||
, model : Model
|
||||
, onFlavorPick : Theme.Flavor -> msg
|
||||
, onSelectVault : VaultList.Model -> Int -> msg
|
||||
, toMsg : Msg -> msg
|
||||
, width : Int
|
||||
} -> Element msg
|
||||
view data =
|
||||
let
|
||||
onSelectVault = data.onSelectVault (ItemPicker.extract data.model.vaults)
|
||||
in
|
||||
case data.model.login of
|
||||
Just login ->
|
||||
Layout.twoBlocks
|
||||
{ height = data.height
|
||||
, el1 =
|
||||
\{ height, width } ->
|
||||
viewIntroduction
|
||||
{ colorBackground = data.colorBackground
|
||||
, colorMenu = data.colorMenu
|
||||
, colorText = data.colorText
|
||||
, height = height
|
||||
, model = data.model.vaults
|
||||
, onAddNew = Nothing
|
||||
, onSelectVault = onSelectVault
|
||||
, width = width
|
||||
}
|
||||
, el2 =
|
||||
\{ height, width } ->
|
||||
LoginView.view
|
||||
{ colorBackground = data.colorBackground2
|
||||
, colorMain = data.colorMain
|
||||
, colorMenu = data.colorMenu
|
||||
, colorText = data.colorText
|
||||
, colorTextField = data.colorTextField
|
||||
, height = height
|
||||
, flavor = data.flavor
|
||||
, model = login
|
||||
, onFlavorPick = data.onFlavorPick
|
||||
, onSubmit = \vault -> OnSubmitVault { name = "New Vault", vault = vault } |> data.toMsg
|
||||
, toMsg = OnLogin >> data.toMsg
|
||||
, width = width
|
||||
}
|
||||
, width = data.width
|
||||
}
|
||||
|
||||
Nothing ->
|
||||
viewIntroduction
|
||||
{ colorBackground = data.colorBackground
|
||||
, colorMenu = data.colorMenu
|
||||
, colorText = data.colorText
|
||||
, height = data.height
|
||||
, model = data.model.vaults
|
||||
, onAddNew = Just (data.toMsg OnAddNew)
|
||||
, onSelectVault = onSelectVault
|
||||
, width = data.width
|
||||
}
|
||||
|
||||
|
||||
viewIntroduction :
|
||||
{ colorBackground : Color
|
||||
, colorMenu : Color
|
||||
, colorText : Color
|
||||
, height : Int
|
||||
, model : ItemPicker.Model VaultList.VaultBlock
|
||||
, onAddNew : Maybe msg
|
||||
, onSelectVault : Int -> msg
|
||||
, width : Int
|
||||
} -> Element msg
|
||||
viewIntroduction data =
|
||||
[ Introduction.view { colorBackground = data.colorBackground, width = data.width }
|
||||
, ItemPicker.view
|
||||
{ colorMenu = data.colorMenu
|
||||
, colorText = data.colorText
|
||||
, height = data.height
|
||||
, model = data.model
|
||||
, toText = \_ vb -> Matrix.Settings.getDeviceName vb.vault
|
||||
, toTitle = \vid vb -> vb.name ++ " #" ++ String.fromInt (vid + 1)
|
||||
, onAddNew = data.onAddNew
|
||||
, onClick = data.onSelectVault
|
||||
, width = data.width
|
||||
}
|
||||
]
|
||||
|> Element.column
|
||||
[ Element.height (Element.px data.height)
|
||||
, Element.scrollbarY
|
||||
, Element.width (Element.px data.width)
|
||||
]
|
Loading…
Reference in New Issue