Mobile engineer in Slovenia

Rok Retar

I build mobile apps in Kotlin, for Android and iOS.Android is where I started. Today I take Kotlin Multiplatform into production: one codebase for an app's logic and data, while each platform keeps its own native UI. On the side I build Parrot, an ebook and audiobook reader.
Kotlin · Kotlin Multiplatform · Android · Compose
Portrait of Rok Retar
My own app

Parrot

A reader for your own ebooks and audiobooks on Android phones, tablets and e-ink readers. It highlights the text as the narrator reads and remembers where you are in every version of a book. Built with Kotlin Multiplatform; an iPhone version is in the works.

Read-along

For ebooks with synced narration, such as those made with Storyteller, each sentence lights up as it is read.

Voices on your device

No audiobook? A downloaded voice reads any ebook aloud. Chapters are prepared ahead so playback has no gaps, and the text never leaves the phone.

One place in every version

Link the ebook and the audiobook of a book and Parrot shows where you are in each, then moves the others to the matching place when you ask.

Your library, your server

Connect the Storyteller or Audiobookshelf server you already run, or browse OPDS catalogues such as Project Gutenberg. Books go straight from the server to the device.

Highlights, notes and a dictionary

Four highlight colours, notes in the margin and one list of everything you marked, exportable as Markdown. Tap a word for an offline definition.

Parrot Cloud

No server? Parrot Cloud keeps your books, reading position, highlights and statistics in sync on every device you sign in to. In early access.

Made for e-ink

A black-and-white theme with no animation, clear outlines and larger type, for e-readers that run Android.

Reading statistics

Time read and listened by day and by book, streaks and every session, computed on the device and synced through Parrot Cloud.
How I work

Share what should be shared. Keep native what should feel native.

I write business logic, data layers and domain models once in Kotlin and share them between Android and iOS. The UI stays native wherever the platform does it better.For a company's production iOS app, I designed and led the move to shared Kotlin. It shipped, and real users run it today.Where the line between shared and native code sits is an engineering decision, not a belief. Module boundaries enforce it: the domain depends on nothing, and data and UI depend on the domain.
—Share the domain and data layers; keep the UI native where the platform does it better.
—Let module boundaries enforce dependency direction, so the domain stays plain Kotlin.
—Ship to production, not to a demo branch.
—Use Kotlin wherever it fits, including this website.
ShippedA company's production iOS app now runs on shared Kotlin, packaged as a static framework the iOS team added without changing their build.
Experience

The tools I use every day

My daily stack is Kotlin, Jetpack Compose, Compose Multiplatform, Ktor, Koin, Decompose, SQLDelight with SQLCipher, and SKIE for Swift interop.I build multi-module apps with strict dependency rules: the domain is plain Kotlin, data layers handle storage and networking, and the UI is native where that matters. This site is written in Kotlin too, with Kobweb and Compose for Web.

Production apps I've shipped

The biggest was moving a company's production iOS app to shared Kotlin. I designed the architecture and built the shared code: business logic, domain models and SQLCipher-encrypted data layers, compiled into a static Kotlin/Native framework. The iOS team added it without a single new linker flag.I've also shipped an AI platform with real-time chat, timelines and push notifications; a gaming app with NFC, biometric sign-in, cashless payments and white-label builds; and Parrot. Each used Kotlin Multiplatform differently, from shared networking and database layers to fully shared Compose UI.

Where I've worked

  1. 2023 – now
    Senior Android Engineer & Tech LeadDevRev · LjubljanaI lead six Android engineers and set the architecture standards. I moved the app from XML views to Jetpack Compose and rebuilt the CircleCI pipelines, which cut build times across the company.
  2. 2019 – 2023
    Android DeveloperNetcetera · LjubljanaI built financial modules for large banking apps under strict security and compliance rules, and split monolithic features into independent modules to shorten the release cycle.
  3. 2020
    Diploma in Software DevelopmentOpenClassroomsA bachelor-level diploma in software development.
Writing

Engineering notes

Write-ups of problems I solved in Kotlin, Kotlin Multiplatform and Kobweb, with the code.

Password managers can't see a canvas: real sign-in forms in Compose for the web

Compose draws its text fields on a canvas, so browser password managers have nothing to fill or save. How Parrot puts a real HTML form under the canvas without changing how the fields look.Read the note →

Neural voices in shared Kotlin: Kokoro on ONNX Runtime, without sherpa-onnx or espeak

Replacing sherpa-onnx with ONNX Runtime behind one Kotlin interface, calling its C API from Kotlin on iPhone, and porting an English pronunciation front end so Kokoro needs no espeak-ng.Read the note →

My Android app in a browser: Parrot on Kotlin/Wasm

57 of 59 shared modules compiling for the browser with two build files changed, SQLite saved into IndexedDB, Readium under a Compose canvas, and what the first screen costs to download.Read the note →

Highlighting the sentence the narrator is reading: EPUB read-along with Media3

How Parrot keeps text and narration in step with SMIL media overlays, turns the page mid-sentence at the right moment, and the Media3 update that silently killed playback.Read the note →

Never lose someone's place: syncing reading positions across devices and formats

Local-first writes, compare-and-set revisions, when to settle a conflict and when to ask, and moving a position between an ebook and its audiobook.Read the note →

Every catalogue is hostile: an OPDS client in Kotlin Multiplatform

Parsing two feed formats in shared Kotlin, keeping passwords on their origin, hard budgets for every response, and the nine bugs a security review found.Read the note →

Neural voices on an e-ink reader: on-device TTS with sherpa-onnx

How Parrot reads any ebook aloud with Kokoro and Supertonic running on the phone, prepares chapters ahead, and survived a lambda that crashed every synthesis.Read the note →

Wrapping the AppsFlyer SDK into a Kotlin Multiplatform library

A coroutine-first wrapper around the AppsFlyer Android and iOS SDKs: all the logic in common code, deep links as a Flow, and tests that never touch a real SDK.Read the note →

Shipping SQLCipher inside a static Kotlin/Native framework (so the iOS team changed nothing)

Baking SQLCipher into a static Kotlin/Native framework, so the iOS team adds nothing, not even a linker flag.Read the note →

Building a smooth, infinite carousel in Kobweb

How to build a gapless, endlessly looping carousel with Kobweb and Silk.Read the note →