Last active
September 30, 2019 06:55
-
-
Save bradphelan/06d2e2250facfcf01b848ee71fda4064 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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