This commit is contained in:
Hadrian Tang 2019-11-05 18:02:48 +08:00
Родитель 9a6e094e1a 5ced068528
Коммит 0c9f8ec598
6 изменённых файлов: 206 добавлений и 39 удалений

Просмотреть файл

@ -3,10 +3,12 @@
<PropertyGroup>
<Version>0.50.0</Version>
<Authors>Fabulous Contributors</Authors>
<PackageVersion>0.50.0-alpha.7</PackageVersion>
<PackageReleaseNotes>This is an alpha release of an ongoing work with multiple breaking changes that might not be in the final version.
Please only use this version with a backup of your solution.
[Fabulous.XamarinForms] Fix issue for NavigationPage reuse</PackageReleaseNotes>
<PackageVersion>0.50.0</PackageVersion>
<PackageReleaseNotes>BREAKING CHANGES: This release introduces many small breaking changes to provide better type-safety and reducing update calls when using events.
Please read the migration guide to know how to update to this new version (https://fsprojects.github.io/Fabulous/Fabulous.XamarinForms/migration-guide-to-0.50.html)
[Fabulous.XamarinForms] Changed the View API to provide better type-safety for properties (see migration guide for more information)
[Fabulous.XamarinForms] Changed the behavior of event handlers. Events will no longer be triggered by Fabulous.XamarinForms when it's incrementally updating the properties (e.g. changing Text triggering TextChanged). This was changed to prevent unnecessary calls to the update function and in some cases an infinite loop on Android
[Fabulous.CodeGen] Introduced Fabulous.CodeGen, a new library, to help build your own library for your favorite framework using the MVU architecture with Fabulous. More documentation to come.</PackageReleaseNotes>
<PackageRequireLicenseAcceptance>False</PackageRequireLicenseAcceptance>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/fsprojects/Fabulous</PackageProjectUrl>

Просмотреть файл

@ -2,6 +2,7 @@
namespace Fabulous.CodeGen.AssemblyReader
open System
open System.Globalization
module Converters =
/// Converts the type name to another type name (e.g. System.Boolean => bool)
@ -26,8 +27,8 @@ module Converters =
| "System.Collections.IList" -> "obj list"
| _ -> typeName
let inline numberWithDecimalsToString literal v =
let str = v.ToString()
let inline numberWithDecimalsToString literal (v: 'T when 'T :> IConvertible) =
let str = v.ToString(CultureInfo.InvariantCulture)
let separator = if not (str.Contains(".")) then "." else ""
str + separator + literal
@ -37,15 +38,15 @@ module Converters =
| null -> Some "null"
| :? bool as b when b = true -> Some "true"
| :? bool as b when b = false -> Some "false"
| :? sbyte as sbyte -> Some (sbyte.ToString() + "y")
| :? byte as byte -> Some (byte.ToString() + "uy")
| :? int16 as int16 -> Some (int16.ToString() + "s")
| :? uint16 as uint16 -> Some (uint16.ToString() + "us")
| :? int as int -> Some (int.ToString())
| :? uint32 as uint32 -> Some (uint32.ToString() + "u")
| :? int64 as int64 -> Some (int64.ToString() + "L")
| :? uint64 as uint64 -> Some (uint64.ToString() + "UL")
| :? bigint as bigint -> Some (bigint.ToString() + "I")
| :? sbyte as sbyte -> Some (sbyte.ToString(CultureInfo.InvariantCulture) + "y")
| :? byte as byte -> Some (byte.ToString(CultureInfo.InvariantCulture) + "uy")
| :? int16 as int16 -> Some (int16.ToString(CultureInfo.InvariantCulture) + "s")
| :? uint16 as uint16 -> Some (uint16.ToString(CultureInfo.InvariantCulture) + "us")
| :? int as int -> Some (int.ToString(CultureInfo.InvariantCulture))
| :? uint32 as uint32 -> Some (uint32.ToString(CultureInfo.InvariantCulture) + "u")
| :? int64 as int64 -> Some (int64.ToString(CultureInfo.InvariantCulture) + "L")
| :? uint64 as uint64 -> Some (uint64.ToString(CultureInfo.InvariantCulture) + "UL")
| :? bigint as bigint -> Some (bigint.ToString(CultureInfo.InvariantCulture) + "I")
| :? float as float when Double.IsNaN(float) -> Some "System.Double.NaN"
| :? double as double when Double.IsNaN(double) -> Some "System.Double.NaN"
| :? float32 as float32 when Single.IsNaN(float32) -> Some "System.Single.NaN"

Просмотреть файл

@ -24,6 +24,7 @@ type RootPageKind =
| CollectionView
| CarouselView
| Effects
| RefreshView
type Model =
{ RootPageKind: RootPageKind
@ -64,6 +65,8 @@ type Model =
AnimatedScroll: AnimationKind
IsScrollingWithFabulous: bool
IsScrolling: bool
// For RefreshView
RefreshViewIsRefreshing: bool
}
type Msg =
@ -122,6 +125,9 @@ type Msg =
| Scrolled of float * float
// For ShellView page demo
//| ShowShell
// For RefreshView
| RefreshViewRefreshing
| RefreshViewRefreshDone
[<AutoOpen>]
module MyExtension =
@ -198,7 +204,8 @@ module App =
ScrollPosition = 0.0, 0.0
AnimatedScroll = Animated
IsScrollingWithFabulous = false
IsScrolling = false }, Cmd.none
IsScrolling = false
RefreshViewIsRefreshing = false }, Cmd.none
let getWebData =
async {
@ -228,6 +235,12 @@ module App =
return Some (Scrolled (x, y))
} |> Cmd.ofAsyncMsgOption
let refreshAsync () =
(async {
do! Async.Sleep 2000
return RefreshViewRefreshDone
}) |> Cmd.ofAsyncMsg
let update msg model =
match msg with
| Increment -> { model with Count = model.Count + 1 }, Cmd.none
@ -324,7 +337,12 @@ module App =
| ScrollXamarinForms (x, y, animated) ->
{ model with IsScrolling = true; IsScrollingWithFabulous = false; ScrollPosition = (x, y); AnimatedScroll = animated }, scrollWithXFAsync (x, y, animated)
| Scrolled (x, y) ->
{ model with ScrollPosition = (x, y); IsScrolling = false; IsScrollingWithFabulous = false }, Cmd.none
{ model with ScrollPosition = (x, y); IsScrolling = false; IsScrollingWithFabulous = false }, Cmd.none
// For RefreshView
| RefreshViewRefreshing ->
{ model with RefreshViewIsRefreshing = true }, refreshAsync ()
| RefreshViewRefreshDone ->
{ model with RefreshViewIsRefreshing = false }, Cmd.none
let pickerItems =
[ ("Aqua", Color.Aqua); ("Black", Color.Black);
@ -335,6 +353,27 @@ module App =
("Purple", Color.Purple); ("Red", Color.Red);
("Silver", Color.Silver); ("Teal", Color.Teal);
("White", Color.White); ("Yellow", Color.Yellow ) ]
let updateViewEffects () =
View.ScrollingContentPage("Effects", [
View.Label("Samples available on iOS and Android only")
View.Label("Focus effect (no properties)", fontSize=FontSize 5., margin=Thickness (0., 30., 0., 0.))
View.Label("Classic Entry field", margin=Thickness (0., 15., 0., 0.))
View.Entry()
View.Label("Entry field with Focus effect", margin=Thickness (0., 15., 0., 0.))
View.Entry(effects = [
View.Effect("FabulousXamarinForms.FocusEffect")
])
View.Label("Shadow effect (with properties)", fontSize=FontSize 15., margin=Thickness (0., 30., 0., 0.))
View.Label("Classic Label field", margin=Thickness (0., 15., 0., 0.))
View.Label("This is a label without shadows")
View.Label("Label field with Shadow effect", margin=Thickness (0., 15., 0., 0.))
View.Label("This is a label with shadows", effects = [
View.ShadowEffect(color=Color.Red, radius=15., distanceX=10., distanceY=10.)
])
])
let view (model: Model) dispatch =
@ -367,6 +406,7 @@ module App =
View.Button(text = "CollectionView", command=(fun () -> dispatch (SetRootPageKind CollectionView)))
View.Button(text = "CarouselView", command=(fun () -> dispatch (SetRootPageKind CarouselView)))
View.Button(text = "Effects", command=(fun () -> dispatch (SetRootPageKind Effects)))
View.Button(text = "RefreshView", command=(fun () -> dispatch (SetRootPageKind RefreshView)))
])))
.ToolbarItems([View.ToolbarItem(text="about", command=(fun () -> dispatch (SetRootPageKind (Choice true))))] )
.TitleView(View.StackLayout(orientation=StackOrientation.Horizontal, children=[
@ -1033,25 +1073,22 @@ module App =
]))
| Effects ->
View.ScrollingContentPage("Effects", [
View.Label("Samples available on iOS and Android only")
View.Label("Focus effect (no properties)", fontSize=FontSize 5., margin=Thickness (0., 30., 0., 0.))
View.Label("Classic Entry field", margin=Thickness (0., 15., 0., 0.))
View.Entry()
View.Label("Entry field with Focus effect", margin=Thickness (0., 15., 0., 0.))
View.Entry(effects = [
View.Effect("FabulousXamarinForms.FocusEffect")
])
View.Label("Shadow effect (with properties)", fontSize=FontSize 15., margin=Thickness (0., 30., 0., 0.))
View.Label("Classic Label field", margin=Thickness (0., 15., 0., 0.))
View.Label("This is a label without shadows")
View.Label("Label field with Shadow effect", margin=Thickness (0., 15., 0., 0.))
View.Label("This is a label with shadows", effects = [
View.ShadowEffect(color=Color.Red, radius=15., distanceX=10., distanceY=10.)
])
])
updateViewEffects ()
| RefreshView ->
View.ContentPage(
View.RefreshView(
isRefreshing = model.RefreshViewIsRefreshing,
refreshing = (fun () -> dispatch RefreshViewRefreshing),
content = View.ScrollView(
View.BoxView(
height = 150.,
width = 150.,
color = if model.RefreshViewIsRefreshing then Color.Red else Color.Blue
)
)
)
)
type App () as app =

