Slide 1

Slide 1 text

Kotlin beyond Android Guillermo Orellana @wiyarmir

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

+ =

Slide 4

Slide 4 text

https://www.thinkgeek.com/product/e554/

Slide 5

Slide 5 text

https://imgur.com/gallery/7oxRClN

Slide 6

Slide 6 text

Back in the day https://www.theverge.com/2014/6/25/5842024/googles-android-logo-gets-a-new-look

Slide 7

Slide 7 text

https://www.pinterest.co.uk/pin/225813368792712452/ My first phone

Slide 8

Slide 8 text

https://www.pinterest.co.uk/pin/225813368792712452/ My first app

Slide 9

Slide 9 text

https://www.pinterest.co.uk/pin/225813368792712452/ My first redesign

Slide 10

Slide 10 text

https://www.redbubble.com/people/dimmi/works/28707595-low-poly-confused-nick-young Why are you talking about Android?

Slide 11

Slide 11 text

Kotlin feels like my first Android app

Slide 12

Slide 12 text

Makes new tech reachable https://en.wikipedia.org/wiki/Multi-touch https://yalik.deviantart.com/art/Daft-Punk-Soundboard-267150429

Slide 13

Slide 13 text

Awesome community

Slide 14

Slide 14 text

Gets people excited

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

Keynotedex

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

–Guillermo Orellana “I am a strong, independent programmer and I need no designer.” Things I regret

Slide 19

Slide 19 text

Goals •100% Kotlin •??? •Profit https://medium.com/elementaryos/all-aboard-the-meson-future-hype-train-2b6c478b6b9e

Slide 20

Slide 20 text

How is it made https://giphy.com/gifs/how-its-made-loop-link-gH6I5QWnIZjy0

Slide 21

Slide 21 text

Web

Slide 22

Slide 22 text

KotlinJS + Kotlin Frontend Plugin

Slide 23

Slide 23 text

KotlinJS

Slide 24

Slide 24 text

What happens with types? ?

Slide 25

Slide 25 text

dynamic https://www.joya.life/en/blog/the-power-of-kryptonite/

Slide 26

Slide 26 text

val a: dynamic = 3 a.`types?` .I.`haven't`.heard .that.name.`in`.years = "!"

Slide 27

Slide 27 text

Kotlin frontend plugin

Slide 28

Slide 28 text

kotlinFrontend { downloadNodeJsVersion = "8.11.2" sourceMaps = false }

Slide 29

Slide 29 text

npm { dependency "react", "16.3.1" dependency "react-dom" dependency "react-router" dependency "react-router-dom" devDependency "babel-loader" devDependency "babel-core" devDependency "css-loader" devDependency "style-loader" devDependency "source-map-loader" }

Slide 30

Slide 30 text

webpackBundle { publicPath = "/frontend/" port = 8080 proxyUrl = "http: //localhost:9090/" sourceMapEnabled = true stats = "errors-only" }

Slide 31

Slide 31 text

./gradlew web:run > Task :web:nodejs-download UP-TO-DATE > Task :web:npm-preunpack UP-TO-DATE > Task :web:npm-configure > Task :web:npm-install UP-TO-DATE > Task :web:npm-index UP-TO-DATE > Task :web:npm-deps > Task :web:npm > Task :web:packages > Task :web:compileKotlin2Js > Task :web:compileJava NO-SOURCE > Task :web:processResources UP-TO-DATE > Task :web:classes > Task :web:compileTestKotlin2Js NO-SOURCE > Task :web:webpack-config UP-TO-DATE > Task :web:karma-config SKIPPED > Task :web:karma-start SKIPPED > Task :web:processTestResources NO-SOURCE > Task :web:runDceKotlinJs > Task :web:runDceTestKotlinJs NO-SOURCE > Task :web:webpack-run webpack started, see http: //localhost:8080/ > Task :web:run BUILD SUCCESSFUL in 9s 15 actionable tasks: 5 executed, 10 up-to-date One command to rule them all ./gradlew web:run

Slide 32

Slide 32 text

Demo time https://asciinema.org/a/HIC2Ct3mT9jLr1LlbJ7wuiFtH

Slide 33

Slide 33 text

React in Kotlin https://en.wikipedia.org/wiki/React_(JavaScript_library) +

Slide 34

Slide 34 text

const Submission = (props) => (

{props.submission.title}

{props.submission.abstract}

{"View details"}
); // Usage

Slide 35

Slide 35 text

class Submission : RComponent() { override fun RBuilder.render() { with(props.submission) { div("col-md-4") { h4 { +title } p { +abstract } routeLink(to = submissionUrl) { attrs { className = "btn btn-secondary btn-lg" } +"View details" } } } } }

Slide 36

Slide 36 text

Rendered component

Slide 37

Slide 37 text

fun fetchUserProfileFromId(userId: String) = promise { val user = userProfile(userId) setState { userProfile = user } } .catch { console.error(it) }

Slide 38

Slide 38 text

Backend

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

https://vertx.io/ https://spring.io/ http://ktor.io/

Slide 41

Slide 41 text

Ktor http://ktor.io/

