Skip to main content
Version: 7.0.0

Release Notes, 6.17.0

๐Ÿšง Minimum required:

@smartface/native v4.4.0 ๐Ÿš€
Android -> v6.17.0 ๐Ÿš€
iOS -> v6.17.0 ๐Ÿš€
CLI -> v6.17.0 ๐Ÿš€

Project Structure Changesโ€‹

In this release, we focused on architectural changes and aimed to improve the structure of Smartface Projects. Therefore, we have made a few changes and added a few repositories to our arsenal!

New Modulesโ€‹

  • Smartface now uses it's own Typescript Watcher:
  • We have developed mixins module to gather our common mixins for better coverage and to add more composition through the project. For usage, keep reading.
  • In addition to context, we have added styling-context module for style based concepts.
  • For core patterns and code, we have added core module.

These repositories should be added in the project:

# Root folder
yarn add @smartface/tsc-watch -W

# Script Folder
yarn add @smartface/mixins
yarn add @smartface/styling-context
yarn add @smartface/core

Updated Modulesโ€‹

In order to fully migrate to the new version, you should update these packages:

For further information about versions, check the playground project of Smartface for updated versions and match yours with the new ones:

To access playground itself, check the repository:

GitHub - smartface/sf-playground: A playground for different methodologies and approaches.
A playground for different methodologies and approaches. - GitHub - smartface/sf-playground: A playground for different methodologies and approaches.
GitHub - smartface/sf-playground: A playground for different methodologies and approaches. favicon https://github.com/smartface/sf-playground
GitHub - smartface/sf-playground: A playground for different methodologies and approaches.

Code Changesโ€‹

Theme Folderโ€‹

Within the addition of styling context, you first need to change scripts/theme.ts file to the code below:

import Data from "@smartface/native/global/data";
import Application from "@smartface/native/application";
import { config } from "settings.json";
import { ThemeService } from "@smartface/styling-context/lib/ThemeService";

const themeConfig = config.theme;
const currentTheme = Data.getStringVariable("currentTheme") || themeConfig.currentTheme;
const themeSources = themeConfig.themes.map((name) => ({
name,
rawStyles: require(`./generated/themes/${name}`),
isDefault: currentTheme === name,
}));

export const themeService = new ThemeService(themeSources);
Application["theme"] = ThemeService.instance;
caution

If you have custom code in this file, do not forget to adapt it to the new structure.

Context Functionsโ€‹

With the type addition on dispatch method, you can type safely use dispatch method to fit your needs and update your style. For more information, check this documentation:

Changing UI Properties on Runtime

Keep in mind that this usage is discouraged and might break your Application on the new structure:

import { pushClassNames, removeClassNames } from "@smartface/contx/lib/styling";
//...
this.layout.dispatch(pushClassNames('.sf-flexLayout'));
this.layout.dispatch(removeClassNames('.sf-flexLayout'));

instead, you should be doing dispatch only:

this.layout.dispatch({
type: "pushClassNames",
classNames: '.sf-flexLayout'
});

this.layout.dispatch({
type: "removeClassName",
className: '.sf-flexLayout'
});

Context Error on Generated Codeโ€‹

If you get an error from generated pages after updating similar to this:

scripts/generated/pages/page1/index.ts:129:21 - error TS2345: Argument of type '{ type: string; name: stri
ng; component: string; classNames: string | string[]; defaultClassNames: string | string[]; userStyle: { [key: strin
g]: any; }; }' is not assignable to parameter of type 'Actions'.
129 this.dispatch(actionAddChild(`item${++this.itemIndex}`, item));

That means your builder version is old. Simply update your packages to required minimum versions.

info

Don't forget to restart your Builder after reinstalling the package.

Style Changesโ€‹

With the addition of styling-context, overall style usage have been changed either.

Getting Style From Codeโ€‹

The old usage consisted of using getCombinedStyle utility. We have removed the need to use utility for this case:

