Unleash your web skills on native!

A presentation at OdessaJS in July 2018 in Odesa, Odessa Oblast, Ukraine, 65000 by Rowdy Rabouw

Slide 1

Slide 1

OdessaJS 2018 - @rowdyrabouw

Slide 2

Slide 2

Unleash your web skills on native!

Slide 3

Slide 3

Slide 4

Slide 4

Web developer mood coaster

Slide 5

Slide 5

web developer in natural habitat

Slide 6

Slide 6

Slide 7

Slide 7

web developer • HTML • CSS • JavaScript • Sass • Node Package Manager #OdessaJS - @rowdyrabouw 7/129

Slide 8

Slide 8

web developer on native iOS / Android

Slide 9

Slide 9

Slide 10

Slide 10

web developer & native • App stores • Provisioning files • Java or Kotlin for Android • Objective-C or Swift for iOS #OdessaJS - @rowdyrabouw 10/129

Slide 11

Slide 11

web developer with nativescript

Slide 12

Slide 12

Slide 13

Slide 13

web developer & nativescript • App stores • Provisioning files • NativeScript • HTML, CSS, JavaScript • Sass • Node Package Manager #OdessaJS - @rowdyrabouw 13/129

Slide 14

Slide 14

web developer ❤ nativescript

Slide 15

Slide 15

Slide 16

Slide 16

who?

Slide 17

Slide 17

Rowdy Rabouw @rowdyrabouw Gouda, The Netherlands I ❤ superhero movies Freelance web and app developer Lead developer Nationale-Nederlanden Pension App Progress Developer Expert for Nativescript #OdessaJS - @rowdyrabouw 17/129

Slide 18

Slide 18

Slide 19

Slide 19

Mobile App framework decision guide

Slide 20

Slide 20

Mobile App framework decision guide Do you want/need a native User Interface and native performance? No Yes #OdessaJS - @rowdyrabouw 20/129

Slide 21

Slide 21

Mobile App framework decision guide Do you want/need a native User Interface and native performance? No Yes Phonegap / Cordova with Ionic • WebView • DOM to manipulate • HTML styled like native #OdessaJS - @rowdyrabouw 21/129

Slide 22

Slide 22

Mobile App framework decision guide Do you want/need a native User Interface and native performance? No Yes Phonegap / Cordova with Ionic • WebView • DOM to manipulate • HTML styled like native continue #OdessaJS - @rowdyrabouw 22/129

Slide 23

Slide 23

Mobile App framework decision guide Do you have too much money and time? Yes No #OdessaJS - @rowdyrabouw 23/129

Slide 24

Slide 24

Mobile App framework decision guide Do you have too much money and time? Yes No Native iOS and Android • Twice the work #OdessaJS - @rowdyrabouw 24/129

Slide 25

Slide 25

Mobile App framework decision guide Do you have too much money and time? Yes No Native iOS and Android • Twice the work continue #OdessaJS - @rowdyrabouw 25/129

Slide 26

Slide 26

Mobile App framework decision guide Do you potentially want/need to share code with the web? Or do you want/need to use web technologies? No Yes #OdessaJS - @rowdyrabouw 26/129

Slide 27

Slide 27

Mobile App framework decision guide Do you potentially want/need to share code with the web? Or do you want/need to use web technologies? No Yes Xamarin • .NET or C# • Cross compiling • Bindings to access native APIs #OdessaJS - @rowdyrabouw 27/129

Slide 28

Slide 28

Mobile App framework decision guide Do you potentially want/need to share code with the web? Or do you want/need to use web technologies? No Yes Flutter • Dart • Cross compiling • Beta #OdessaJS - @rowdyrabouw 28/129

Slide 29

Slide 29

Mobile App framework decision guide Do you potentially want/need to share code with the web? Or do you want/need to use web technologies? No Yes Flutter • Dart • Cross compiling • Beta continue #OdessaJS - @rowdyrabouw 29/129

Slide 30

Slide 30

Mobile App framework decision guide Do you want to use modern JavaScript? No Yes #OdessaJS - @rowdyrabouw 30/129

Slide 31

Slide 31

Mobile App framework decision guide Do you want to use modern JavaScript? No Yes Titanium • No ES6/ES2015 support • Can't use NPM • Old MVC framework (Alloy) #OdessaJS - @rowdyrabouw 31/129

Slide 32

Slide 32

