Skip to content

Commit

Permalink
Merge pull request #51 from TimLariviere/enumerator-for-diffing
Browse files Browse the repository at this point in the history
Enumerator for diffing
  • Loading branch information
TimLariviere authored Jan 19, 2022
2 parents 8754324 + 47a3fac commit 540d0ba
Show file tree
Hide file tree
Showing 21 changed files with 777 additions and 679 deletions.
2 changes: 1 addition & 1 deletion src/Fabulous.Tests/APISketchTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ module SimpleStackTests =

// add first
instance.ProcessMessage(AddNew(1, "yo"))
Assert.AreEqual(stack.Children.Count, 1)
Assert.AreEqual(1, stack.Children.Count)

let label =
stack.Children.[0] :?> TestLabel :> IText
Expand Down
2 changes: 1 addition & 1 deletion src/Fabulous.Tests/TestUI.Attributes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module Attributes =
ConvertValue = id
Compare = ScalarAttributeComparers.noCompare
UpdateNode =
fun (newValueOpt, node) ->
fun newValueOpt node ->

let btn = node.Target :?> IButton

Expand Down
8 changes: 4 additions & 4 deletions src/Fabulous.Tests/TestUI.ViewUpdaters.fs
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,19 @@ open Tests.Platform
// navigationPage.PushAsync(page) |> ignore


let updateText (newValueOpt: string voption, node: IViewNode) =
let updateText (newValueOpt: string voption) (node: IViewNode) =
let textElement = node.Target :?> IText
textElement.Text <- ValueOption.defaultValue "" newValueOpt

let updateRecord (newValueOpt: bool voption, node: IViewNode) =
let updateRecord (newValueOpt: bool voption) (node: IViewNode) =
let textElement = node.Target :?> TestLabel
textElement.record <- ValueOption.defaultValue false newValueOpt

let updateTextColor (newValueOpt: string voption, node: IViewNode) =
let updateTextColor (newValueOpt: string voption) (node: IViewNode) =
let textElement = node.Target :?> IText
textElement.TextColor <- ValueOption.defaultValue "" newValueOpt

let updateAutomationId (newValueOpt: string voption, node: IViewNode) =
let updateAutomationId (newValueOpt: string voption) (node: IViewNode) =
let el = node.Target :?> TestViewElement
el.AutomationId <- ValueOption.defaultValue "" newValueOpt

Expand Down
2 changes: 1 addition & 1 deletion src/Fabulous.Tests/TestUI.Widgets.fs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ module Widgets =
CreateView =
fun (widget, context, parentNode) ->
let name = typeof<'T>.Name
printfn $"Creating view for {name}"
// printfn $"Creating view for {name}"