import { getCombinedStyle } from '@smartface/extension-utils/lib/getCombinedStyle';
const style = getCombinedStyle('.sf-flexLayout');

For more information, check the following documentation:

Getting Style Properties From Code

Usage of componentContextPatchโ€‹

In the old structure, in order to add a component to the context without connecting it to the page, we would be using componentContextPatch method.

We have deprecated that usage and moved on to a better usage!

import componentContextPatch from "@smartface/contx/lib/smartface/componentContextPatch";

const flexLayout = new FlexLayout();
componentContextPatch(flexLayout, "flexLayoutGeneric");

Page Life Cycle Eventsโ€‹

With the architectural upgrade (since @smartface/builder@0.7.0) on builder, it can be converted to a more readable version as shown on the New Page Class Tab.

Now, the callbacks are implemented in more object oriented fashion, allowing to inherit them easier.

import Page1Design from 'generated/pages/page1';

export default class Page1 extends Page1Design {
constructor() {
super();
this.onShow = onShow.bind(this, this.onShow.bind(this));
this.onLoad = onLoad.bind(this, this.onLoad.bind(this));
}
}

function onShow(superOnShow: () => void) {
superOnShow();
}

function onLoad(superOnLoad: () => void) {
superOnLoad();
}

Router Changesโ€‹

The old architecture was dependant of the Smartface Utility heavily. Within the new changes, this dependency have been removed on core implementations.

For example, at the old scripts/routes/index.ts file, usage of back and dismiss button implementations relied on utility.

See the utility dependencies in the old usage? Within the new changes, the back&dimiss button logic have been moved into Page by mixins:

import buildExtender from "@smartface/extension-utils/lib/router/buildExtender";
import { NativeRouter as Router, NativeStackRouter as StackRouter, Route, BottomTabBarRouter } from "@smartface/router";
import "@smartface/extension-utils/lib/router/goBack"; // Implements onBackButtonPressed
import backClose from '@smartface/extension-utils/lib/router/back-close';
import Image from "@smartface/native/ui/image";
import Page from "@smartface/native/ui/page";

const ROOT_PATH = '/root';
const TAB_PREFIX = 'tab';

backClose.setDefaultBackStyle({
image: Image.createFromFile('images://close_icon.png'),
hideTitle: false
});

backClose.dismissBuilder = () => {
return {
image: Image.createFromFile("images://backarrow.png"),
position: backClose.DismissPosition.LEFT
};
};

const router = Router.of({
path: '/',
isRoot: true,
routes: [
StackRouter.of({
path: '/pages',
routes: [
Route.of({
path: '/pages/page1',
build: buildExtender({
getPageClass: () => require('pages/page1').default,
headerBarStyle: { visible: true },
}),
}),
Route.of({
path: '/pages/page2',
build: buildExtender({
getPageClass: () => require('pages/page2').default,
headerBarStyle: { visible: true },
}),
}),
],
}),
],
});
export default router;

Usage of Mixins and Changing Back&Dismiss Buttonsโ€‹

Since the utility usage have been deprecated, in order to make the page classes more concise, you can use the mixins provided by Smartface!

Let's look at the page class implementation with and without mixin:

import Page1Design from "generated/pages/page1";
import { Route, BaseRouter as Router } from "@smartface/router";

export default class Page1 extends Page1Design {
constructor(private router?: Router, private route?: Route) {
super({});
}
onShow() {
super.onShow();
}

onLoad() {
super.onLoad();
}
}

For usage, just hover over the functions and see what are their capabilities!

caution

By default, this.initDismissButton uses close_icon.png as image. Remember to add it to your project as image. You can find the default icon by clicking the link:

Check the following documentation on how to generate image(s):

Image Generation

Usage of routeDataโ€‹

Within the new implementation, routeData will not be added to the page anymore. In the old usage, we could do this.routeData but now, we can't do that as is. We should add it ourselves.