Mobile App framework decision guide Do you want to use modern JavaScript? No Yes Titanium • No ES6/ES2015 support • Can't use NPM • Old MVC framework (Alloy) continue #OdessaJS - @rowdyrabouw 32/129

Slide 33

Slide 33

Mobile App framework decision guide Do you know and like React? Yes No #OdessaJS - @rowdyrabouw 33/129

Slide 34

Slide 34

Mobile App framework decision guide Do you know and like React? Yes No React Native • React • Native code to access APIs • Version 0.55 #OdessaJS - @rowdyrabouw 34/129

Slide 35

Slide 35

Mobile App framework decision guide Do you know and like React? Yes No React Native • React • Native code to access APIs • Version 0.55 continue #OdessaJS - @rowdyrabouw 35/129

Slide 36

Slide 36

Slide 37

Slide 37

NATIVESCRIPT

Slide 38

Slide 38

NATIVESCRIPT

Slide 39

Slide 39

What is NativeScript? • Open source framework for building truly native mobile apps • JavaScript, markup (XML/HTML) and CSS • Native code inside your JavaScript if you want and dare • Cross Platform: one codebase for iOS and Android • Backed by software company Progress • Android 4.2 or a later stable official release • iOS 7.0 or later stable official release #OdessaJS - @rowdyrabouw 39/129

Slide 40

Slide 40

Slide 41

Slide 41

Nice ... but get me up to speed

Slide 42

Slide 42

install Homebrew

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

install Node.js

brew install node

install NativeScript CLI

npm install -g nativescript

install iOS and Android requirements

Windows

@powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((new-object net.webclient).DownloadString('https://www.nativescript.org/setup/win'))"

macOS

ruby -e "$(curl -fsSL https://www.nativescript.org/setup/mac)" #OdessaJS - @rowdyrabouw 42/129

Slide 43

Slide 43

NativeScript CLI (tns = Telerik NativeScript)

tns <Command> [Command Parameters] [-- command <Options>] tns create <app-name> tns create <app-name> --tsc tns create <app-name> --ng vue init nativescript-vue/vue-cli-template <app-name> tns create <app-name> --template <template-url> tns platform add ios tns platform add android tns build ios tns build android tns run ios tns run android #OdessaJS - @rowdyrabouw 43/129

Slide 44

Slide 44

docs.nativescript.org

Slide 45

Slide 45

nativescript.org/get-the-nativescript-book

Slide 46

Slide 46

nativescripting.com

Slide 47

Slide 47

nativescript.org/nativescript-sidekick

Slide 48

Slide 48

play.nativescript.org

Slide 49

Slide 49

forum.nativescript.org

Slide 50

Slide 50

nativescriptcommunity.slack.com

Slide 51

Slide 51

Slide 52

Slide 52

markup like on the web

Slide 53

Slide 53

Markup http://2xr.nl/markup https://docs.nativescript.org/ui/components < ActionBar

title ="Native elements"/> < StackLayout

< Button

text ="Button" tap ="{{ onButtonTap }}"/>

< Switch

checked ="false"/>

< SegmentedBar

items ="{{ segmentedBarItems }}"/>

< Progress

value ="0" maxValue ="100"/>

< Slider

value ="0" minValue ="0" maxValue ="100"/>

< DatePicker

year ="2018" month ="1" day ="1"

minDate ="1970-01-01" maxDate ="2100-12-31"/> </ StackLayout

#OdessaJS - @rowdyrabouw 53/129

Slide 54

Slide 54

Slide 55

Slide 55

TextField https://docs.nativescript.org/api-reference/modules/ui_text_field.textfield < TextField /> < TextField

text =""/> < TextField

hint ="Enter your name"/> #OdessaJS - @rowdyrabouw 55/129

Slide 56

Slide 56

TextField: autocapitalization https://docs.nativescript.org/api-reference/modules/ui_text_field.textfield < TextField

autocapitalizationType ="allCharacters"/> < TextField

autocapitalizationType ="sentences"/> < TextField

autocapitalizationType ="words"/> #OdessaJS - @rowdyrabouw 56/129

Slide 57

Slide 57

TextField: autocapitalization https://docs.nativescript.org/api-reference/modules/ui_text_field.textfield < TextField

autocapitalizationType ="allCharacters"/> < TextField

autocapitalizationType ="sentences"/> < TextField

autocapitalizationType ="words"/> < TextField

autocapitalizationType ="none"/> #OdessaJS - @rowdyrabouw 57/129

Slide 58

Slide 58

