diff --git a/CHANGELOG.md b/CHANGELOG.md index b677cda..3d64e16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 _No unreleased changes_ +## [8.0.5] - 2024-01-10 + +### Changed +- Additional performance optimizations by @TimLariviere (https://github.com/fabulous-dev/Fabulous.MauiControls/pull/55) + ## [8.0.4] - 2024-01-08 ### Changed @@ -150,8 +155,9 @@ Essentially v2.8.1 and v8.0.0 are similar except for the required .NET version. ### Changed - Fabulous.MauiControls has moved from the Fabulous repository to its own repository: [https://github.com/fabulous-dev/Fabulous.MauiControls](https://github.com/fabulous-dev/Fabulous.MauiControls) -[unreleased]: https://github.com/fabulous-dev/Fabulous.MauiControls/compare/8.0.3...HEAD -[8.0.3]: https://github.com/fabulous-dev/Fabulous.MauiControls/releases/tag/8.0.3 +[unreleased]: https://github.com/fabulous-dev/Fabulous.MauiControls/compare/8.0.5...HEAD +[8.0.5]: https://github.com/fabulous-dev/Fabulous.MauiControls/releases/tag/8.0.5 +[8.0.4]: https://github.com/fabulous-dev/Fabulous.MauiControls/releases/tag/8.0.4 [8.0.2]: https://github.com/fabulous-dev/Fabulous.MauiControls/releases/tag/8.0.2 [8.0.1]: https://github.com/fabulous-dev/Fabulous.MauiControls/releases/tag/8.0.1 [8.0.0]: https://github.com/fabulous-dev/Fabulous.MauiControls/releases/tag/8.0.0 diff --git a/src/Fabulous.MauiControls/AppHostBuilderExtensions.fs b/src/Fabulous.MauiControls/AppHostBuilderExtensions.fs index 22c5b7a..1180b0d 100644 --- a/src/Fabulous.MauiControls/AppHostBuilderExtensions.fs +++ b/src/Fabulous.MauiControls/AppHostBuilderExtensions.fs @@ -10,16 +10,28 @@ open System type AppHostBuilderExtensions = [] static member UseFabulousApp(this: MauiAppBuilder, program: Program) : MauiAppBuilder = - this.UseMauiApp(fun (_serviceProvider: IServiceProvider) -> (Program.startApplication program) :> Microsoft.Maui.IApplication) + this.UseMauiApp(fun (_serviceProvider: IServiceProvider) -> + let app = Program.startApplication program + Theme.ListenForChanges(app) + app) [] static member UseFabulousApp(this: MauiAppBuilder, program: Program>) : MauiAppBuilder = - this.UseMauiApp(fun (_serviceProvider: IServiceProvider) -> (Program.startApplicationMemo program) :> Microsoft.Maui.IApplication) + this.UseMauiApp(fun (_serviceProvider: IServiceProvider) -> + let app = Program.startApplicationMemo program + Theme.ListenForChanges(app) + app) [] static member UseFabulousApp(this: MauiAppBuilder, program: Program<'arg, 'model, 'msg, #IFabApplication>, arg: 'arg) : MauiAppBuilder = - this.UseMauiApp(fun (_serviceProvider: IServiceProvider) -> (Program.startApplicationWithArgs arg program) :> Microsoft.Maui.IApplication) + this.UseMauiApp(fun (_serviceProvider: IServiceProvider) -> + let app = Program.startApplicationWithArgs arg program + Theme.ListenForChanges(app) + app) [] static member UseFabulousApp(this: MauiAppBuilder, program: Program<'arg, 'model, 'msg, Memo.Memoized<#IFabApplication>>, arg: 'arg) : MauiAppBuilder = - this.UseMauiApp(fun (_serviceProvider: IServiceProvider) -> (Program.startApplicationWithArgsMemo arg program) :> Microsoft.Maui.IApplication) + this.UseMauiApp(fun (_serviceProvider: IServiceProvider) -> + let app = Program.startApplicationWithArgsMemo arg program + Theme.ListenForChanges(app) + app) diff --git a/src/Fabulous.MauiControls/Attributes.fs b/src/Fabulous.MauiControls/Attributes.fs index bd616fe..110715f 100644 --- a/src/Fabulous.MauiControls/Attributes.fs +++ b/src/Fabulous.MauiControls/Attributes.fs @@ -5,6 +5,15 @@ open Fabulous open Fabulous.ScalarAttributeDefinitions open Microsoft.Maui.Controls open System +open System.IO +open Microsoft.Maui + +[] +type ImageSourceValue = + | Source of source: IImageSource + | File of file: string + | Uri of uri: Uri + | Stream of stream: Stream [] type ValueEventData<'data, 'eventArgs> = @@ -106,6 +115,28 @@ module Attributes = | ValueNone -> target.ClearValue(bindableProperty) | ValueSome v -> target.SetValue(bindableProperty, v)) + /// Performance optimization: avoid allocating a new ImageSource instance on each update + /// we store the user value (eg. string, Uri, Stream) and convert it to an ImageSource only when needed + let inline defineBindableImageSource (bindableProperty: BindableProperty) = + Attributes.defineScalar + bindableProperty.PropertyName + id + ScalarAttributeComparers.equalityCompare + (fun _ newValueOpt node -> + let target = node.Target :?> BindableObject + + match newValueOpt with + | ValueNone -> target.ClearValue(bindableProperty) + | ValueSome v -> + let value = + match v with + | ImageSourceValue.Source source -> source + | ImageSourceValue.File file -> ImageSource.FromFile file + | ImageSourceValue.Uri uri -> ImageSource.FromUri uri + | ImageSourceValue.Stream stream -> ImageSource.FromStream(fun () -> stream) + + target.SetValue(bindableProperty, value)) + /// Define an attribute storing a Widget for a bindable property let inline defineBindableWidget (bindableProperty: BindableProperty) = Attributes.definePropertyWidget diff --git a/src/Fabulous.MauiControls/Fabulous.MauiControls.fsproj b/src/Fabulous.MauiControls/Fabulous.MauiControls.fsproj index 15c460d..d9fdda7 100644 --- a/src/Fabulous.MauiControls/Fabulous.MauiControls.fsproj +++ b/src/Fabulous.MauiControls/Fabulous.MauiControls.fsproj @@ -1,6 +1,8 @@ - + - net8.0 + false + + net8.0 true true @@ -152,9 +154,12 @@ This version will be used as the lower bound in the NuGet package --> - + + + + diff --git a/src/Fabulous.MauiControls/ThemeAware.fs b/src/Fabulous.MauiControls/ThemeAware.fs index 94e4d2c..7f5c726 100644 --- a/src/Fabulous.MauiControls/ThemeAware.fs +++ b/src/Fabulous.MauiControls/ThemeAware.fs @@ -1,16 +1,22 @@ namespace Fabulous.Maui +open Microsoft.Maui.Controls open Microsoft.Maui.ApplicationModel open Fabulous open Fabulous.Maui +[] +type Theme = + static let mutable _currentTheme = AppTheme.Unspecified + static member Current = _currentTheme + + static member ListenForChanges(app: Application) = + app.RequestedThemeChanged.Add(fun args -> _currentTheme <- args.RequestedTheme) + [] type ThemeAware = static member With(light: 'T, dark: 'T) = - if AppInfo.RequestedTheme = AppTheme.Dark then - dark - else - light + if Theme.Current = AppTheme.Dark then dark else light module ThemeAwareProgram = type Model<'model> = { Theme: AppTheme; Model: 'model } @@ -22,9 +28,7 @@ module ThemeAwareProgram = let init (init: 'arg -> 'model * Cmd<'msg>) (arg: 'arg) = let model, cmd = init arg - { Theme = AppInfo.RequestedTheme - Model = model }, - Cmd.map ModelMsg cmd + { Theme = Theme.Current; Model = model }, Cmd.map ModelMsg cmd let update (update: 'msg * 'model -> 'model * Cmd<'msg>) (msg: Msg<'msg>, model: Model<'model>) = match msg with diff --git a/src/Fabulous.MauiControls/Views/Cells/ImageCell.fs b/src/Fabulous.MauiControls/Views/Cells/ImageCell.fs index d44873d..ee4c0c0 100644 --- a/src/Fabulous.MauiControls/Views/Cells/ImageCell.fs +++ b/src/Fabulous.MauiControls/Views/Cells/ImageCell.fs @@ -12,8 +12,7 @@ type IFabImageCell = module ImageCell = let WidgetKey = Widgets.register() - let ImageSource = - Attributes.defineBindableWithEquality ImageCell.ImageSourceProperty + let ImageSource = Attributes.defineBindableImageSource ImageCell.ImageSourceProperty [] module ImageCellBuilders = @@ -23,25 +22,37 @@ module ImageCellBuilders = /// The text of the cell /// The image source static member inline ImageCell<'msg>(text: string, source: ImageSource) = - WidgetBuilder<'msg, IFabImageCell>(ImageCell.WidgetKey, TextCell.Text.WithValue(text), ImageCell.ImageSource.WithValue(source)) + WidgetBuilder<'msg, IFabImageCell>( + ImageCell.WidgetKey, + TextCell.Text.WithValue(text), + ImageCell.ImageSource.WithValue(ImageSourceValue.Source source) + ) /// Create an ImageCell widget with a text and an image source /// The text of the cell /// The image source static member inline ImageCell<'msg>(text: string, source: string) = - View.ImageCell<'msg>(text, ImageSource.FromFile(source)) + WidgetBuilder<'msg, IFabImageCell>( + ImageCell.WidgetKey, + TextCell.Text.WithValue(text), + ImageCell.ImageSource.WithValue(ImageSourceValue.File source) + ) /// Create an ImageCell widget with a text and an image source /// The text of the cell /// The image source static member inline ImageCell<'msg>(text: string, source: Uri) = - View.ImageCell<'msg>(text, ImageSource.FromUri(source)) + WidgetBuilder<'msg, IFabImageCell>(ImageCell.WidgetKey, TextCell.Text.WithValue(text), ImageCell.ImageSource.WithValue(ImageSourceValue.Uri source)) /// Create an ImageCell widget with a text and an image source /// The text of the cell /// The image source static member inline ImageCell<'msg>(text: string, source: Stream) = - View.ImageCell<'msg>(text, ImageSource.FromStream(fun () -> source)) + WidgetBuilder<'msg, IFabImageCell>( + ImageCell.WidgetKey, + TextCell.Text.WithValue(text), + ImageCell.ImageSource.WithValue(ImageSourceValue.Stream source) + ) [] type ImageCellModifiers = diff --git a/src/Fabulous.MauiControls/Views/Controls/Button.fs b/src/Fabulous.MauiControls/Views/Controls/Button.fs index 4779fe4..4719329 100644 --- a/src/Fabulous.MauiControls/Views/Controls/Button.fs +++ b/src/Fabulous.MauiControls/Views/Controls/Button.fs @@ -40,8 +40,7 @@ module Button = let FontSize = Attributes.defineBindableFloat Button.FontSizeProperty - let ImageSource = - Attributes.defineBindableWithEquality Button.ImageSourceProperty + let ImageSource = Attributes.defineBindableImageSource Button.ImageSourceProperty let LineBreakMode = Attributes.defineBindableWithEquality Button.LineBreakModeProperty @@ -156,7 +155,7 @@ type ButtonModifiers = /// The image source [] static member inline image(this: WidgetBuilder<'msg, #IFabButton>, source: ImageSource) = - this.AddScalar(Button.ImageSource.WithValue(source)) + this.AddScalar(Button.ImageSource.WithValue(ImageSourceValue.Source source)) /// Set the line break mode /// Current widget @@ -211,23 +210,24 @@ type ButtonModifiers = type ButtonExtraModifiers = /// Set the image source /// Current widget - /// The image source + /// The image source [] - static member inline image(this: WidgetBuilder<'msg, #IFabButton>, source: string) = - this.image(ImageSource.FromFile(source)) + static member inline image(this: WidgetBuilder<'msg, #IFabButton>, value: string) = + this.AddScalar(Button.ImageSource.WithValue(ImageSourceValue.File value)) /// Set the image source /// Current widget - /// The image source + /// The image source [] - static member inline image(this: WidgetBuilder<'msg, #IFabButton>, source: Uri) = this.image(ImageSource.FromUri(source)) + static member inline image(this: WidgetBuilder<'msg, #IFabButton>, value: Uri) = + this.AddScalar(Button.ImageSource.WithValue(ImageSourceValue.Uri value)) /// Set the image source /// Current widget - /// The image source + /// The image source [] - static member inline image(this: WidgetBuilder<'msg, #IFabButton>, source: Stream) = - this.image(ImageSource.FromStream(fun () -> source)) + static member inline image(this: WidgetBuilder<'msg, #IFabButton>, value: Stream) = + this.AddScalar(Button.ImageSource.WithValue(ImageSourceValue.Stream value)) /// Set the padding inside the button /// Current widget diff --git a/src/Fabulous.MauiControls/Views/Controls/Image.fs b/src/Fabulous.MauiControls/Views/Controls/Image.fs index 94d710d..be17bd6 100644 --- a/src/Fabulous.MauiControls/Views/Controls/Image.fs +++ b/src/Fabulous.MauiControls/Views/Controls/Image.fs @@ -22,24 +22,7 @@ module Image = let IsOpaque = Attributes.defineBindableBool Image.IsOpaqueProperty - let Source = Attributes.defineBindableWithEquality Image.SourceProperty - - /// Performance optimization: avoid allocating a new ImageSource instance on each update - /// we store the user value (eg. string, Uri, Stream) and convert it to an ImageSource only when needed - let inline private defineSourceAttribute<'model when 'model: equality> ([] convertModelToValue: 'model -> ImageSource) = - Attributes.defineScalar<'model, 'model> Image.SourceProperty.PropertyName id ScalarAttributeComparers.equalityCompare (fun _ newValueOpt node -> - let target = node.Target :?> Image - - match newValueOpt with - | ValueNone -> target.ClearValue(Image.SourceProperty) - | ValueSome v -> target.SetValue(Image.SourceProperty, convertModelToValue v)) - - let SourceFile = defineSourceAttribute ImageSource.FromFile - - let SourceUri = defineSourceAttribute ImageSource.FromUri - - let SourceStream = - defineSourceAttribute(fun stream -> ImageSource.FromStream(fun () -> stream)) + let Source = Attributes.defineBindableImageSource Image.SourceProperty [] module ImageBuilders = @@ -48,46 +31,46 @@ module ImageBuilders = /// Create an Image widget with a source /// The image source static member inline Image<'msg>(source: ImageSource) = - WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(source)) + WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.Source source)) /// Create an Image widget with a source and an aspect /// The image source /// The image aspect static member inline Image<'msg>(source: ImageSource, aspect: Aspect) = - WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(source), Image.Aspect.WithValue(aspect)) + WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.Source source), Image.Aspect.WithValue(aspect)) /// Create an Image widget with a source /// The image source static member inline Image<'msg>(source: string) = - WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.SourceFile.WithValue(source)) + WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.File source)) /// Create an Image widget with a source and an aspect /// The image source /// The image aspect static member inline Image<'msg>(source: string, aspect: Aspect) = - WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.SourceFile.WithValue(source), Image.Aspect.WithValue(aspect)) + WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.File source), Image.Aspect.WithValue(aspect)) /// Create an Image widget with a source /// The image source static member inline Image<'msg>(source: Uri) = - WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.SourceUri.WithValue(source)) + WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.Uri source)) /// Create an Image widget with a source and an aspect /// The image source /// The image aspect static member inline Image<'msg>(source: Uri, aspect: Aspect) = - WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.SourceUri.WithValue(source), Image.Aspect.WithValue(aspect)) + WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.Uri source), Image.Aspect.WithValue(aspect)) /// Create an Image widget with a source /// The image source static member inline Image<'msg>(source: Stream) = - WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.SourceStream.WithValue(source)) + WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.Stream source)) /// Create an Image widget with a source and an aspect /// The image source /// The image aspect static member inline Image<'msg>(source: Stream, aspect: Aspect) = - WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.SourceStream.WithValue(source), Image.Aspect.WithValue(aspect)) + WidgetBuilder<'msg, IFabImage>(Image.WidgetKey, Image.Source.WithValue(ImageSourceValue.Stream source), Image.Aspect.WithValue(aspect)) [] type ImageModifiers = diff --git a/src/Fabulous.MauiControls/Views/Controls/ImageButton.fs b/src/Fabulous.MauiControls/Views/Controls/ImageButton.fs index 898f01f..29ed6e3 100644 --- a/src/Fabulous.MauiControls/Views/Controls/ImageButton.fs +++ b/src/Fabulous.MauiControls/Views/Controls/ImageButton.fs @@ -41,7 +41,7 @@ module ImageButton = let Released = Attributes.defineEventNoArg "ImageButton_Released" (fun target -> (target :?> ImageButton).Released) - let Source = Attributes.defineBindableWithEquality ImageButton.SourceProperty + let Source = Attributes.defineBindableImageSource ImageButton.SourceProperty [] module ImageButtonBuilders = @@ -54,7 +54,7 @@ module ImageButtonBuilders = WidgetBuilder<'msg, IFabImageButton>( ImageButton.WidgetKey, ImageButton.Clicked.WithValue(MsgValue(onClicked)), - ImageButton.Source.WithValue(source) + ImageButton.Source.WithValue(ImageSourceValue.Source source) ) /// Create an ImageButton with an image source and an aspect and listen for the Click event @@ -65,7 +65,7 @@ module ImageButtonBuilders = WidgetBuilder<'msg, IFabImageButton>( ImageButton.WidgetKey, ImageButton.Clicked.WithValue(MsgValue(onClicked)), - ImageButton.Source.WithValue(source), + ImageButton.Source.WithValue(ImageSourceValue.Source source), ImageButton.Aspect.WithValue(aspect) ) @@ -73,40 +73,67 @@ module ImageButtonBuilders = /// The image source /// Message to dispatch static member inline ImageButton<'msg>(source: string, onClicked: 'msg) = - View.ImageButton(ImageSource.FromFile(source), onClicked) + WidgetBuilder<'msg, IFabImageButton>( + ImageButton.WidgetKey, + ImageButton.Clicked.WithValue(MsgValue(onClicked)), + ImageButton.Source.WithValue(ImageSourceValue.File source) + ) /// Create an ImageButton with an image source and an aspect and listen for the Click event /// The image source /// Message to dispatch /// The aspect value static member inline ImageButton<'msg>(source: string, onClicked: 'msg, aspect: Aspect) = - View.ImageButton(ImageSource.FromFile(source), onClicked, aspect) + WidgetBuilder<'msg, IFabImageButton>( + ImageButton.WidgetKey, + ImageButton.Clicked.WithValue(MsgValue(onClicked)), + ImageButton.Source.WithValue(ImageSourceValue.File source), + ImageButton.Aspect.WithValue(aspect) + ) /// Create an ImageButton with an image source and listen for the Click event /// The image source /// Message to dispatch static member inline ImageButton<'msg>(source: Uri, onClicked: 'msg) = - View.ImageButton(ImageSource.FromUri(source), onClicked) + WidgetBuilder<'msg, IFabImageButton>( + ImageButton.WidgetKey, + ImageButton.Clicked.WithValue(MsgValue(onClicked)), + ImageButton.Source.WithValue(ImageSourceValue.Uri source) + ) /// Create an ImageButton with an image source and an aspect and listen for the Click event /// The image source /// Message to dispatch /// The aspect value static member inline ImageButton<'msg>(source: Uri, onClicked: 'msg, aspect: Aspect) = - View.ImageButton(ImageSource.FromUri(source), onClicked, aspect) + WidgetBuilder<'msg, IFabImageButton>( + ImageButton.WidgetKey, + ImageButton.Clicked.WithValue(MsgValue(onClicked)), + ImageButton.Source.WithValue(ImageSourceValue.Uri source), + ImageButton.Aspect.WithValue(aspect) + ) /// Create an ImageButton with an image source and listen for the Click event /// The image source /// Message to dispatch static member inline ImageButton<'msg>(source: Stream, onClicked: 'msg) = - View.ImageButton(ImageSource.FromStream(fun () -> source), onClicked) + WidgetBuilder<'msg, IFabImageButton>( + ImageButton.WidgetKey, + ImageButton.Clicked.WithValue(MsgValue(onClicked)), + ImageButton.Source.WithValue(ImageSourceValue.Stream source) + ) /// Create an ImageButton with an image source and an aspect and listen for the Click event /// The image source /// Message to dispatch /// The aspect value static member inline ImageButton<'msg>(source: Stream, onClicked: 'msg, aspect: Aspect) = - View.ImageButton(ImageSource.FromStream(fun () -> source), onClicked, aspect) + WidgetBuilder<'msg, IFabImageButton>( + ImageButton.WidgetKey, + ImageButton.Clicked.WithValue(MsgValue(onClicked)), + ImageButton.Source.WithValue(ImageSourceValue.Stream source), + ImageButton.Aspect.WithValue(aspect) + ) [] type ImageButtonModifiers = diff --git a/src/Fabulous.MauiControls/Views/Controls/Slider.fs b/src/Fabulous.MauiControls/Views/Controls/Slider.fs index 8d854c1..b6dab16 100644 --- a/src/Fabulous.MauiControls/Views/Controls/Slider.fs +++ b/src/Fabulous.MauiControls/Views/Controls/Slider.fs @@ -49,7 +49,7 @@ module Slider = let ThumbColor = Attributes.defineBindableColor Slider.ThumbColorProperty let ThumbImageSource = - Attributes.defineBindableWithEquality Slider.ThumbImageSourceProperty + Attributes.defineBindableImageSource Slider.ThumbImageSourceProperty let ValueWithEvent = Attributes.defineBindableWithEvent "Slider_ValueWithEvent" Slider.ValueProperty (fun target -> (target :?> Slider).ValueChanged) @@ -112,7 +112,7 @@ type SliderModifiers = /// The image source of the thumb [] static member inline thumbImage(this: WidgetBuilder<'msg, #IFabSlider>, value: ImageSource) = - this.AddScalar(Slider.ThumbImageSource.WithValue(value)) + this.AddScalar(Slider.ThumbImageSource.WithValue(ImageSourceValue.Source value)) /// Link a ViewRef to access the direct Slider control instance /// Current widget @@ -128,18 +128,18 @@ type SliderExtraModifiers = /// The image source of the thumb [] static member inline thumbImage(this: WidgetBuilder<'msg, #IFabSlider>, value: string) = - this.thumbImage(ImageSource.FromFile(value)) + this.AddScalar(Slider.ThumbImageSource.WithValue(ImageSourceValue.File value)) /// Set the image source of the thumb /// Current widget /// The image source of the thumb [] static member inline thumbImage(this: WidgetBuilder<'msg, #IFabSlider>, value: Uri) = - this.thumbImage(ImageSource.FromUri(value)) + this.AddScalar(Slider.ThumbImageSource.WithValue(ImageSourceValue.Uri value)) /// Set the image source of the thumb /// Current widget /// The image source of the thumb [] static member inline thumbImage(this: WidgetBuilder<'msg, #IFabSlider>, value: Stream) = - this.thumbImage(ImageSource.FromStream(fun () -> value)) + this.AddScalar(Slider.ThumbImageSource.WithValue(ImageSourceValue.Stream value)) diff --git a/src/Fabulous.MauiControls/Views/MenuItems/MenuItem.fs b/src/Fabulous.MauiControls/Views/MenuItems/MenuItem.fs index 4b56b6f..db73648 100644 --- a/src/Fabulous.MauiControls/Views/MenuItems/MenuItem.fs +++ b/src/Fabulous.MauiControls/Views/MenuItems/MenuItem.fs @@ -21,7 +21,7 @@ module MenuItem = Attributes.defineEventNoArg "MenuItem_Clicked" (fun target -> (target :?> MenuItem).Clicked) let IconImageSource = - Attributes.defineBindableWithEquality MenuItem.IconImageSourceProperty + Attributes.defineBindableImageSource MenuItem.IconImageSourceProperty let IsDestructive = Attributes.defineBindableBool MenuItem.IsDestructiveProperty @@ -52,7 +52,7 @@ type MenuItemModifiers = /// The source of the icon image [] static member inline icon(this: WidgetBuilder<'msg, #IFabMenuItem>, value: ImageSource) = - this.AddScalar(MenuItem.IconImageSource.WithValue(value)) + this.AddScalar(MenuItem.IconImageSource.WithValue(ImageSourceValue.Source value)) /// Set a value that indicates whether or not the menu item removes its associated widget /// Current widget @@ -74,17 +74,19 @@ type MenuItemExtraModifiers = /// Current widget /// The source of the icon image [] - static member inline icon(this: WidgetBuilder<'msg, #IFabMenuItem>, value: string) = this.icon(ImageSource.FromFile(value)) + static member inline icon(this: WidgetBuilder<'msg, #IFabMenuItem>, value: string) = + this.AddScalar(MenuItem.IconImageSource.WithValue(ImageSourceValue.File value)) /// Set the source of the icon image /// Current widget /// The source of the icon image [] - static member inline icon(this: WidgetBuilder<'msg, #IFabMenuItem>, value: Uri) = this.icon(ImageSource.FromUri(value)) + static member inline icon(this: WidgetBuilder<'msg, #IFabMenuItem>, value: Uri) = + this.AddScalar(MenuItem.IconImageSource.WithValue(ImageSourceValue.Uri value)) /// Set the source of the icon image /// Current widget /// The source of the icon image [] static member inline icon(this: WidgetBuilder<'msg, #IFabMenuItem>, value: Stream) = - this.icon(ImageSource.FromStream(fun () -> value)) + this.AddScalar(MenuItem.IconImageSource.WithValue(ImageSourceValue.Stream value)) diff --git a/src/Fabulous.MauiControls/Views/Pages/NavigationPage.fs b/src/Fabulous.MauiControls/Views/Pages/NavigationPage.fs index 3f8e597..e18d495 100644 --- a/src/Fabulous.MauiControls/Views/Pages/NavigationPage.fs +++ b/src/Fabulous.MauiControls/Views/Pages/NavigationPage.fs @@ -302,7 +302,7 @@ module NavigationPageAttached = let IconColor = Attributes.defineBindableColor NavigationPage.IconColorProperty let TitleIconImageSource = - Attributes.defineBindableWithEquality NavigationPage.TitleIconImageSourceProperty + Attributes.defineBindableImageSource NavigationPage.TitleIconImageSourceProperty let TitleView = Attributes.defineBindableWidget NavigationPage.TitleViewProperty @@ -428,7 +428,7 @@ type NavigationPageAttachedModifiers = /// The image source [] static member inline titleIcon(this: WidgetBuilder<'msg, #IFabPage>, value: ImageSource) = - this.AddScalar(NavigationPageAttached.TitleIconImageSource.WithValue(value)) + this.AddScalar(NavigationPageAttached.TitleIconImageSource.WithValue(ImageSourceValue.Source value)) /// Sets the value for TitleView /// Current widget @@ -444,21 +444,21 @@ type NavigationPageExtraAttachedModifiers = /// The image source [] static member inline titleIcon(this: WidgetBuilder<'msg, #IFabPage>, value: string) = - this.titleIcon(ImageSource.FromFile(value)) + this.AddScalar(NavigationPageAttached.TitleIconImageSource.WithValue(ImageSourceValue.File value)) /// Set the image source of the title icon /// Current widget /// The image source [] static member inline titleIcon(this: WidgetBuilder<'msg, #IFabPage>, value: Uri) = - this.titleIcon(ImageSource.FromUri(value)) + this.AddScalar(NavigationPageAttached.TitleIconImageSource.WithValue(ImageSourceValue.Uri value)) /// Set the image source of the title icon /// Current widget /// The image source [] static member inline titleIcon(this: WidgetBuilder<'msg, #IFabPage>, value: Stream) = - this.titleIcon(ImageSource.FromStream(fun () -> value)) + this.AddScalar(NavigationPageAttached.TitleIconImageSource.WithValue(ImageSourceValue.Stream value)) [] type NavigationPagePlatformModifiers = diff --git a/src/Fabulous.MauiControls/Views/Pages/_Page.fs b/src/Fabulous.MauiControls/Views/Pages/_Page.fs index 6fa97bc..e2a2e79 100644 --- a/src/Fabulous.MauiControls/Views/Pages/_Page.fs +++ b/src/Fabulous.MauiControls/Views/Pages/_Page.fs @@ -17,13 +17,13 @@ module Page = Attributes.defineEventNoArg "Page_Appearing" (fun target -> (target :?> Page).Appearing) let BackgroundImageSource = - Attributes.defineBindableWithEquality Page.BackgroundImageSourceProperty + Attributes.defineBindableImageSource Page.BackgroundImageSourceProperty let Disappearing = Attributes.defineEventNoArg "Page_Disappearing" (fun target -> (target :?> Page).Disappearing) let IconImageSource = - Attributes.defineBindableWithEquality Page.IconImageSourceProperty + Attributes.defineBindableImageSource Page.IconImageSourceProperty let IsBusy = Attributes.defineBindableBool Page.IsBusyProperty @@ -52,14 +52,14 @@ type PageModifiers = /// The image source [] static member inline backgroundImageSource(this: WidgetBuilder<'msg, #IFabPage>, value: ImageSource) = - this.AddScalar(Page.BackgroundImageSource.WithValue(value)) + this.AddScalar(Page.BackgroundImageSource.WithValue(ImageSourceValue.Source value)) /// Set the image source of the icon /// Current widget /// The image source [] static member inline icon(this: WidgetBuilder<'msg, #IFabPage>, value: ImageSource) = - this.AddScalar(Page.IconImageSource.WithValue(value)) + this.AddScalar(Page.IconImageSource.WithValue(ImageSourceValue.Source value)) /// Set the page as busy. This will cause the global activity indicator to show a busy state /// Current widget @@ -109,40 +109,42 @@ type PageExtraModifiers = /// The image source [] static member inline backgroundImageSource(this: WidgetBuilder<'msg, #IFabPage>, value: string) = - this.backgroundImageSource(ImageSource.FromFile(value)) + this.AddScalar(Page.BackgroundImageSource.WithValue(ImageSourceValue.File value)) /// Set the image source of the background /// Current widget /// The image source [] static member inline backgroundImageSource(this: WidgetBuilder<'msg, #IFabPage>, value: Uri) = - this.backgroundImageSource(ImageSource.FromUri(value)) + this.AddScalar(Page.BackgroundImageSource.WithValue(ImageSourceValue.Uri value)) /// Set the image source of the background /// Current widget /// The image source [] static member inline backgroundImageSource(this: WidgetBuilder<'msg, #IFabPage>, value: Stream) = - this.backgroundImageSource(ImageSource.FromStream(fun () -> value)) + this.AddScalar(Page.BackgroundImageSource.WithValue(ImageSourceValue.Stream value)) /// Set the image source of the icon /// Current widget /// The image source [] - static member inline icon(this: WidgetBuilder<'msg, #IFabPage>, value: string) = this.icon(ImageSource.FromFile(value)) + static member inline icon(this: WidgetBuilder<'msg, #IFabPage>, value: string) = + this.AddScalar(Page.IconImageSource.WithValue(ImageSourceValue.File value)) /// Set the image source of the icon /// Current widget /// The image source [] - static member inline icon(this: WidgetBuilder<'msg, #IFabPage>, value: Uri) = this.icon(ImageSource.FromUri(value)) + static member inline icon(this: WidgetBuilder<'msg, #IFabPage>, value: Uri) = + this.AddScalar(Page.IconImageSource.WithValue(ImageSourceValue.Uri value)) /// Set the image source of the icon /// Current widget /// The image source [] static member inline icon(this: WidgetBuilder<'msg, #IFabPage>, value: Stream) = - this.icon(ImageSource.FromStream(fun () -> value)) + this.AddScalar(Page.IconImageSource.WithValue(ImageSourceValue.Stream value)) /// Set the padding inside the widget /// Current widget