let view = new 'T()
let weakReference = WeakReference(view)
Expand Down
6 changes: 3 additions & 3 deletions src/Fabulous.XamarinForms/Attributes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ module Attributes =
(bindableProperty: BindableProperty)
(convert: 'inputType -> 'modelType)
(convertValue: 'modelType -> 'valueType)
(compare: 'modelType * 'modelType -> ScalarAttributeComparison)
(compare: 'modelType -> 'modelType -> ScalarAttributeComparison)
=
Attributes.defineScalarWithConverter<'inputType, 'modelType, 'valueType>
bindableProperty.PropertyName
convert
convertValue
compare
(fun (newValueOpt, node) ->
(fun newValueOpt node ->
let target = node.Target :?> BindableObject

match newValueOpt with
Expand All @@ -53,7 +53,7 @@ module Attributes =
id
id
ScalarAttributeComparers.equalityCompare
(fun (newValueOpt, node) ->
(fun newValueOpt node ->
let target = node.Target :?> BindableObject

match newValueOpt with
Expand Down
26 changes: 8 additions & 18 deletions src/Fabulous.XamarinForms/ViewUpdaters.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ open Fabulous
open Xamarin.Forms

module ViewUpdaters =
let updateSliderMinMax (newValueOpt: (float * float) voption, node: IViewNode) =
let updateSliderMinMax (newValueOpt: struct (float * float) voption) (node: IViewNode) =
let slider = node.Target :?> Slider

match newValueOpt with
Expand All @@ -22,7 +22,7 @@ module ViewUpdaters =
slider.SetValue(Slider.MinimumProperty, min)
slider.SetValue(Slider.MaximumProperty, max)

let updateStepperMinMax (newValueOpt: (float * float) voption, node: IViewNode) =
let updateStepperMinMax (newValueOpt: struct (float * float) voption) (node: IViewNode) =
let stepper = node.Target :?> Stepper

match newValueOpt with
Expand All @@ -40,7 +40,7 @@ module ViewUpdaters =
stepper.SetValue(Stepper.MinimumProperty, min)
stepper.SetValue(Stepper.MaximumProperty, max)

let updateGridColumnDefinitions (newValueOpt: Dimension [] voption, node: IViewNode) =
let updateGridColumnDefinitions (newValueOpt: Dimension [] voption) (node: IViewNode) =
let grid = node.Target :?> Grid

match newValueOpt with
Expand All @@ -58,7 +58,7 @@ module ViewUpdaters =

grid.ColumnDefinitions.Add(ColumnDefinition(Width = gridLength))

let updateGridRowDefinitions (newValueOpt: Dimension [] voption, node: IViewNode) =
let updateGridRowDefinitions (newValueOpt: Dimension [] voption) (node: IViewNode) =
let grid = node.Target :?> Grid

match newValueOpt with
Expand All @@ -78,11 +78,11 @@ module ViewUpdaters =

/// NOTE: Would be better to have a custom diff logic for Navigation
/// because it's a Stack and not a random access collection
let applyDiffNavigationPagePages (diffs: ArraySlice<WidgetCollectionItemChange>, node: IViewNode) =
let applyDiffNavigationPagePages (diffs: WidgetCollectionItemChanges) (node: IViewNode) =
let navigationPage = node.Target :?> NavigationPage
let pages = List.ofSeq navigationPage.Pages

for diff in ArraySlice.toSpan diffs do
for diff in diffs do
match diff with
| WidgetCollectionItemChange.Insert (index, widget) ->
if index >= pages.Length then
Expand Down Expand Up @@ -110,17 +110,7 @@ module ViewUpdaters =
let childNode =
node.TreeContext.GetViewNode(box pages.[index])

match diff.ScalarChanges with
| ValueSome changes -> childNode.ApplyScalarDiffs(changes)
| ValueNone -> ()

match diff.WidgetChanges with
| ValueSome slice -> childNode.ApplyWidgetDiffs(ArraySlice.toSpan slice)
| ValueNone -> ()

match diff.WidgetCollectionChanges with
| ValueSome slice -> childNode.ApplyWidgetCollectionDiffs(ArraySlice.toSpan slice)
| ValueNone -> ()
childNode.ApplyDiff(&diff)


| WidgetCollectionItemChange.Replace (index, widget) ->
Expand Down Expand Up @@ -163,7 +153,7 @@ module ViewUpdaters =
navigationPage.PushAsync(temp.Pop(), false)
|> ignore

let updateNavigationPagePages (newValueOpt: ArraySlice<Widget> voption, node: IViewNode) =
let updateNavigationPagePages (newValueOpt: ArraySlice<Widget> voption) (node: IViewNode) =
let navigationPage = node.Target :?> NavigationPage
navigationPage.PopToRootAsync(false) |> ignore

Expand Down
4 changes: 2 additions & 2 deletions src/Fabulous.XamarinForms/WidgetExtensions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module AdditionalAttributes =
let UseSafeArea =
Attributes.define<bool>
"Page_UseSafeArea"
(fun (newValueOpt, node) ->
(fun newValueOpt node ->
let page = node.Target :?> Xamarin.Forms.Page

let value =
Expand All @@ -28,7 +28,7 @@ module AdditionalAttributes =
let ToolbarPlacement =
Attributes.define<ToolbarPlacement>
"TabbedPage_ToolbarPlacement"
(fun (newValueOpt, node) ->
(fun newValueOpt node ->
let tabbedPage = node.Target :?> Xamarin.Forms.TabbedPage

let value =
Expand Down
18 changes: 9 additions & 9 deletions src/Fabulous.XamarinForms/Xamarin.Forms.Core.Attributes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module Application =
let Resources =
Attributes.define<Xamarin.Forms.ResourceDictionary>
"Application_Resources"
(fun (newValueOpt, node) ->
(fun newValueOpt node ->
let application =
node.Target :?> Xamarin.Forms.Application

Expand All @@ -29,7 +29,7 @@ module Application =
let UserAppTheme =
Attributes.define<Xamarin.Forms.OSAppTheme>
"Application_UserAppTheme"
(fun (newValueOpt, node) ->
(fun newValueOpt node ->
let application =
node.Target :?> Xamarin.Forms.Application

Expand Down Expand Up @@ -241,7 +241,7 @@ module Switch =

module Slider =
let MinimumMaximum =
Attributes.define<float * float> "Slider_MinimumMaximum" ViewUpdaters.updateSliderMinMax
Attributes.define<struct (float * float)> "Slider_MinimumMaximum" ViewUpdaters.updateSliderMinMax

let Value =
Attributes.defineBindable<float> Xamarin.Forms.Slider.ValueProperty
Expand Down Expand Up @@ -399,7 +399,7 @@ module ToolbarItem =
let Order =
Attributes.define<Xamarin.Forms.ToolbarItemOrder>
"ToolbarItem_Order"
(fun (newValueOpt, node) ->
(fun newValueOpt node ->
let toolbarItem =
node.Target :?> Xamarin.Forms.ToolbarItem

Expand Down Expand Up @@ -495,7 +495,7 @@ module Stepper =
Attributes.defineBindable<float> Xamarin.Forms.Stepper.IncrementProperty

let MinimumMaximum =
Attributes.define<float * float> "Stepper_MinimumMaximum" ViewUpdaters.updateStepperMinMax
Attributes.define<struct (float * float)> "Stepper_MinimumMaximum" ViewUpdaters.updateStepperMinMax

let Value =
Attributes.defineBindable<float> Xamarin.Forms.Stepper.ValueProperty
Expand All @@ -515,7 +515,7 @@ module ItemsView =
for x in modelValue.OriginalItems do
modelValue.Template x
})
(fun (a, b) -> ScalarAttributeComparers.equalityCompare (a.OriginalItems, b.OriginalItems))
(fun a b -> ScalarAttributeComparers.equalityCompare a.OriginalItems b.OriginalItems)

let GroupedItemsSource<'T> =
Attributes.defineBindableWithComparer<GroupedWidgetItems<'T>, GroupedWidgetItems<'T>, IEnumerable<GroupItem>>
Expand All @@ -526,7 +526,7 @@ module ItemsView =
for x in modelValue.OriginalItems do
modelValue.Template x
})
(fun (a, b) -> ScalarAttributeComparers.equalityCompare (a.OriginalItems, b.OriginalItems))
(fun a b -> ScalarAttributeComparers.equalityCompare a.OriginalItems b.OriginalItems)

module ItemsViewOfCell =
let ItemsSource<'T> =
Expand All @@ -539,7 +539,7 @@ module ItemsViewOfCell =
for x in modelValue.OriginalItems do
modelValue.Template x
})
(fun (a, b) -> ScalarAttributeComparers.equalityCompare (a.OriginalItems, b.OriginalItems))
(fun a b -> ScalarAttributeComparers.equalityCompare a.OriginalItems b.OriginalItems)

let GroupedItemsSource<'T> =
Attributes.defineBindableWithComparer<GroupedWidgetItems<'T>, GroupedWidgetItems<'T>, IEnumerable<GroupItem>>
Expand All @@ -551,7 +551,7 @@ module ItemsViewOfCell =
for x in modelValue.OriginalItems do
modelValue.Template x
})
(fun (a, b) -> ScalarAttributeComparers.equalityCompare (a.OriginalItems, b.OriginalItems))
(fun a b -> ScalarAttributeComparers.equalityCompare a.OriginalItems b.OriginalItems)

module ListView =
let RowHeight =
Expand Down
4 changes: 2 additions & 2 deletions src/Fabulous.XamarinForms/Xamarin.Forms.Core.fs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ type ViewBuilders private () =
ViewKeys.Slider,
Slider.Value.WithValue(value),
Slider.ValueChanged.WithValue(fun args -> onValueChanged args.NewValue |> box),
Slider.MinimumMaximum.WithValue(min, max)
Slider.MinimumMaximum.WithValue(struct (min, max))
)

static member inline ActivityIndicator<'msg>(isRunning: bool) =
Expand Down Expand Up @@ -398,7 +398,7 @@ type ViewBuilders private () =
ViewKeys.Stepper,
Stepper.Value.WithValue(value),
Stepper.ValueChanged.WithValue(fun args -> onValueChanged args.NewValue |> box),
Stepper.MinimumMaximum.WithValue((min, max))
Stepper.MinimumMaximum.WithValue(struct (min, max))
)

static member inline ListView<'msg, 'itemData, 'itemMarker when 'itemMarker :> ICell>(items: seq<'itemData>) =
Expand Down
40 changes: 18 additions & 22 deletions src/Fabulous/AttributeDefinitions.fs
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
namespace Fabulous

open Fabulous
open System.Collections.Generic
open Fabulous

type IAttributeDefinition =
abstract member Key: AttributeKey
abstract member UpdateNode: newValueOpt: obj voption * node: IViewNode -> unit

[<Struct; RequireQualifiedAccess>]
type ScalarAttributeComparison =
| Identical
| Different
abstract member UpdateNode: obj voption -> IViewNode -> unit

type IScalarAttributeDefinition =
inherit IAttributeDefinition
abstract member CompareBoxed: a: obj * b: obj -> ScalarAttributeComparison
abstract member CompareBoxed: a: obj -> b: obj -> ScalarAttributeComparison


/// Attribute definition for scalar properties
type ScalarAttributeDefinition<'inputType, 'modelType, 'valueType> =
{ Key: AttributeKey
Name: string
Convert: 'inputType -> 'modelType
ConvertValue: 'modelType -> 'valueType
Compare: 'modelType * 'modelType -> ScalarAttributeComparison
UpdateNode: 'valueType voption * IViewNode -> unit }
Compare: 'modelType -> 'modelType -> ScalarAttributeComparison
UpdateNode: 'valueType voption -> IViewNode -> unit }

member x.WithValue(value) : ScalarAttribute =
{ Key = x.Key
Expand All @@ -35,23 +31,23 @@ type ScalarAttributeDefinition<'inputType, 'modelType, 'valueType> =
interface IScalarAttributeDefinition with
member x.Key = x.Key

member x.CompareBoxed(a, b) =
x.Compare(unbox<'modelType> a, unbox<'modelType> b)
member x.CompareBoxed a b =
x.Compare(unbox<'modelType> a) (unbox<'modelType> b)

member x.UpdateNode(newValueOpt, node) =
member x.UpdateNode newValueOpt node =
let newValueOpt =
match newValueOpt with
| ValueNone -> ValueNone
| ValueSome v -> ValueSome(x.ConvertValue(unbox<'modelType> v))

x.UpdateNode(newValueOpt, node)
x.UpdateNode newValueOpt node

/// Attribute definition for widget properties
type WidgetAttributeDefinition =
{ Key: AttributeKey
Name: string
ApplyDiff: WidgetDiff * IViewNode -> unit
UpdateNode: Widget voption * IViewNode -> unit }
ApplyDiff: WidgetDiff -> IViewNode -> unit
UpdateNode: Widget voption -> IViewNode -> unit }

member x.WithValue(value: Widget) : WidgetAttribute =
{ Key = x.Key
Expand All @@ -63,20 +59,20 @@ type WidgetAttributeDefinition =
interface IAttributeDefinition with
member x.Key = x.Key

member x.UpdateNode(newValueOpt, node) =
member x.UpdateNode newValueOpt node =
let newValueOpt =
match newValueOpt with
| ValueNone -> ValueNone
| ValueSome v -> ValueSome(unbox<Widget> v)

x.UpdateNode(newValueOpt, node)
x.UpdateNode newValueOpt node

/// Attribute definition for collection properties
type WidgetCollectionAttributeDefinition =
{ Key: AttributeKey
Name: string
ApplyDiff: ArraySlice<WidgetCollectionItemChange> * IViewNode -> unit
UpdateNode: ArraySlice<Widget> voption * IViewNode -> unit }
ApplyDiff: WidgetCollectionItemChanges -> IViewNode -> unit
UpdateNode: ArraySlice<Widget> voption -> IViewNode -> unit }

member x.WithValue(value: ArraySlice<Widget>) : WidgetCollectionAttribute =
{ Key = x.Key
Expand All @@ -88,13 +84,13 @@ type WidgetCollectionAttributeDefinition =
interface IAttributeDefinition with
member x.Key = x.Key

member x.UpdateNode(newValueOpt, node) =
member x.UpdateNode newValueOpt node =
let newValueOpt =
match newValueOpt with
| ValueNone -> ValueNone
| ValueSome v -> ValueSome(unbox<ArraySlice<Widget>> v)

x.UpdateNode(newValueOpt, node)
x.UpdateNode newValueOpt node

module AttributeDefinitionStore =
let private _attributes =
Expand Down
Loading

0 comments on commit 540d0ba

Please sign in to comment.