Skip to content

Instantly share code, notes, and snippets.

@bradphelan
Last active September 30, 2019 06:55
Show Gist options
  • Save bradphelan/06d2e2250facfcf01b848ee71fda4064 to your computer and use it in GitHub Desktop.
Save bradphelan/06d2e2250facfcf01b848ee71fda4064 to your computer and use it in GitHub Desktop.
namespace XoaDotNet
open Avalonia.Controls
open Avalonia.Media
open Avalonia.FuncUI.Types
open Avalonia.FuncUI
open Avalonia.Layout
open FSharpx.Collections
open Bogus
[<AutoOpen>]
module Helpers =
let pvSet = PersistentVector.update
let pvGet = PersistentVector.nth
let pvAdd = PersistentVector.conj
let pvDel id =
Seq.indexed
>> Seq.where ( fun (_id,_)->id<>_id)
>> Seq.map (fun (_,p)->p)
>> PersistentVector.ofSeq
type IndexedMessage<'Msg> = ( int*'Msg )
let itemTemplate view dispatch =
Avalonia.Controls.Templates.FuncDataTemplate<(int*'state)>( ( fun (id,state) ->
let viewElement = (view state id dispatch)
let view = viewElement |> VirtualDom.createView
let delta = Avalonia.FuncUI.VirtualDom.Delta.ViewDelta.From viewElement
VirtualDom.Patcher.patch(view, delta)
view
) ,false)
module PersonModule =
type PersonState = {
name : string
age : int
}
let f = Faker()
let personGen() : PersonState = {
name = f.Name.FirstName()
age = f.Random.Number(10,99)
}
type PersonMsg =
| EditName of string
| EditAge of int
let update (msg:PersonMsg) (state:PersonState) : PersonState =
match msg with
| EditName name -> { state with name = name }
| EditAge age -> {state with age = age}
let updateNth (msg:PersonMsg) id state =
pvSet id (update msg (pvGet id state)) state
let view (state:PersonState) (dispatch) : View =
Views.uniformGrid [
Attrs.columns 2
Attrs.children [
Views.textBox [
Attrs.text state.name
Attrs.onKeyUp(fun sender args ->
dispatch (EditName (sender :?> TextBox).Text)
)
]
Views.textBox [
Attrs.text (sprintf "%d" state.age)
Attrs.onKeyUp(fun sender args ->
dispatch (EditAge ((sender :?> TextBox).Text |> int))
)
]
]
]
module PersonsModule =
type PersonsMsg =
| Update of IndexedMessage<PersonModule.PersonMsg>
| Delete of int
let update (personsMsg:PersonsMsg) state =
match personsMsg with
| Update (id, msg) -> pvSet id (PersonModule.update msg (pvGet id state)) state
| Delete id -> pvDel id state
let itemView (person:PersonModule.PersonState) (id:int) dispatch : View =
// Set up a dispatcher for a person at a specific id
let dispatchPerson id = (fun msg -> dispatch(Update(id,msg)))
Views.dockpanel [
Attrs.children [
Views.button [
Attrs.dockPanel_dock Dock.Left
Attrs.content "X"
Attrs.onClick ( fun sender args -> dispatch (PersonsMsg.Delete id) )
]
Views.textBlock [
Attrs.text (id |> sprintf("%d"))
]
PersonModule.view person (dispatchPerson id)
]
]
let view (state:PersonModule.PersonState PersistentVector) (dispatch) : View =
Views.listBox [
//Attrs.virtualizationMode ItemVirtualizationMode.Simple
Attrs.itemTemplate (itemTemplate itemView dispatch )
Attrs.items (state |> Seq.indexed |> PersistentVector.ofSeq )
]
module ParentView =
open Bogus
// The model holds data that you want to keep track of while the application is running
type ParentState = {
people : PersonModule.PersonState PersistentVector
}
let rec barConjGen n state =
match n with
| 0 -> state
| n -> state |> PersistentVector.conj (PersonModule.personGen()) |> barConjGen (n-1)
//The initial state of of the application
let initialState = {
people = PersistentVector.empty |> barConjGen 30
}
type ParentViewMsg =
| PersonsMsg of PersonsModule.PersonsMsg
| NewPerson
let update (msg: ParentViewMsg) (state: ParentState) : ParentState =
match msg with
| PersonsMsg msg -> { state with people = PersonsModule.update msg state.people }
| NewPerson -> { state with people = state.people |> barConjGen 1 }
let view (state: ParentState) (dispatch): View =
Views.dockpanel[
Attrs.children [
Views.button [
Attrs.dockPanel_dock Dock.Bottom
Attrs.content "new"
Attrs.onClick (fun sender args -> dispatch ParentViewMsg.NewPerson)
]
PersonsModule.view state.people (PersonsMsg >> dispatch)
]
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment