New in version 0.20.2

Released one year ago

Please remember to uno clean your projects after upgrading Fuse.

Welcome to Fuse 0.20!

This long-awaited release of Fuse comes with tons of shiny new features, improvements, bugfixes, optimizations and cleanups of old legacy to make Fuse truly ready for prime time. We have been working on this release behind the scenes for several months while releasing hotfixes to 0.12, and we are super excited to finally make it available.

All of this awesomeness comes at a price; this release has several backwards-incompatible changes. Please take your time to upgrade carefully. Depending on the size of your existing project, upgrading can take some time and may not be 1:1 with your old version.

If moving an existing project to 0.20, make sure you check out the Migration guide (also reproduced below).

We also have a new, greatly improved documentation system: http://www.fusetools.com/docs - go there for docs and examples on the features mentioned here.

New features & release highlights
New best practices for navigation, components & structuring your app
  • New classes Router & Navigator greatly simplify app navigation and structuring larger apps in a scalable way, while allowing full customization of transitions.

    • Easily navigate between pages of your app using router.goto(), .push() and .goBack() in JavaScript
    • Pass parameters to the route to "send messages" between pages
    • Multi-level navigation
    • Fuse preview remembers the route for each preview instance. No more being thrown back to the start page for every change
    • Back-buttons e.g in Android devices automatically work with Router.
    • Navigator takes automatic care of lazy-instantiating views, recycling inactive views, reusing views etc
  • New feature ux:Dependency allows dependency injection into ux:Class - improves ability to create reusable components in UX/JS.

  • JavaScript now has access to all objects in their scope by ux:Name and ux:Dependency through their scripting interface, e.g. ux:Name="foo" and then foo.doSomething() in JavaScript. This allows truly isolated components (ux:Class) with inner logic in JavaScript that works on the objects and dependencies of the class. The new documentation system now shows what methods are available from scripts on each class.
  • All ux:Property declarations are now implicitly available as Observables

Very high-level example of recommended app structure:

<App>
    <Router ux:Name="router" />
    <JavaScript>
        router.goto("user", { id: 34 });
    </JavaScript>
    <Navigator>
        <LoginPage ux:Template="login" router="router" />
        <HomePage ux:Template="home" router="router" />
        <SettingsPage ux:Template="settings" router="router" />
        <UserProfilePage ux:Template="user" router="router" />
    </Navigator>
</App>

where each of the pages is a ux:Class in a separate file, with <Router ux:Dependency="router" />.

See the documentation and examples for more in-depth information.

Fuse library cleanups & improvements
  • Each, Match/Case and triggers now preserve their intuitive ordering and can be nested without intermediary panels. Ooh yeah!
  • Styles, Themes and related features long considered deprecated are now eliminated. Long live ux:Class and reusable components!
  • Large refactoring of the core architecture for improved speed, reduced memory usage, eliminated memory leaks etc. If you have a lot of Uno code touching core things and run into issues, make sure you read the rest of the document carefully.
Fuse preview improvements
  • New Reset (Cmd/Ctrl+R) function in local preview.
  • Back button simulation (Cmd/Ctrl+B) in local preview. On iOS, hold 3 fingers for 1 seconds to bring up back button emulator.
  • Rotate device (previously Cmd/Ctrl+R) renamed to Flip device (Cmd/Ctrl+F)
  • You can now have both a fuse preview version and a fuse build version of your app installed on a phone at the same time (they now have different package identifiers)
More foreign code

Most of Fuse is now rewritten from the old native bindings system to the new foreign code system. What this means for you:

  • We will very soon open up an API to make it easy to write new UX wrappers for native controls yourself in foreign code. This means native control wrappers can be distributed as packages.
  • Once bindings are completely eliminated from the Fuse libraries, compilation times for Android and iOS will be reduced a lot. We're almost there now.
Migration guide (0.12 -> 0.20)
No more Themes or Styles
  • Remove the Theme property from your <App /> class. This means no more Theme="Basic".
  • Remove ux:InheritStyle, ux:Cascade, IgnoreStyle attributes, as they no longer have any meaning or effect.

An empty app now looks like this:

<App>
</App>

