Copenhagen Denmark
BUILD A BROWSER BY KOTLIN COLIN LEE SEBASTIAN KASPARI
@colinmlee @Anti_Hype
BUILD A BROWSER BY KOTLIN COLIN LEE SEBASTIAN KASPARI @colinmlee - - PowerPoint PPT Presentation
BUILD A BROWSER BY KOTLIN COLIN LEE SEBASTIAN KASPARI @colinmlee @Anti_Hype Copenhagen Denmark Feature Session Toolbar Downloads Contextmenu Customtabs Findinpage Webnotifications Reader View Search Sync Prompts Sendtab QR ...
Copenhagen Denmark
@colinmlee @Anti_Hype
Agenda
Firefox for Android
Firefox for Android Focus for Android
Firefox for Android Focus for Android Firefox Rocket Firefox Lite
Firefox for Android Focus for Android Firefox Rocket Firefox for Fire TV Firefox Lite
Firefox for Echo Show
Firefox for Android Focus for Android Firefox Rocket Firefox for Fire TV Firefox Lite
Firefox for Echo Show
? ? ?
Firefox for Android Focus for Android Firefox Rocket Firefox for Fire TV Firefox Lite
Firefox for Echo Show
? ? ?
Goals
products.
Components?
Components?
100% Kotlin
Components?
100% Kotlin Well, and some Rust
HTML CSS JS Browser Engine
Browser Engine
GeckoView
○ Only one version needs to be supported. No surprises.
Engine Components
Engine Components
feature-downloads feature-downloads feature-media browser-awesomebar browser-contextmenu feature-readerview
Feature Browser Concept UI Service Support Lib
Session Toolbar Downloads Contextmenu Customtabs Findinpage Webnotifications Reader View Search Sync Prompts Sendtab QR ... Toolbar Engine-System Engine-Gecko Search Tabstray Menu ... Engine Toolbar Storage Fetch Push Tabstray ... Autocomplete ... ... ... State Crash ...
Mozilla ❤ Kotlin
Explicit nullability
lib-state
Store State
Store & State
data classes
data class BrowserState( val tabs: List<TabSessionState> = emptyList(), val selectedTabId: String? = null, val customTabs: List<..> = emptyList(), val extensions: Map<..> = emptyMap() ) : State
Modeling State
lib-state
Store State Component / App
State
Observing state
lib-state
@CheckResult(suggest = "observe") @Synchronized fun observeManually(
): Subscription<S, A> { // .. } Observing state
lib-state
Observing state
val subscription = store.observeManually { state -> // .. } subscription.unsubscribe()
Extension functions
@MainThread fun <..> Store<S, A>.observe(
) { // .. } Iterating on API
Extension functions
@MainThread fun <..> Store<S, A>.observe( view: View,
) { // .. } Iterating on API
lib-state
Store State Component / App
State dispatches Action
Dispatching actions
Sealed classes
sealed class TabListAction : BrowserAction() { data class AddTabAction( val tab: TabSessionState, val select: Boolean = false ) : TabListAction() data class SelectTabAction( val tabId: String ) : TabListAction() // .. }
Modeling Actions
lib-state
Store Reducer State Action
Inside the store
State
Functions & Sealed classes
Reducing state
fun reduce( state: BrowserState, action: TabListAction ): BrowserState { return when (action) { is TabListAction.AddTabAction -> { .. } is TabListAction.SelectTabAction -> { .. } // .. } }
data classes
Creating a new state val newState = state.copy( selectedTabId = "some-other-tab" )
Type aliases
Observing state typealias Observer<S> = (S) -> Unit typealias Reducer<S, A> = (S, A) -> S
Channel
@ExperimentalCoroutinesApi @MainThread fun <..> Store<S, A>.channel(
): ReceiveChannel<S> { // .. }
Observing state sequentially
Flow
@ExperimentalCoroutinesApi @MainThread fun <..> Store<S, A>.flow(
): Flow<S> { // .. } Observing state
“Scoped flow”
@ExperimentalCoroutinesApi @MainThread fun <..> Store<S, A>.flowScoped(
block: suspend (Flow<S>) -> Unit ): CoroutineScope { // .. } Observing state
Flow operators
fun <T> Flow<T>.ifChanged(): Flow<T> Only update UI if the state has changed
store .flow() .map { state -> state.selectedTab.title } .ifChanged() .collect { title -> // .. }
Flow operators
fun <T, R> Flow<T>.ifChanged( transform: (T) -> R ): Flow<T> Only update UI if state changed partially
store .flow() .ifChanged { state -> state.selectedTab.title } .collect { state -> // .. }
Flow operators
fun <T, R> Flow<List<T>>.filterChanged( transform: (T) -> R ): Flow<T> store .flow() .map { state -> state.tabs } .filterChanged { tab -> tab.title } .collect { tab -> // .. }
https://mozac.org https://mozilla.github.io/geckoview https://mozilla.github.io/application-services/ https://github.com/mozilla-mobile/
#KotlinConf
Colin Lee @colinmlee Sebastian Kaspari @Anti_Hype