TextField: autocorrect https://docs.nativescript.org/api-reference/modules/ui_text_field.textfield < TextField

autocorrect ="true"/> < TextField

autocorrect ="false"/> #OdessaJS - @rowdyrabouw 58/129

Slide 59

Slide 59

TextField: keyboardType http://2xr.nl/keyboardType https://docs.nativescript.org/api-reference/modules/ui_enums.keyboardtype < TextField

keyboardType ="number"/> < TextField

keyboardType ="datetime"/> < TextField

keyboardType ="phone"/> < TextField

keyboardType ="email"/> < TextField

keyboardType ="url"/> #OdessaJS - @rowdyrabouw 59/129

Slide 60

Slide 60

Slide 61

Slide 61

TextField: more attributes https://docs.nativescript.org/api-reference/modules/ui_text_field.textfield < TextField

textAlignment =""/> < TextField

visibility =""/> < TextField

width =""/> < TextField

maxLength =""/> #OdessaJS - @rowdyrabouw 61/129

Slide 62

Slide 62

Layouts https://docs.nativescript.org/ui/layouts #OdessaJS - @rowdyrabouw 62/129

Slide 63

Slide 63

Layouts https://docs.nativescript.org/ui/layouts #OdessaJS - @rowdyrabouw 63/129

Slide 64

Slide 64

DockLayout https://docs.nativescript.org/ui/layouts < DockLayout

height ="100%"

stretchLastChild ="true">

< Label

text ="1" dock ="top"/>

< Label

text ="2" dock ="bottom"/>

< Label

text ="3" dock ="right"/>

< Label

text ="4" dock ="left"/> </ DockLayout

<!-- 1 + 2 have fixed height 3 has fixed width 4 will get all remaining space -->

#OdessaJS - @rowdyrabouw 64/129

Slide 65

Slide 65

GridLayout https://docs.nativescript.org/ui/layouts < GridLayout

rows ="100, auto, *"

columns ="100, auto, *">

< Label

text ="1" row ="0" col ="0">

< Label

text ="2" row ="0" col ="1"

colSpan ="2"/>

< Label

text ="3" row ="1" col ="0"

rowSpan ="2"/>

< Label

text ="4" row ="1" col ="1"/>

< Label

text ="5" row ="1" col ="2"/>

< Label

text ="6" row ="2" col ="1"/>

< Label

text ="7" row ="2" col ="2"/> </ GridLayout

#OdessaJS - @rowdyrabouw 65/129

Slide 66

Slide 66

Slide 67

Slide 67

Cascading Style Sheets

Slide 68

Slide 68

Cascading Style Sheets https://docs.nativescript.org/ui/styling • a large subset of CSS properties is supported • device-independent pixels • application-wide, page-specific or inline • platform-specific possible • animations • SASS #OdessaJS - @rowdyrabouw 68/129

Slide 69

Slide 69

{N} Core Themes https://docs.nativescript.org/ui/theme • ready to use color schemes • tailored for iOS and Android #OdessaJS - @rowdyrabouw

Slide 70

Slide 70

NativeScript Theme Builder https://www.nativescriptthemebuilder.com #OdessaJS - @rowdyrabouw 70/129

Slide 71

Slide 71

TabView < TabView

height ="100%">

< StackLayout * tabItem ="{title: 'Rocket Raccoon'}" class ="full rocket"/>

< StackLayout * tabItem ="{title: 'Harley Quinn'}" class ="full harley"/>

< StackLayout * tabItem ="{title: 'Hulk'}" class ="full hulk"/> </ TabView

#OdessaJS - @rowdyrabouw 71/129

Slide 72

Slide 72

TabView .full {

background-size : cover;

background-position : center;

background-repeat : no-repeat; } .rocket { background-image : url ( "~/images/rocket-raccoon.jpg" ); } .harley { background-image : url ( "~/images/harley-quinn.jpg" ); } .hulk { background-image : url ( "~/images/hulk.jpg" ); } #OdessaJS - @rowdyrabouw 72/129

Slide 73

Slide 73

Slide 74

Slide 74

Slide 75

Slide 75

Fantastic 4 Choices

Slide 76

Slide 76

4 Fantastic Choices

Slide 77

Slide 77

JavaScript

Slide 78

Slide 78

TypeScript

Slide 79

Slide 79

Vue.js

Slide 80

Slide 80

Angular

Slide 81

Slide 81

Slide 82

Slide 82

Native Code Objective-C

Slide 83

Slide 83