import Page1Design from "generated/pages/page1";
import { Route, BaseRouter as Router } from "@smartface/router";

export default class Page1 extends Page1Design {
routeData: Record<string, any> = this.route.getState().routeData; // Or if you are sure of what type it will receive, you can strongly type it.
constructor(private router?: Router, private route?: Route) {
super({});
}
onShow() {
super.onShow();
console.info(this.routeData); // Use it!
}

onLoad() {
super.onLoad();
}
}

Getting the Instance of Pageโ€‹

For abstraction purposes, we have deprecated active utility and discourage getting the page instance. You should pass the page instance from the pages you want to use.

Android Changesโ€‹

Since we upgraded to a new v8 version, PackageProfiles.xml must also be updated accordingly. To do this go to your PackageProfiles.xml file under the config/Android folder and remove armeabi="1" from there. Otherwise, your project will fail on build steps.

<?xml version="1.0" encoding="utf-8" ?>
<packageProfiles>
<profile name="Default">
<android x86="0" arm64-v8a="1">
<!-- ... rest of your xml -->
</android>
</profile>
</packageProfiles>

Our newly updated v8 version also requires changes on NDK version. If you are using Appcircle, the following script needs to be added to your build workflow with a new Custom Script after the Smartface Eject for Android step.

set -e
set -x

wget -q --show-progress https://dl.google.com/android/repository/android-ndk-r19c-linux-x86_64.zip -O android-ndk-r19c-temp.zip \
&& unzip -q android-ndk-r19c-temp.zip -d $AC_REPOSITORY_DIR/ndk \
&& rm android-ndk-r19c-temp.zip

touch $AC_PROJECT_PATH/local.properties

echo "ndk.dir=$AC_REPOSITORY_DIR/ndk/android-ndk-r19c" >> $AC_PROJECT_PATH/local.properties

For local builds, you can refer to:

Building Apps Locally

IDE Changesโ€‹

IDE Releases are held in its respective place. You can reach it under:

Releases ยท smartface/smartface-ide-releases
Smartface ide releases. Contribute to smartface/smartface-ide-releases development by creating an account on GitHub.
Releases ยท smartface/smartface-ide-releases favicon https://github.com/smartface/smartface-ide-releases/releases
Releases ยท smartface/smartface-ide-releases

For IDE Documentation&Usage, you can refer to this documentation:

UI Editor Basics

Native and Framework Changesโ€‹

๐Ÿ†• What's Newโ€‹

  • Feature: App shortcuts added. By app shortcuts, you can define shortcuts to perform specific actions in your app. These shortcuts can be displayed in a supported launcher or assistant, like Google Assistant, and help your users quickly start common or recommended tasks within your app
  • Improvement: Material components have updated: The affected components: BottomTabbar, MaterialTextbox and TabbarController. These components are refactored to adapt the latest Material Design Guidelines.
  • Feature: Multiple image and video pick support added. By using pickMultipleFromGallery, you can now pick multiple items from the gallery.
  • Removal: Removed FloatingMenu component. Removed FloatingMenu component from both platforms.
  • Feature: Added launchCropper method to Multimedia. This will help you to use native cropper to crop your images at your will.
  • Feature: dirty method have been added to View. Now Views can be marked as dirty and the layouts will be recalculated. The dirty method is useful for text-based views such as Label, MaterialTextBox etc. Check the applyLayout documentation for more details.
  • Feature: isVoiceOverEnabled property has been added to Application class. It can be used to check if the voiceover is active.
  • Feature: hasCameraFeature property has been added to Multimedia class. It can be used to check if the device has an available camera feature.
  • Revert: shareText & shareImage & shareFile methods are rewamped: This methods are no longer deprecated due to some Android devices not allowing to share without declaring the metadata.
  • Feature: Added support for using Smartface emulator over USB cable: Smartface emulator can communicate with Smartface IDE without WiFi/LAN on Android using ADB as connection medium. Check details on IDE
  • Feature: Gridview now supports rowRange methods just like ListView:
  • Feature: isEmulator method have been added to determine if the current running application is running under emulator or not.
  • Improvement: Added proper typing to dispatch method while using context changes.