Просмотреть файл

@ -222,6 +222,9 @@
},
{
"source": "Text"
},
{
"source": "VerticalTextAlignment"
}
],
"events": [
@ -361,6 +364,9 @@
{
"type": "Xamarin.Forms.Span",
"properties": [
{
"source": "CharacterSpacing"
},
{
"source": "BackgroundColor"
},
@ -1227,6 +1233,9 @@
{
"source": "BorderWidth"
},
{
"source": "CharacterSpacing"
},
{
"source": "Command"
},
@ -1291,6 +1300,9 @@
{
"type": "Xamarin.Forms.DatePicker",
"properties": [
{
"source": "CharacterSpacing"
},
{
"source": "Date"
},
@ -1414,6 +1426,9 @@
{
"source": "AutoSize"
},
{
"source": "CharacterSpacing"
},
{
"source": "FontAttributes"
},
@ -1461,6 +1476,12 @@
{
"type": "Xamarin.Forms.Entry",
"properties": [
{
"source": "CharacterSpacing"
},
{
"source": "ClearButtonVisibility"
},
{
"source": "CursorPosition",
"updateCode": "ViewUpdaters.updateEntryCursorPosition"
@ -1506,6 +1527,9 @@
},
{
"source": "TextColor"
},
{
"source": "VerticalTextAlignment"
}
],
"events": [
@ -1531,6 +1555,9 @@
{
"source": "CancelButtonColor"
},
{
"source": "CharacterSpacing"
},
{
"source": "FontAttributes"
},
@ -1570,6 +1597,9 @@
},
{
"source": "TextColor"
},
{
"source": "VerticalTextAlignment"
}
],
"events": [
@ -1641,7 +1671,47 @@
{
"type": "Xamarin.Forms.CarouselView",
"name": "XFCarouselView",
"canBeInstantiated": false
"canBeInstantiated": false,
"properties": [
{
"source": "CurrentItem"
},
{
"source": "IsBounceEnabled"
},
{
"source": "IsScrollAnimated"
},
{
"source": "IsSwipeEnabled"
},
{
"source": "ItemsLayout"
},
{
"source": "NumberOfSideItems"
},
{
"source": "PeekAreaInsets"
},
{
"source": "Position"
}
],
"events": [
{
"source": "CurrentItemChanged",
"relatedProperties": [
"CurrentItem"
]
},
{
"source": "PositionChanged",
"relatedProperties": [
"Position"
]
}
]
},
{
"type": "Fabulous.XamarinForms.CustomCarouselView",
@ -1799,6 +1869,9 @@
},
{
"source": "Refreshing"
},
{
"source": "Scrolled"
}
]
},
@ -1867,6 +1940,9 @@
{
"type": "Xamarin.Forms.Label",
"properties": [
{
"source": "CharacterSpacing"
},
{
"source": "FontAttributes"
},
@ -1893,6 +1969,9 @@
{
"source": "MaxLines"
},
{
"source": "Padding"
},
{
"source": "Text"
},
@ -1902,6 +1981,9 @@
{
"source": "TextDecorations"
},
{
"source": "TextType"
},
{
"source": "VerticalTextAlignment"
}
@ -2190,6 +2272,28 @@
"Content"
]
},
{
"type": "Xamarin.Forms.RefreshView",
"properties": [
{
"source": "IsRefreshing"
},
{
"source": "RefreshColor"
}
],
"events": [
{
"source": "Refreshing",
"relatedProperties": [
"IsRefreshing"
]
}
],
"primaryConstructorMembers": [
"Content"
]
},
{
"type": "Xamarin.Forms.OpenGLView",
"properties": [
@ -2204,6 +2308,9 @@
{
"type": "Xamarin.Forms.Picker",
"properties": [
{
"source": "CharacterSpacing"
},
{
"source": "FontAttributes"
},
@ -2388,8 +2495,12 @@
},
{
"type": "Xamarin.Forms.TimePicker",
"name": "XFTimePicker",
"canBeInstantiated": false,
"properties": [
{
"source": "CharacterSpacing"
},
{
"source": "FontAttributes"
},
@ -2414,6 +2525,7 @@
},
{
"type": "Fabulous.XamarinForms.CustomTimePicker",
"name": "TimePicker",
"events": [
{
"source": "TimeChanged",
@ -2508,6 +2620,9 @@
"canBeInstantiated": false,
"name": "XFSearchHandler",
"properties": [
{
"source": "CharacterSpacing"
},
{
"source": "BackgroundColor"
},
@ -2594,6 +2709,9 @@
},
{
"source": "TextColor"
},
{
"source": "VerticalTextAlignment"
}
],
"events": [

Просмотреть файл

@ -7,7 +7,7 @@
"Elmish",
"Cross-platform"
],
"name": "Fabulous Xamarin.Forms App v0.50.0-alpha.7",
"name": "Fabulous Xamarin.Forms App v0.50.0",
"groupIdentity": "Fabulous.XamarinForms.App",
"identity": "Fabulous.XamarinForms.FSharp",
"shortName": "fabulous-xf-app",
@ -162,7 +162,7 @@
"type": "parameter",
"dataType": "string",
"replaces": "FabulousPkgsVersion",
"defaultValue": "0.50.0-alpha.7"
"defaultValue": "0.50.0"
},
"NewtonsoftJsonPkg": {
"type": "parameter",

Просмотреть файл

@ -1,3 +1,12 @@
#### 0.50.0
BREAKING CHANGES: This release introduces many small breaking changes to provide better type-safety and reducing update calls when using events.
Please read the migration guide to know how to update to this new version (https://fsprojects.github.io/Fabulous/Fabulous.XamarinForms/migration-guide-to-0.50.html)
* [Fabulous.XamarinForms] Changed the View API to provide better type-safety for properties (see migration guide for more information)
* [Fabulous.XamarinForms] Changed the behavior of event handlers. Events will no longer be triggered by Fabulous.XamarinForms when it's incrementally updating the properties (e.g. changing Text triggering TextChanged). This was changed to prevent unnecessary calls to the update function and in some cases an infinite loop on Android
* [Fabulous.CodeGen] Introduced Fabulous.CodeGen, a new library, to help build your own library for your favorite framework using the MVU architecture with Fabulous. More documentation to come.
#### 0.50.0-alpha.7
This is an alpha release of an ongoing work with multiple breaking changes that might not be in the final version.