{N} Angular directory structure app/components/slider/ slider.component.html slider.component.css slider.component.ts slider-routing.module.ts slider-module.ts #OdessaJS - @rowdyrabouw 83/129

Slide 84

Slide 84

slider.component.html < StackLayout

< Slider

</ Slider

</ StackLayout

#OdessaJS - @rowdyrabouw 84/129

Slide 85

Slide 85

slider.component.css StackLayout {

padding : 50 ; } #OdessaJS - @rowdyrabouw 85/129

Slide 86

Slide 86

slider.component.ts import { Component } from

"@angular/core" ; @Component({

selector : "app-slider" ,

moduleId : module .id,

templateUrl : "slider.component.html" ,

styleUrls : [ "slider.component.css" ] }) export

class SliderComponent {

constructor () {} } #OdessaJS - @rowdyrabouw 86/129

Slide 87

Slide 87

#OdessaJS - @rowdyrabouw 87/129

Slide 88

Slide 88

slider.component.html < StackLayout

< Slider

slider-icon

</ Slider

</ StackLayout

• attribute directive • changes the appearance or behavior of an element #OdessaJS - @rowdyrabouw 88/129

Slide 89

Slide 89

slider.directive.ts import { Directive, ElementRef } from

"@angular/core" ; import { isIOS } from

"platform" ; @Directive({

selector : "[slider-icon]" }) export

class SliderIconDirective {

constructor (private el: ElementRef) {

if (isIOS) {

let uiSlider = this .el.nativeElement.ios; uiSlider.setThumbImageForState( UIImage.imageNamed( "image.png" ), UIControlState.Normal); } } } #OdessaJS - @rowdyrabouw 89/129

Slide 90

Slide 90

slider.directive.ts import { Directive, ElementRef } from

"@angular/core" ; import { isIOS } from

"platform" ; @Directive({

selector : "[slider-icon]" }) export

class SliderIconDirective {

constructor (private el: ElementRef) {

if (isIOS) {

let uiSlider = this .el.nativeElement.ios; uiSlider.setThumbImageForState( UIImage.imageNamed( "image.png" ), UIControlState.Normal); } } } #OdessaJS - @rowdyrabouw 90/129

Slide 91

Slide 91

slider.directive.ts import { Directive, ElementRef } from

"@angular/core" ; import { isIOS } from

"platform" ; @Directive({

selector : "[slider-icon]" }) export

class SliderIconDirective {

constructor (private el: ElementRef) {

if (isIOS) {

let uiSlider = this .el.nativeElement.ios; uiSlider.setThumbImageForState( UIImage.imageNamed( "image.png" ), UIControlState.Normal); } } } #OdessaJS - @rowdyrabouw 91/129

Slide 92

Slide 92

slider.module.ts import { NgModule, NO_ERRORS_SCHEMA } from

"@angular/core" ; import { NativeScriptModule } from

"nativescript-angular/nativescript.module" ; import { SliderIconDirective } from

"./slider.directive" ; import { SliderRoutingModule } from

"./slider-routing.module" ; import { SliderComponent } from

"./slider.component" ; @NgModule({

imports : [NativeScriptModule, SliderRoutingModule],

declarations : [SliderComponent, SliderIconDirective],

schemas : [NO_ERRORS_SCHEMA] }) export

class SliderModule {} #OdessaJS - @rowdyrabouw 92/129

Slide 93

Slide 93

93/129

Slide 94

Slide 94

slider.component.html < StackLayout

< AbsoluteLayout

< StackLayout

background

class ="captain" top ="0" left ="0"></ StackLayout

< FlexboxLayout

class ="flexcontainer" top ="0" left ="0">

< Slider

slider-icon ( valueChange )="onSliderChange($event)"></ Slider

</ FlexboxLayout

</ AbsoluteLayout

</ StackLayout

#OdessaJS - @rowdyrabouw 94/129

Slide 95

Slide 95

slider.component.css .captain {

background-image : url ( "~/assets/images/captain-america.jpg" );

background-repeat : no-repeat;

background-position : center;

background-size : cover;

height : 100% ;

width : 100% ;

opacity : 0 ; } #OdessaJS - @rowdyrabouw 95/129

Slide 96

Slide 96