Android Changesโ€‹

  • Maintenance: Facebook yoga library version has updated to v1.19.0: Smartface uses it to provide a cross-platform layout engine which implements Flexlayout.
  • Migration: Migrated from Picasso to Glide: Glide is an image loading and caching library that used in ImageView functions that loadFromUrl, loadFromFile and fetchFromUrl.
  • Feature: displayZoomControls added to WebView: Used to set the visibility of zoom controls.
  • Feature: Added Android support for canOpenUrl: Use canOpenUrl method to check whether url can launch.
  • Feature: Added maxLines property to MaterialTextbox: Used to set the max lines count for MaterialTextbox.
  • Migration: Migrated some dependencies to JitPack: Migrated the BlurView, Transcoder, RangeBarSlider and VideoPlayer (Exoplayer) componentes from JCenter to JitPack package repository.
  • Improvement: Improved application call: Remove the Package Manager query checks.
  • Maintenance: V8 version upgraded to v9.3: Smartface uses v8 JavaScript engine in Android projects. We have upgraded to one of the newest versions, thus the .apk package build size has also increased.
  • Maintenance: Armv7a cpu architecture being fully supported
  • Maintenance: Minimum supported Android NDK version increased to r19c
  • Improvement: HeaderBar Item Design has been improved: Padding and contentInsetStartWithNavigation properties added to HeaderBar for Android.
  • Removal: Multimedia.getAllGalleryItems method is removed.

iOS Changesโ€‹

  • Feature: Added expandsOnOverflow property to MaterialTextbox: Use expandsOnOverflow property in order to make auto grow MaterialTextBox.

๐Ÿž Bug Fixโ€‹

  • Fixed the cursor position when new text is set on SearchView for Android.
  • Fixed the LiveMediaPlayer not starting up correctly when resuming on Application.onMaximize event
  • Fixed the BlurView causing unexpected behaviors when initialized.
  • Fixed the that next character input does not trigger onTextChanged callback when set the text inside onTextChanged in SearchView.
  • Fixed the onFailure callback is not executing when an empty URL is given to imageView.loadFromUrl.

๐Ÿ“‘ Documentationโ€‹

The following docs are updated, you can have a look to see what's new:

Glideโ€‹

Glide is a fast and efficient image loading library and caching library for Android focused on smooth scrolling. Glide supports fetching, decoding, and displaying video stills, images, and animated GIFs.

Glide's primary focus is on making scrolling any kind of a list of images as smooth and fast as possible, but Glide is also effective for almost any case where you need to fetch, resize, and display a remote image.

ImageView functions that loadFromUrl, loadFromFile and fetchFromUrl are using glide as a library.

Previously, we were using Picasso as an image loading and caching library. But we were facing customization and performance issues. Due to that issues, we migrated from picasso to glide.

For more info about ImageView you can refer to:

ImageView

Dirty Method for Layout Recalculationsโ€‹

With this version, we have implemented a new method called dirty() for Views, now Views can be marked as dirty and the layouts will be recalculated. The dirty method is useful for text-based views such as Label, MaterialTextBox etc.

const label = new Label({ text: "Hello World" });
label.dirty();
label.text = "Some long text";

There is one difference between Android and iOS while using the dirty method. in iOS, applyLayout() method needs to be called whenever the dirty method is used in order to safely recalculate the layouts. An example code below can be found below:

import System from "@smartface/native/device/system";

const label = new Label({ text: "Hello World" });
label.dirty();
label.text = "Some long text";
if (System.OS === System.OSType.iOS) {
this.layout.applyLayout();
}

For more information, check the applyLayout documentation in order to learn more about re-calculating layouts

ApplyLayout