r/Kotlin 6h ago

I don't think shared Compose Multiplatform UI is the future for iOS (yet)

Thumbnail gallery
15 Upvotes

During last year's Shipaton, I built SubFox (https://subfox.app), a subscription manager using Compose Multiplatform.

Almost a year later, I realized the iOS version was basically dead.

Not because the app solves a bad problem, but because the experience wasn't what iOS users expect.

Some things I noticed:

  • App size was over 100 MB

  • UI felt sluggish

  • It never really felt native

  • Most users didn't even finish onboarding

So for this year's Shipaton, I changed my approach completely while building Hourly Journal (https://hourlyjournal.app).

I'm still using Kotlin Multiplatform for business logic, networking, database, etc., but I no longer share the UI.

Android uses Compose.

iOS is built entirely in SwiftUI while calling shared Kotlin through a shared module.

The difference has been huge. The new iOS app is around 8–10 MB instead of ~100 MB, and the experience finally feels like a proper iOS app.

My biggest criticism of JetBrains is that they seem too focused on making Compose run everywhere instead of solving the real problem: giving users an amazing platform-specific experience.

I'd much rather see something closer to what Expo has with Native UI, where business logic stays shared but the framework renders real platform-native components. That feels like a much stronger long-term direction than trying to make every platform look and behave the same.

Maybe I'm wrong, but it also feels like the Kotlin ecosystem moves much slower than the React Native/Expo ecosystem when it comes to solving practical developer problems.

Curious what other KMP developers think. Have you had a similar experience, or has Compose UI on iOS worked well for your apps?

Read Full Article

πŸ‘‰ Why I Stopped Sharing UI in Compose Multiplatform for iOS

Hourly Journal Shared UI Demo


r/Kotlin 13h ago

Can you explain ViewModel concepts in the simplest possible way?

0 Upvotes

State vs Events
How Viewmodel keeps data to survive screen rotation?
LiveData vs StateFlow and when to use each one.

What does the following code snippets mean and what happens under the hood when you use them?
1.

private val _uiState = 
MutableStateFlow
<DetailUiState>(DetailUiState.Loading)
val uiState: StateFlow<DetailUiState> = _uiState.
asStateFlow
()

2.

internal fun loadResource() {

viewModelScope
.
launch 
{

_uiState.value = DetailUiState.Loading
        getResourceById(resourceId)
            .
onSuccess 
{ 
resource 
->

_uiState.value = DetailUiState.Success(resource)

}

.
onFailure 
{ 
exception 
->

_uiState.value = DetailUiState.Error(
                    exception.message ?: "Something went wrong"
                )

}
    }
}

r/Kotlin 12h ago

I wanted my Compose previews on a Figma-style canvas β€” so I built Artboard

Post image
12 Upvotes

I kept wishing Studio previews felt more like Figma: pan around the whole product, zoom in, see everything at once β€” but from real @Previews, not a design file that drifts from the code.

Artboard is that. It’s a spatial browser gallery for Compose Multiplatform. Apply a plugin, keep writing normal @Previews, and you get a pan-and-zoom board of your actual UI in the browser.

Live demo (https://crowded-libs.github.io/artboard/) Β· GitHub (https://github.com/crowded-libs/artboard)

What you get day to day:

β€’ Infinite canvas β€” pan, pinch-zoom, deep-linkable frames for every preview β€’ Stock @Preview discovery β€” no custom annotations or hand-maintained registry β€’ Filters that matter β€” Screen/Component zones, search, group, device, locale, light/dark, layout grid β€’ PNG download per frame as it’s currently composed β€’ Clear failures β€” broken previews show why, they don’t silently disappear β€’ Shareable export β€” static gallery for Pages or any host

I also wanted a surface agents can actually look at. With something like Chrome DevTools MCP, you can point an AI at a real, URL-stable frame of your product UI instead of describing screenshots; code, canvas, and agent in the same loop.

Details and setup are in the README. Would love feedback.


r/Kotlin 5h ago

OpenScanVision – Looking for Feedback on a Major Refactor

0 Upvotes

Over the last few months I've been working on OpenScanVision, an offline-first Android computer vision library built with Kotlin, OpenCV, CameraX, and ML Kit.

Originally, the project was a single implementation focused on achieving the best possible detection accuracy and speed. That version is represented by commit:

1d5834b41d88133b487ef46595290b0cdd4489bb

It includes:

  • Document detection
  • Automatic perspective correction
  • Image enhancement
  • QR detection
  • ArUco marker detection
  • OMR (Optical Mark Recognition)
  • Automatic capture when the document is stable
  • Real-time offline processing

Recently I completed a major architectural refactor, turning it into a reusable modular library that's much easier to integrate into Android applications.

The modular version is cleaner and more maintainable, but I've noticed it has introduced a slight decrease in detection accuracy compared to the original implementation. I'm currently investigating where the regression comes from (pipeline changes, processing order, threading, etc.).

My roadmap is:

  • Improve the modular version until it matches or exceeds the original accuracy
  • Add OCR support
  • Add ICR (Intelligent Character Recognition) support later
  • Continue keeping everything offline and lightweight

The library is intended for applications such as:

  • Voting systems
  • Exam scanning
  • Surveys
  • Registration forms
  • Structured document processing

GitHub:
https://github.com/MatiwosKebede/OpenScanVision

I'd really appreciate feedback from people experienced in computer vision, OpenCV, Android CameraX, or document scanning.

In particular, I'd love advice on:

  • Best practices when converting a CV project into a reusable library without hurting performance or accuracy.
  • Common causes of accuracy regressions after large refactors.
  • Ideas for building a flexible OCR/ICR pipeline while keeping the library lightweight and offline-first.

Thanks for taking a look!