Slide 42

Slide 42 text

"Easy to use, fun and asynchronous." http://ktor.io/

Slide 43

Slide 43 text

fun main(args: Array) { embeddedServer(Netty, 8080) { routing { get("/") { call.respondText("My Example Blog", ContentType.Text.Html) } } }.start(wait = true) } http://ktor.io/

Slide 44

Slide 44 text

fun Application.configureOAuth(authConf: Authentication.Configuration) = authConf.oauth("oauth") { val config = environment.config.config("keynotedex.oauth.github") client = HttpClient(Apache) .apply { environment.monitor.subscribe(ApplicationStopping) { close() } } providerLookup = { OAuthServerSettings.OAuth2ServerSettings( name = "github", authorizeUrl = "https: //github.com/login/oauth/authorize", accessTokenUrl = "https: //github.com/login/oauth/access_token", clientId = config.propertyOrNull("clientId") ?.getString() ?: "", clientSecret = config.propertyOrNull("clientSecret") ?.getString() ?: "" ) } urlProvider = { settings: OAuthServerSettings -> redirectString(OAuthLoginEndpoint(settings.name)) } }

Slide 45

Slide 45 text

class ApplicationPage : Template { val caption = Placeholder() val head = Placeholder<HEAD>() override fun HTML.apply() { head { meta { charset = "utf-8" } meta { name = "viewport" content = "width=device-width, initial-scale=1.0" } title { insert(caption) } insert(head) } body { div { id = "content" } script(src = "frontend/frontend.bundle.js") } } }

Slide 46

Slide 46 text

class KeynotedexPageContent : Template { val head = Placeholder() val bundle = Placeholder() override fun HTML.apply() { head { meta { charset = "utf-8" } meta { name = "viewport" content = "width=device-width, initial-scale=1.0, shrink-to-fit=no" } title { +"Keynotedex" } insert(head) link( rel = LinkRel.stylesheet, type = LinkType.textCss, href = "https: //maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" ) { attributes["integrity"] = "sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" attributes["crossorigin"] = "anonymous" } } body { div { id = "content" } script(src = "https: //code.jquery.com/jquery-3.2.1.slim.min.js") { attributes["integrity"] = "sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" attributes["crossorigin"] = "anonymous" } script(src = "https: //cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js") { attributes["integrity"] = "sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" attributes["crossorigin"] = "anonymous" } script(src = "https: //maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js") { attributes["integrity"] = "sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" attributes["crossorigin"] = "anonymous" } script { insert(bundle) } } } }

Slide 47

Slide 47 text

Don't overuse builders

Slide 48

Slide 48 text

fun Route.index() { static("frontend") { resource("web.bundle.js") } accept(ContentType.Text.Html) { get { val model = mapOf( "jsbundle" to "/frontend/web.bundle.js" ) call.respond(FreeMarkerContent("index.ftl", model)) } } }

Slide 49

Slide 49 text

Shared code

Slide 50

Slide 50 text

Kotlin Multiplatform common jvm android js native compile

Slide 51

Slide 51 text

Platform specific code actual class Foo actual constructor(val bar: String) { actual fun frob() { println("Frobbing the $bar") } } Native Common expect class Foo(bar: String) { fun frob() }

Slide 52

Slide 52 text

common-android android Platform specific module common common-android common-jvm common-js common-native expectedBy android jvm js native compile

Slide 53

Slide 53 text

https://giphy.com/gifs/castle-nathan-fillion-favourite-Ow59c0pwTPruU

Slide 54

Slide 54 text

kotlinx.serialization •Cross-platform •Multi-format •Reflectionless https://imgflip.com/memetemplate/113426012/House-MD-Thumbs-Up

Slide 55

Slide 55 text

@Serializable data class SubmissionResponse( val submission: Submission )

Slide 56

Slide 56 text

val submissionResponse = KJSON.parse(responseText) call.respond( JSON.stringify( SubmissionResponse() ) ) JSON Serialise Deserialise

Slide 57

Slide 57 text

val submissionResponse = CBOR.load(responseBytes) call.respond( CBOR.dump( SubmissionResponse() ) ) CBOR Serialise Deserialise

Slide 58

Slide 58 text

val submissionResponse = ProtoBuf.load(resBytes) call.respond( ProtoBuf.dump( SubmissionResponse() ) ) Protocol Buffers Serialise Deserialise

Slide 59

Slide 59 text

https://memegenerator.net/instance/53270254/yeah-thatd-be-great-yeah-if-you-could-just-show-me-some-code-thatd-be-great

Slide 60

Slide 60 text

https://github.com/wiyarmir/keynotedex

Slide 61

Slide 61 text

What next?

Slide 62

Slide 62 text

Konan https://www.flickr.com/photos/edenpictures/9306258916

Slide 63

Slide 63 text

Android https://www.thinkgeek.com/product/e554/

Slide 64

Slide 64 text

Slides: tinyurl.com/mkcc-kotlinbeyondandroid Code: github.com/wiyarmir/keynotedex Contact: twitter.com/@wiyarmir https://milan.kotlincommunityconf.com