Note that all semantic controls (Button, Switch, Slider and TextInput) will no longer get the Basic theme apperance, but instead a much more plain generic look/no look at all. To keep the old appearance, prefix all uses of those controls with Basic., e.g. <Basic.Button />. Remember to add a reference to Fuse.BasicTheme in your .unoproj if you want access to this (not default).

The long deprecated <Style> tag is now finally removed. Rewrite to use ux:Class instead, which is a much nicer and much more performant way of doing consistent styling.

Some users have a legacy habit of using <Style ux:Class="MyStyle"> as a dummy-container for a collection of classes. In this case, you can simply replace <Style .. with <Panel .. or any other dummy to keep this pattern.

Changes in default package references
  • Remove all the Fuse.* packages (including FuseCore) and replace with two simple references to Fuse, FuseJS.

You might also want to add a reference to the following depending on whether you need a feature:

  • "Fuse.GeoLocation"
  • "Fuse.Camera"
  • "Fuse.Vibration"
  • "Fuse.Launcher"
  • "Fuse.PushNotifications"
  • "Fuse.LocalNotifications"
  • "Fuse.BasicTheme"

A minimal .unoproj file should now look something like this:

{
  "Packages": [
    "Fuse",
    "FuseJS",
    "Fuse.GeoLocation"
  ],
  "Includes": [
    "*"
  ]
}

If you have references to Uno.* packages, whether you need to keep them around depends on whether you have .uno code depending on those packages.

If you want to use the Basic. controls, add a reference to Fuse.BasicTheme. These are now not included by default to avoid bloat in your generated app if you are not using it.

You need to keep references to third party packages that you depend on in either UX, Uno or JS.

ux:Global on JavaScript tags is now deprecated

Using ux:Global on JavaScript modules to make them accessible to require() will have unpredictable behavior in fuse preview.

Instead require the JS file directly by including it in your project as a bundle file, for example:

"Includes": [
    "*",
    "*.js:Bundle"
]

and then use require with the filename instead:

var foo = require('foo'); // requires foo.js in the project root
var bar = require('./../bar'); // requires bar.js in the folder above the current file

Check out the detailed docs for more info.

Changes to TextInput and TextEdit APIs

TextEdit is now removed. TextInput now gives an undecorated text input control. If you want a decorated text input, you can get the old Basic style by using Basic.TextInput.

  • Replace all occurrences of TextEdit with TextInput. The previous use case for the TextEdit was to get an undecorated TextInput. Instead, the TextInput is now undecorated.
  • For existing TextInput, use the Basic.TextInput if you want to keep the old style, or keep as TextInput if you want to keep it undecorated. Y
  • TextInput is now always single line. To get the multiline version of TextInput, use a TextView instead.
  • PlainTextEdit no longer exists. Use TextInput instead.
  • As TextInput is invisible by default, you can use the new TextBox to get a decorated text input (easier while prototyping).

You can now style TextInput by putting elements inside it. It behaves like a DockPanel where remaining space is the actual editor:

<TextInput>
    <Rectangle Dock="Bottom" Height="2" Color="Blue" Margin="4" />
</TextInput>
Changes (bugfixes) to UX element ordering semantics
  • Elements placed inside Triggers will now be placed at the same location in the children list as their containing Trigger.

Here is an example where this matters:

<Panel>
    <Each Count="2">
        <ElemOne/>
    </Each>
    <ElemTwo/>
</Panel>

The previous behavior turned the above UX into the following equivalent:

<Panel>
    <ElemTwo/>
    <ElemOne/>
    <ElemOne/>
</Panel>

Notice that the element inside the Each are placed after element outside it.

The new behavior works like this:

<Panel>
    <ElemOne/>
    <ElemOne/>
    <ElemTwo/>
</Panel>

The elements are now placed where you'd intuitively expect them to be.

Consolidated ux:Template and ux:Factory concepts

In UX markup, the concept of Factory has been renamed to Template. The old Template concept is removed (was used in Styles, which are now removed).

The new Template-concept is used heavily in the new Router/Navigator APIs.

  • Instead of ux:Generate="Factory" use ux:Generate="Template"

You can also create a named template by using ux:Template="the_name".

The PageControl.DotFactory has been renamed to PageControl.DotTemplate.

Changes to animation APIs
  • Attractor.SimulationType has been removed in favor of two new properties; Type and Unit. Take a look here for details.

  • LinearNavigation no longer has an Easing and Duration property.