slider.component.css .flexcontainer {

justify-content : center;

align-items : center;

height : 100% ;

width : 100% ; } Slider {

width : 80% ;

background-color : #BC1A0F ; } ActionBar {

background-color : #FFFFFF ; } #OdessaJS - @rowdyrabouw 96/129

Slide 97

Slide 97

slider.component.ts import { Component, OnInit, ViewChild, ElementRef } from

"@angular/core" ; import { Page } from

"ui/page" ; import { Slider } from

"ui/slider" ; import { StackLayout } from

"ui/layouts/stack-layout" ; import { TNSPlayer } from

"nativescript-audio" ; @Component({

selector : "app-slider" ,

moduleId : module .id,

templateUrl : "slider.component.html" ,

styleUrls : [ "slider.component.css" ] }) #OdessaJS - @rowdyrabouw 97/129

Slide 98

Slide 98

slider.component.ts export

class SliderComponent implements OnInit { @ViewChild( "background" ) background: ElementRef; private viewStack: StackLayout; private player: TNSPlayer;

constructor (private page: Page) {} ngOnInit() {

this .page.actionBarHidden = true ;

this .viewStack = this .background.nativeElement;

this .player = new TNSPlayer();

this .player.initFromFile({

audioFile : "~/assets/audio/captain.mp3" ,

loop : false }); } #OdessaJS - @rowdyrabouw 98/129

Slide 99

Slide 99

slider.component.ts onSliderValueChange(args) {

let slider = < Slider

args.object; // opacity and volume range is 0 - 1 let sliderValue = slider.value / 100; this.viewStack.opacity = sliderValue; if (Math.round(slider.value) > 0) { this.player.play(); this.player.volume = sliderValue; } else { this.player.seekTo(0); this.player.pause(); } } } #OdessaJS - @rowdyrabouw 99/129

Slide 100

Slide 100

Slide 101

Slide 101

Packages & Libraries

Slide 102

Slide 102

Node Package Manager • commonly known as npm • ready to use JavaScript modules • about 650.000 packages of free, reusable code #OdessaJS - @rowdyrabouw 102/129

Slide 103

Slide 103

Android Arsenal • libraries for Android (Java / Kotlin) Cocoapods • libraries for iOS (Objective-C / Swift) #OdessaJS - @rowdyrabouw 103/129

Slide 104

Slide 104

Slide 105

Slide 105

Multilingual: ngx-translate

Slide 106

Slide 106

Multilingual: ngx-translate • internationalization library for Angular 2+ • define translations in different languages • switch between them easily • no hardcoded text/labels, all in one place • start directly, even with one language #OdessaJS - @rowdyrabouw 106/129

Slide 107

Slide 107

Multilingual: ngx-translate {

"HOME" : {

"TITLE" : "Hello OdessaJS!" ,

"TEXT" : "It's great to be here and introduce NativeScript to you." ,

"SLIDER" : "Slider" ,

"ENGLISH" : "English" ,

"FOREIGN" : "Ukrainian" ,

"MIP" : "WowWee MiP" ,

"SPEECH_RECOGNITION" : "Speech recognition!" } } #OdessaJS - @rowdyrabouw 107/129

Slide 108

Slide 108

Multilingual: ngx-translate < ActionBar

[ title ]="'HOME.TITLE' | translate"> </ ActionBar

< Button

[ text ]="'HOME.FOREIGN' | translate" ( tap )="changeLanguage('uk')"> </ Button

[] = one way data binding in Angular | = display-value transformations #OdessaJS - @rowdyrabouw 108/129

Slide 109

Slide 109

109/129

Slide 110

Slide 110

Slide 111

Slide 111

NativeScript Plugins

Slide 112

Slide 112

What are {N} plugins? When the NativeScript core modules do not provide the native device or platform capability that you need, you can use plugins. • usually for both iOS and Android • JavaScript interface to native platform code #OdessaJS - @rowdyrabouw 112/129

Slide 113

Slide 113

#OdessaJS - @rowdyrabouw 113/129

Slide 114

Slide 114

Nativescript plugins • nativescript-bluetooth • nativescript-accelerometer • nativescript-speech-recognition • nativescript-texttospeech #OdessaJS - @rowdyrabouw 114/129

Slide 115

Slide 115

Nativescript plugins • nativescript-directions • nativescript-camera • nativescript-social-share • nativescript-videoplayer #OdessaJS - @rowdyrabouw 115/129

Slide 116

Slide 116

{N} Plugins live demo

Slide 117

Slide 117

nativescript-bluetooth import * as bluetooth from

"nativescript-bluetooth" ; bluetooth.startScanning({

seconds : 4 ,

onDiscovered : peripheral => {

if (peripheral.UUID == "CA9F644C-1920-4572-8833-1D137A6T2A05" ) { bluetooth.connect({

UUID : peripheral.UUID,

onConnected : peripheral => { bluetooth.stopScanning();

// do stuff } }); } } }); #OdessaJS - @rowdyrabouw 117/129

Slide 118

Slide 118

nativescript-accelerometer import { startAccelerometerUpdates } from

"nativescript-accelerometer" ; startAccelerometerUpdates( data => {

// lean left (0 to -1) / right (0 to 1)

let leftOrRight = data.x;

// lean forward (0 to -1) / back (0 to 1)

let forwardOrBack = data.y;

// do stuff }); #OdessaJS - @rowdyrabouw 118/129

Slide 119

Slide 119

nativescript-speech-recognition import { SpeechRecognition, SpeechRecognitionTranscription }

from

"nativescript-speech-recognition" ; private speechRecognition = new SpeechRecognition(); this .speechRecognition.available().then(

( available: boolean ) =>

console .log(available ? "YES!" : "NO" ), (err: string) => console .log(err) ); this .speechRecognition.requestPermission().then( ( granted: boolean ) => {

console .log( "Granted? "

  • granted); }); #OdessaJS - @rowdyrabouw 119/129

Slide 120

Slide 120

nativescript-speech-recognition this .speechRecognition.startListening({

locale : "en-US" ,

returnPartialResults : true ,

onResult : ( transcription: SpeechRecognitionTranscription ) => {

console .log( User said: ${transcription.text} ); } }); this .speechRecognition.stopListening().then( () => {

// do something with the recognized text }); #OdessaJS - @rowdyrabouw 120/129

Slide 121

Slide 121

nativescript-texttospeech import { TNSTextToSpeech, SpeakOptions }

from

"nativescript-texttospeech" ; let textToSpeech = new TNSTextToSpeech(); let speakOptions: SpeakOptions = {

text : "Hello world!" ,

locale : "en-US" ,

speakRate : 0.5 ,

pitch : 0.8 }; textToSpeech.speak(speakOptions); . #OdessaJS - @rowdyrabouw 121/129

Slide 122

Slide 122

nativescript-directions import { Directions } from

"nativescript-directions" ; let directions = new Directions(); directions.navigate({

// optional, default "current location"

from : {

lat : 46.433131 ,

lng : 30.7618338 },

// if an Array is passed, the last item is the destination,

// the addresses in between are "waypoints" to: [{

address : "Vorontsovs'kyi Ln, 4, Odessa" , // Witch House }, {

address : "Potemkin Stairs, Odesa, Ukraine" }],

ios : {

preferGoogleMaps : true ,

allowGoogleMapsWeb : true

} }) #OdessaJS - @rowdyrabouw 122/129

Slide 123

Slide 123

nativescript-camera import * as camera from

"nativescript-camera" ; import { ImageSource } from

"tns-core-modules/image-source" ; camera.requestPermissions(); camera.takePicture({

width : 1000 ,

height : 1000 }) .then( imageAsset => {

new ImageSource().fromAsset(imageAsset).then( imageSource => {

// do something with the image }); }); #OdessaJS - @rowdyrabouw 123/129

Slide 124

Slide 124

nativescript-social-share import * as camera from

"nativescript-camera" ; import { ImageSource } from

"tns-core-modules/image-source" ; import * as SocialShare from

"nativescript-social-share" ; camera.requestPermissions(); camera.takePicture({

width : 1000 ,

height : 1000 }) .then( imageAsset => {

new ImageSource().fromAsset(imageAsset).then( imageSource => { SocialShare.shareImage(imageSource); }); }); #OdessaJS - @rowdyrabouw 124/129

Slide 125

Slide 125

nativescript-videoplayer < VideoPlayer

src ="video.mp4"

controls ="true"

loop ="true"

autoplay ="false"> </ VideoPlayer

#OdessaJS - @rowdyrabouw 125/129

Slide 126

Slide 126

Slide 127

Slide 127

2xr.nl/odessajs #OdessaJS - @rowdyrabouw

Slide 128

Slide 128

Дякую #OdessaJS - @rowdyrabouw

Slide 129

Slide 129

Links Native elements playground: http://2xr.nl/markup keyboardType playground: http://2xr.nl/keyboardType TabView playground: http://2xr.nl/TabView Plugin demo app: https://github.com/rowdyrabouw/NativeScriptTalk/tree/OdessaJS #OdessaJS - @rowdyrabouw 129/129