Getting Started Guide

This guide walks you through integrating and using the SweetMeSoft KMP Library in a new Kotlin Multiplatform (KMP) project.


1. Prerequisites and Versions

Compatibility Warning Ensure your KMP project aligns with the library’s target environment versions before adding the dependencies.

  • Kotlin Version: 2.4.10
  • Compose Multiplatform: 1.11.1
  • Android Gradle Plugin (AGP): 9.3.0
  • Android Target SDK: 37 (Compile SDK: 37, Min SDK: 24)
  • iOS Target: iOS 12.0 or higher

2. Installation & Configuration

A. Version Catalog (gradle/libs.versions.toml)

Open your libs.versions.toml file and add the SweetMeSoft library declarations and required AndroidX Lifecycle transitive dependencies:

[versions]
sweetmesoft = "2.2.1"
androidx-lifecycle = "2.11.0"
compose-multiplatform = "1.9.0"
compose-plugin = "1.11.1"

[libraries]
sweetmesoft-kmpbase = { module = "com.sweetmesoft.kmpbase:kmpbase", version.ref = "sweetmesoft" }
sweetmesoft-kmpcontrols = { module = "com.sweetmesoft.kmpcontrols:kmpcontrols", version.ref = "sweetmesoft" }
sweetmesoft-kmpmaps = { module = "com.sweetmesoft.kmpmaps:kmpmaps", version.ref = "sweetmesoft" }

# Required Lifecycle libraries
androidx-lifecycle-viewmodel = { group = "androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" }
androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidx-lifecycle" }

B. Declaring Module Dependencies (build.gradle.kts - Shared Module)

In your shared multiplatform module (usually :shared or :composeApp), add the dependencies under the commonMain source set:

kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation(libs.sweetmesoft.kmpbase)
            implementation(libs.sweetmesoft.kmpcontrols)
            implementation(libs.sweetmesoft.kmpmaps)
        }
    }
}

3. Android Initialization

For Android applications, you must initialize the library in your MainActivity inside the onCreate method. This sets up edge-to-edge styling and caches the activity context for platform-specific library APIs (like map rendering, vibration feedback, files sharing, and image scaling).

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import com.sweetmesoft.kmpbase.BaseAndroid.Companion.initSweetMeSoft

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // Initialize the SweetMeSoft KMP Library
        initSweetMeSoft(this)
        
        setContent {
            App()
        }
    }
}

4. Voyager Navigation Integration

The architecture utilizes Voyager for type-safe multiplatform navigation. Connect Voyager’s Navigator to the core libraries inside your main shared application entry point:

import androidx.compose.runtime.Composable
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.transitions.SlideTransition
import com.sweetmesoft.kmpbase.base.BaseViewModel
import com.sweetmesoft.kmpbase.theme.AppTheme

@Composable
fun App() {
    AppTheme {
        Navigator(screen = LoginScreen()) { navigator ->
            // Connect navigator to BaseViewModel to allow navigation from VM layers
            BaseViewModel.navigator = navigator
            
            // Add transitions
            SlideTransition(navigator)
        }
    }
}

5. Implementing Screens & ViewModels

Ensure all presentation screens and business logic models inherit from BaseScreen and BaseViewModel respectively.

A. ViewModels (BaseViewModel)

Subclass BaseViewModel to handle standard loading operations, handle network routines safely within coroutines, and present alerts.

import com.sweetmesoft.kmpbase.base.BaseViewModel
import com.sweetmesoft.kmpbase.controls.alerts.PopupHandler
import com.sweetmesoft.kmpbase.tools.NetworkUtils
import kotlinx.coroutines.launch

class LoginViewModel : BaseViewModel() {

    fun executeLogin(credentials: UserCredentials) {
        viewModelScope.launch {
            // Trigger global loading spinner overlay
            showLoading()
            
            val result = NetworkUtils.post<LoginResponse>(
                url = "https://api.example.com/login",
                body = credentials
            )
            
            hideLoading()
            
            result.onSuccess { response ->
                // Navigate to home screen
                navigator?.replace(HomeScreen())
            }.onFailure { exception ->
                // Trigger global error alert dialog from VM layer
                PopupHandler.displayAlert(
                    title = "Authentication Error",
                    message = exception.message ?: "Failed to log in."
                )
            }
        }
    }
}

B. Screens (BaseScreen)

Subclass BaseScreen (or advanced layouts like BaseBottomBarScreen, BaseDrawerScreen, or BaseBottomSheetScreen) to build layouts. The base screen automatically overlays global alert dialogs and progress sheets.

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.sweetmesoft.kmpbase.base.BaseScreen
import com.sweetmesoft.kmpbase.controls.LoadingView

class MainDashboardScreen : BaseScreen(
    title = "Dashboard",
    showTop = true // Shows the standard Toolbar header
) {
    @Composable
    override fun ScreenContent() {
        val viewModel = rememberScreenModel { MainDashboardViewModel() }
        
        Box(modifier = Modifier.fillMaxSize()) {
            Column(modifier = Modifier.padding(16.dp)) {
                Text("Welcome to KMP dashboard!")
            }
            
            // Required overlay to show global loader triggered by showLoading()
            LoadingView()
        }
    }
}

6. Usage of Shared Core Components

A. List Configurations (RemoteList)

Easily bind network data structures directly to composable list canvases:

import com.sweetmesoft.kmpbase.controls.commonList.RemoteList

RemoteList<Product>(
    url = "https://api.example.com/products",
    title = "Available Products",
    bearer = "session_token"
) { product ->
    ProductRow(product)
}

B. Map Components (MapComponent)

Add a platform-specific map component (Google Maps on Android, MapKit on iOS) with custom marker positions:

import com.sweetmesoft.kmpmaps.MapComponent
import com.sweetmesoft.kmpmaps.controls.Coordinates
import com.sweetmesoft.kmpmaps.controls.GeoPosition
import com.sweetmesoft.kmpmaps.controls.MarkerMap

val points = listOf(
    GeoPosition(
        coordinates = Coordinates(37.7749, -122.4194),
        markerMap = MarkerMap(title = "SF Headquarters")
    )
)

MapComponent(
    coordinates = Coordinates(37.7749, -122.4194),
    zoom = 12f,
    markers = points
)

C. Picker Controls (DatePicker)

import com.sweetmesoft.kmpcontrols.pickers.DatePicker
import kotlinx.datetime.LocalDate

var selectedDate by remember { mutableStateOf(LocalDate(2026, 6, 28)) }

DatePicker(
    value = selectedDate,
    title = "Select Date",
    onSelectedDate = { date ->
        selectedDate = date
    }
)

D. Autocomplete Controls (AutoCompleteTextField)

import com.sweetmesoft.kmpcontrols.controls.AutoCompleteTextField

var selectedFruit by remember { mutableStateOf("") }
val fruits = listOf("Apple", "Banana", "Cherry")

AutoCompleteTextField(
    value = selectedFruit,
    title = "Select Fruit",
    suggestions = fruits.filter { it.contains(selectedFruit, ignoreCase = true) },
    onValueChange = { selectedFruit = it },
    onSuggestionSelected = { suggestion ->
        selectedFruit = suggestion
        true
    }
)

This site uses Just the Docs, a documentation theme for Jekyll.