If you need to use a custom Easing and Duration, rewrite

<LinearNavigation Easing="CubicOut" Duration="0.3" />

To this:

<LinearNavigation>
    <NavigationMotion Easing="CubicOut" Duration="0.3" />
</LinearNavigation>
Uno API Changes

These changes are only relevant if you have custom .uno code in your projects.

  • protected override void OnRooted() and OnUnrooted() no longer take the parent node as an argument. The Parent property is assumed to be set at the time these methods are called.

  • Nodes no longer have a separate list for elements, behaviors and properties. They are all in the same list called Children.

  • Many places that used to take in a Node now take in a Visual instead. For example, in theWhileLoaded trigger:

public static void SetState(Node n, bool loaded)

has become

public static void SetState(Visual v, bool loading)
UX/Uno changes in detail
  • The base type of navigation classes, Navigation, has been renamed to VisualNavigation (as it's navigation of Visual objects). The generic and static navigation functions, however, remain in the Navigation class.

  • PageControl now derives from a common base NavigationControl and some enums have been renamed: PageControlInactiveState => NavigationControlInactiveState, PageControlInteraction -> NavigationControlInteraction, PageControlTransition -> NavigationControlTransition.

  • Navigation no longer sends per-page progress messages, instead only updating the Navigation object itself. This should not affect UX-level user code, only Uno code that might have subscribed to these messages.

  • INavigation gains some new functions. PageProgressChanged is now a NavigationHandler.

  • PageControl.AllowedSwipeDirections and SwipeNavigate.AllowedDirections have been added to control the allowed swiping direction.

  • SwipeNavigate.SwipeDirection is replaced with SwipeNavigate.ForwardDirection to clarify the direction you swipe to go "forward". This new property is actually the opposite of the previous one, so if you have Left you want Right now, Up becomes Down, and vice-versa.

  • SnapTo, EndSeekArgs, UpdateSeekArgs and ISeekable have been made internal to Fuse.Navigation. These are implementation details that cannot be used publicly.

  • SwipeNavigation.SwipeAllow and PageControl.SwipeAllow to limit the direction the user may swipe. Default is Both, but may be Forward or Backward to allow swiping in one direction only.

UX Markup trigger-ordering now preserved (previously random/undefined)
  • The children of behaviors (e.g. Each, Match/Case WhileTrue) will now be added to their parent just after the trigger itself. This means the order of the UX file is now preserved even as triggers turn on/off. Previously the children would always be added to the end. If you need to add to the end, place the trigger at the end of the parent.
MapView changes
  • Removed ZoomMin and ZoomMax properties
  • Made iOS and Android maps respond to the same kind of zoom values (a factor between 2 and 21)
  • Fixed issue where databinding on MapMarker properties would fail outside of Each
TextInput changes
  • Added support for AutoCorrectHint to control auto-correct on iOS and Android
  • Added support for AutoCapitalizationHint to control auto-capitalization on iOS and Android
ScrollView sizing change

As styles are being deprecated, the manner in which the @ScrollView determines its content alignment and size has changed. It should, in most cases, be identical to before.

The one exception is with minimum sizing. If you previously did not specify an Alignment, Height/Width, or MinHeight/Width the minimum width would be set to 100% by default. This is no longer the case. If you need this then add MinHeight="100%" to the content of the @ScrollView.

Animation control for navigation and scrolling
  • Removed StructuredNavigation.EasingBack and DurationBack as they have no equivalent in the new motion system.
  • Deprecated StructuredNavigation.Easing and Duration as they are now ambiguous in the new system. In the interim they will be mapped to Motion.GotoEasing and Motion.GotoDuration, though the meaning is not exactly the same (use GotoDurationExp='0' on a NavigationMotion to get a flat duration as before). Refer to the full NavigationMotion type for details.

      <NavigationMotion GotoEasing="SinusoidalInOut" GotoDuration="0.4" GotoDurationExp="0"/>
    
  • Removed SwipeNavigation.SwipeEnds and PageControl.SwipeEnds; use a NavigationMotion with the Overflow property instead.

      <NavigationMotion Overflow="Clamp"/>
    
  • The package Experimental.Physics has been removed: the API is still under too much flux to release, and the code has been moved to a private package in Fuse.Motion (which exposes high-level interfaces where appropriate). If you were using some of this code in your project, please contact us and can make the previous source available.

  • Introducing the Fuse.Motion package for high level simulation and physics configuration/behavior
  • The option to set an Attractor.Simulation has been removed for now, as the simulations are private. Use the SimulationType parameter to configure the type.
  • Attractor.SimulationType has been removed. Use the Type and Unit property instead.
  • Deprecated ScrollableGoto in favour of ScrollTo. This is simply a name change -- the old name still works with a deprecation warning.
Misc
  • How triggers and animations work has been changed. This corrects a few defects and should be backwards compatible.

  • Padding on visuals/primitives is now applied differently to be more useful and consistent. The local visual does not honor the padding anymore, only the children.

    <Rectangle Color="#F00" Padding="5">
        <Rectangle Color="#00F"/>
    </Rectangle>

Previously, the red rectangle would not be visible, since it was the same size as the child. Now, it will show in the padding area, since it ignores the padding for the local visual.

  • Change.MixOp has a new default of Offset rather than Weight. This changes how values are combined in a Change animator, fixing a few issues with easings such as BackInOut. For properties targeted by only a single animator the change is otherwise not noticable, only for 2+ animators. To get the old behavior use MixOp="Weight".
  • If you Change a Size property, such as Height, MinHeigth, Offset, etc. you must set the value of the property explicitly and not rely on the default setting. Animations from the default to a particular value will either not do want you want or do nothing at all.

  • TriggerAnimationState has been made internal (it already had an internal constructor) UpdateStage, Mixers and PostLayoutMixers have been removed. The Layout stage is no longer exclusive layout, and includes all trigger updates. The AddDeferredAction function takes a priority to assist in sub-stage ordering. Triggers should more universally use bypass mode during rooting. If you notice an animation that isn't playing when you desire, then use the Bypass="Never" mode, or ask for assistance on how to configure the effect you want.

  • ux:Generate="Factory" is replaced with ux:Generate="Template" to be consistent with the new ux:Template feature.

  • Element.CalcRenderBounds no longer includes the ActualSize of the element by default. If there is a background it will, otherwise the derived classes must provide their correct size (in addition to calling the base implementation).

  • Fuse.Controls.Number has been deprecated. Use a Text control instead with JavaScript formatting:

    exports.DisplayValue = this.Value.map(function(x) { return "$ " + x; });
  • OnUserEvent.Name is renamed to OnUserEvent.EventName. This is to avoid a conflict with the generic Node.Name that arises due to the Node/Trigger refactoring.

  • KeyframeInterpolation.CatmullRom has been given the friendlier name Smooth. The old name is left an alias for now (it will be removed at some point).

Uno / Foreign code improvements
  • Fixed a bug which resulted in comments not working in foreign Objective-C.

  • Added support for writing constructors using foreign code.

  • Foreign Objective-C code is now automatically wrapped in an Objective-C @autoreleasepool.

  • Support for transitive project references.

    Given the projects App, A & B:

    • App refences A, which has a transitive reference to B.
    • This means that App has a implicit reference to B through A.

      You can use transitive references in your project file like this:

      "IsTransitive": true
      

      This will make all references in your project transitive, effectively making your project a transitive package.

  • New default package names (Android) and bundle identifiers (iOS)

    • By default we use the string com.apps.@(Project.Name) converted to lower case.
    • This was done to solve collisions in the file system causing builds to fail.
    • On iOS, _ is replaced by - because _ are not allowed in bundle identifiers.

      If you want to override the defaults, you can edit your .unoproj.

      "Android.Package": "com.domain.my_app"
      
      "iOS.BundleIdentifier": "com.domain.my-app"
      

      Users that have apps in app stores probably want something that fits their app or organization, rather than the defaults.

  • New add no-build command.

    This allows deferring --build, --debug & --run without triggering a full uno build. Options are simplified but similar to uno build, please see uno no-build --help.

    One example:

      cd <project-dir>
      uno build ios --no-native
      uno no-build ios --build --run
    

    Thanks to @bolav for suggesting this feature.

  • C++/MSVC: Added *.natvis files for Visual Studio. This makes debugger better able to visualize Uno objects.