GitPedia

GithubSearchKMM Compose SwiftUI

🍭 GithubSearchKMM - Github Repos Search - Android - iOS - Kotlin Multiplatform Mobile using Jetpack Compose, SwiftUI, FlowRedux, Coroutines Flow, Dagger Hilt, Koin Dependency Injection, shared KMP ViewModel, Clean Architecture

From hoc081098·Updated April 20, 2026·View on GitHub·

Github Repos Search - Kotlin Multiplatform Mobile using Jetpack Compose, SwiftUI, FlowRedux, Coroutines Flow, Dagger Hilt, Koin Dependency Injection, shared KMP ViewModel, Clean Architecture The project is written primarily in Kotlin, distributed under the MIT License license, first published in 2022. Key topics include: jetpack-compose, kmm, kmm-flowredux, kmm-jetpack-compose, kmm-library.

Latest release: 0.1.0
September 29, 2023View Changelog →

GithubSearchKMM

Github Repos Search - Kotlin Multiplatform Mobile using Jetpack Compose, SwiftUI,
FlowRedux, Coroutines Flow, Dagger Hilt, Koin Dependency Injection, shared KMP ViewModel, Clean Architecture

Android Build CI
iOS Build CI
Validate Gradle Wrapper
API
Kotlin
Hits
License: MIT
codecov
Platform

Minimal Kotlin Multiplatform project with SwiftUI, Jetpack Compose.

  • Android (Jetpack compose)
  • iOS (SwiftUI)

Liked some of my work? Buy me a coffee (or more likely a beer)

<a href="https://www.buymeacoffee.com/hoc081098" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-blue.png" alt="Buy Me A Coffee" height=64></a>

Modern Development

  • Kotlin Multiplatform
  • Jetpack Compose
  • Kotlin Coroutines & Flows
  • Dagger Hilt
  • SwiftUI
  • Koin Dependency Injection
  • FlowRedux State Management
  • Shared KMP ViewModel
  • Clean Architecture

Tech Stacks

Screenshots

Android (Light theme)

Android (Dark theme)

iOS (Light theme)

iOS (Dark theme)

Overall Architecture

What is shared?

  • domain: Domain models, UseCases, Repositories.
  • presentation: ViewModels, ViewState, ViewSingleEvent, ViewAction.
  • data: Repository Implementations, Remote Data Source, Local Data Source.
  • utils: Utilities, Logging Library

Unidirectional data flow - FlowRedux

<p align="center"> <img src="https://raw.githubusercontent.com/freeletics/RxRedux/master/docs/rxredux.png" width="600" alt="RxRedux In a Nutshell"/> </p>
kotlin
public sealed interface FlowReduxStore<Action, State> { /** * The state of this store. */ public val stateFlow: StateFlow<State> /** * @return false if cannot dispatch action (this store was closed). */ public fun dispatch(action: Action): Boolean /** * Call this method to close this store. * A closed store will not accept any action anymore, thus state will not change anymore. * All [SideEffect]s will be cancelled. */ public fun close() /** * After calling [close] method, this function will return true. * * @return true if this store was closed. */ public fun isClosed(): Boolean }

Multiplatform ViewModel

kotlin
open class GithubSearchViewModel( searchRepoItemsUseCase: SearchRepoItemsUseCase, private val savedStateHandle: SavedStateHandle, ) : ViewModel() { private val effectsContainer = GithubSearchSideEffectsContainer(searchRepoItemsUseCase) private val store = viewModelScope.createFlowReduxStore( initialState = GithubSearchState.initial(), sideEffects = effectsContainer.sideEffects, reducer = Reducer(flip(GithubSearchAction::reduce)) .withLogger(githubSearchFlowReduxLogger()) ) val termStateFlow: NonNullStateFlowWrapper<String> = savedStateHandle.getStateFlow(TERM_KEY, "").wrap() val stateFlow: NonNullStateFlowWrapper<GithubSearchState> = store.stateFlow.wrap() val eventFlow: NonNullFlowWrapper<GithubSearchSingleEvent> = effectsContainer.eventFlow.wrap() init { store.dispatch(InitialSearchAction(termStateFlow.value)) } @MainThread fun dispatch(action: GithubSearchAction): Boolean { if (action is GithubSearchAction.Search) { savedStateHandle[TERM_KEY] = action.term } return store.dispatch(action) } companion object { private const val TERM_KEY = "com.hoc081098.github_search_kmm.presentation.GithubSearchViewModel.term" /** * Used by non-Android platforms. */ fun create(searchRepoItemsUseCase: SearchRepoItemsUseCase): GithubSearchViewModel = GithubSearchViewModel(searchRepoItemsUseCase, SavedStateHandle()) } }

Platform ViewModel

Android

Extends GithubSearchViewModel to use Dagger Constructor Injection.

kotlin
@HiltViewModel class DaggerGithubSearchViewModel @Inject constructor( searchRepoItemsUseCase: SearchRepoItemsUseCase, savedStateHandle: SavedStateHandle, ) : GithubSearchViewModel(searchRepoItemsUseCase, savedStateHandle)

iOS

Conform to ObservableObject and use @Published property wrapper.

swift
import Foundation import Combine import shared @MainActor class IOSGithubSearchViewModel: ObservableObject { private let vm: GithubSearchViewModel @Published private(set) var state: GithubSearchState @Published private(set) var term: String = "" let eventPublisher: AnyPublisher<GithubSearchSingleEventKs, Never> init(vm: GithubSearchViewModel) { self.vm = vm self.eventPublisher = vm.eventFlow.asNonNullPublisher() .assertNoFailure() .map(GithubSearchSingleEventKs.init) .eraseToAnyPublisher() self.state = vm.stateFlow.value vm.stateFlow.subscribe( scope: vm.viewModelScope, onValue: { [weak self] in self?.state = $0 } ) self.vm .termStateFlow .asNonNullPublisher(NSString.self) .assertNoFailure() .map { $0 as String } .assign(to: &$term) } @discardableResult func dispatch(action: GithubSearchAction) -> Bool { self.vm.dispatch(action: action) } deinit { Napier.d("\(self)::deinit") vm.clear() } }

Download APK

Building & Develop

  • Android Studio Hedgehog | 2023.1.1 (note: Java 17 is now the minimum version required).

  • Xcode 13.2.1 or later (due to use of new Swift 5.5 concurrency APIs).

  • Clone project: git clone https://github.com/hoc081098/GithubSearchKMM.git

  • Android: open project by Android Studio and run as usual.

  • iOS

    shell
    # Cd to root project directory cd GithubSearchKMM # Setup sh scripts/run_ios.sh

    There's a Build Phase script that will do the magic. 🧞 <br>
    <kbd>Cmd</kbd> + <kbd>B</kbd> to build
    <br>
    <kbd>Cmd</kbd> + <kbd>R</kbd> to run.

    You can also build and run iOS app from Xcode as usual.

LOC

shell
-------------------------------------------------------------------------------- Language Files Lines Blank Comment Code -------------------------------------------------------------------------------- Kotlin 116 7942 996 453 6493 JSON 7 3938 0 0 3938 Swift 16 960 124 102 734 Markdown 1 281 53 0 228 Bourne Shell 2 249 28 116 105 Batch 1 92 21 0 71 XML 6 69 6 0 63 -------------------------------------------------------------------------------- Total 149 13531 1228 671 11632 --------------------------------------------------------------------------------

Contributors

Showing top 3 contributors by commit count.

View all contributors on GitHub →

This article is auto-generated from hoc081098/GithubSearchKMM-Compose-SwiftUI via the GitHub API.Last fetched: 6/19/2026