# Yasan Glass Toolkit Yasan Glass Toolkit is a comprehensive Kotlin Multiplatform library that provides essential utilities and components for building cross-platform applications. The toolkit supports Android, iOS, JVM, JavaScript, and WebAssembly platforms, offering a unified API for common development patterns. It focuses on reducing boilerplate code and providing reusable components for modern Kotlin applications. The toolkit is organized into four modules: Core (fundamental utilities and platform abstractions), Compose (Jetpack Compose Multiplatform extensions), About (developer information components), and Koin (dependency injection configuration). Each module is independently versioned and published to Maven Central, allowing developers to include only the components they need. The library emphasizes clean architecture principles, type safety, and seamless integration with popular Kotlin frameworks. ## Core Module - URL Launcher Cross-platform URL launching with platform-specific implementations. ```kotlin // Gradle dependency implementation("glass.yasan.toolkit:core:") // Basic usage with Koin injection class MyViewModel( private val urlLauncher: UrlLauncher ) : ViewModel() { fun openWebsite() { val success = urlLauncher.launch("https://example.com") if (!success) { // Handle launch failure println("Failed to open URL") } } fun sendEmail() { urlLauncher.launch("mailto:hello@example.com") } } // Manual instantiation (without DI) val launcher = UrlLauncherImpl() launcher.launch("https://github.com") ``` ## Core Module - Dispatcher Provider Centralized coroutine dispatcher management for testable asynchronous code. ```kotlin // Define custom dispatcher provider for testing class TestDispatcherProvider : DispatcherProvider { override val main = Dispatchers.Unconfined override val io = Dispatchers.Unconfined override val default = Dispatchers.Unconfined override val unconfined = Dispatchers.Unconfined } // Production usage with Koin class DataRepository( private val dispatcherProvider: DispatcherProvider ) { suspend fun fetchData() = withContext(dispatcherProvider.io) { // Network call or database operation api.getData() } suspend fun processData(data: List) = withContext(dispatcherProvider.default) { // CPU-intensive processing data.map { it.uppercase() } } } // Create default dispatcher provider val dispatchers = createDefaultDispatcherProvider() ``` ## Core Module - Coroutine Extensions Utilities for handling cancellation and errors in coroutines. ```kotlin suspend fun loadUserData(): Result = runCatching { apiService.getUser() } // Safe handling with cancellation support suspend fun displayUserData() { val user = loadUserData() .getOrNullOrRethrowCancellation() if (user != null) { updateUI(user) } } // Alternative error handling suspend fun loadWithFallback() { val data = loadUserData() .getOrElseOrRethrowCancellation { error -> log.error("Failed to load user", error) User.default() // Fallback value } } // Check if exception should be rethrown try { riskyOperation() } catch (e: Exception) { e.rethrowCancellation() // Rethrows if coroutine cancelled handleError(e) } ``` ## Compose Module - Toolkit ViewModel Base ViewModel with built-in state, event, and action management. ```kotlin // Define contracts data class HomeViewState( val isLoading: Boolean = false, val users: List = emptyList() ) : ViewState sealed class HomeViewEvent : ViewEvent { data object LoadUsers : HomeViewEvent() data class DeleteUser(val id: String) : HomeViewEvent() } sealed class HomeViewAction : ViewAction { data class ShowError(val message: String) : HomeViewAction() data object NavigateToSettings : HomeViewAction() } // Implement ViewModel class HomeViewModel( private val repository: UserRepository ) : ToolkitViewModel() { override fun defaultViewState() = HomeViewState() override suspend fun onViewEvent(event: HomeViewEvent) { when (event) { is HomeViewEvent.LoadUsers -> loadUsers() is HomeViewEvent.DeleteUser -> deleteUser(event.id) } } private suspend fun loadUsers() { updateViewState { copy(isLoading = true) } repository.getUsers() .onSuccess { users -> updateViewState { copy(users = users, isLoading = false) } } .onFailure { error -> updateViewState { copy(isLoading = false) } sendViewAction(HomeViewAction.ShowError(error.message ?: "Unknown error")) } } private suspend fun deleteUser(id: String) { repository.deleteUser(id) sendViewEvent(HomeViewEvent.LoadUsers) // Reload list } } // Use in Compose UI @Composable fun HomeScreen(viewModel: HomeViewModel) { val state by viewModel.viewState.collectAsState() LaunchedEffect(Unit) { viewModel.sendViewEvent(HomeViewEvent.LoadUsers) viewModel.viewAction.collect { action -> when (action) { is HomeViewAction.ShowError -> { // Show snackbar or toast } is HomeViewAction.NavigateToSettings -> { // Navigate } } } } if (state.isLoading) { CircularProgressIndicator() } else { UserList(state.users) } } ``` ## Compose Module - Color Extensions Utility functions for color manipulation and accessibility. ```kotlin val primaryColor = Color(0xFF6200EE) // Check color brightness if (primaryColor.isDark()) { // Use light text } else { // Use dark text } // Get appropriate content color for accessibility val contentColor = primaryColor.toContentColor() // Returns Black or White Text( text = "Hello", color = contentColor, modifier = Modifier.background(primaryColor) ) // Adjust color brightness val lighterColor = primaryColor.lighten(factor = 0.1f) // 10% lighter val darkerColor = primaryColor.darken(factor = 0.2f) // 20% darker // Custom threshold for brightness detection val backgroundColor = Color(0xFF888888) if (backgroundColor.isLight(luminanceThreshold = 0.6f)) { // More strict light detection } ``` ## Compose Module - Spacer Utilities Convenient spacer composables for layouts and lazy lists. ```kotlin @Composable fun ProfileScreen() { Column { Avatar() VerticalSpacer(height = 16.dp) Text("John Doe") VerticalSpacer(height = 8.dp) Text("Software Developer") VerticalSpacer(height = 24.dp) Row { Button(onClick = {}) { Text("Follow") } HorizontalSpacer(width = 12.dp) Button(onClick = {}) { Text("Message") } } } } // Use in lazy lists @Composable fun ItemList() { LazyColumn { items(users) { user -> UserItem(user) } verticalSpacerItem(height = 16.dp) item { LoadMoreButton() } } } // Horizontal lazy list @Composable fun HorizontalList() { LazyRow { items(categories) { category -> CategoryChip(category) } horizontalSpacerItem(width = 8.dp) } } ``` ## Compose Module - Flow Extensions (Non-Web) StateFlow conversion utilities scoped to ViewModel lifecycle. ```kotlin class ProductViewModel( private val repository: ProductRepository ) : ToolkitViewModel() { // Convert Flow to StateFlow with eager start val products: StateFlow> = repository.getProducts() .stateInEagerly(initialValue = emptyList()) // Convert with lazy start (only when collected) val categories: StateFlow> = repository.getCategories() .stateInLazily(initialValue = emptyList()) // Convert with WhileSubscribed strategy val searchResults: StateFlow> = searchQueryFlow .flatMapLatest { query -> repository.search(query) } .stateInWhileSubscribed( stopTimeout = 5.seconds, replayExpiration = Duration.INFINITE, initialValue = emptyList() ) // Custom SharingStarted strategy val activeUserCount: StateFlow = userActivityFlow .stateIn( started = SharingStarted.WhileSubscribed(5000), initialValue = 0 ) override fun defaultViewState() = ProductViewState() override suspend fun onViewEvent(event: ProductViewEvent) {} } ``` ## About Module - Developer Model Data model for developer information with automatic icon mapping. ```kotlin // Use default Yasan Glass developer info val developer = Developer() // Custom developer information val customDeveloper = Developer( name = "Jane Smith", biography = "Mobile App Developer specializing in Kotlin Multiplatform", picture = Developer.Picture( gravatar = Developer.Picture.Gravatar( id = "md5hash_of_email_address" ) ), links = persistentListOf( Developer.Link( name = "Website", url = "https://janesmith.dev" ), Developer.Link( name = "GitHub", url = "https://github.com/janesmith" ), Developer.Link( name = "Email", url = "mailto:jane@example.com" ), Developer.Link( name = "Telegram Channel", url = "https://t.me/janeupdates" ) ) ) // Access link properties customDeveloper.links.forEach { link -> println("${link.name}: ${link.url}") println("Type: ${link.type}") // AUTO-DETECTED: EMAIL, GITHUB, etc. println("Icon: ${link.icon}") // AUTO-MAPPED drawable resource } // Get Gravatar image URL val avatarUrl = customDeveloper.picture.gravatar.getImageUrl(size = 256) // Link type detection examples Developer.Link("GitHub", "https://github.com/user").type // GITHUB Developer.Link("Email", "mailto:user@example.com").type // EMAIL Developer.Link("Discord", "https://discord.gg/invite").type // DISCORD Developer.Link("Website", "https://example.com").type // WEBSITE ``` ## About Module - Developer Repository Repository for accessing developer information. ```kotlin class AboutViewModel( private val repository: AboutRepository ) : ViewModel() { val developer: StateFlow = repository.developer .stateIn( scope = viewModelScope, started = SharingStarted.Lazily, initialValue = Developer() ) } // Use in Compose @Composable fun AboutScreen(viewModel: AboutViewModel) { val developer by viewModel.developer.collectAsState() Column { AsyncImage( model = developer.picture.gravatar.getImageUrl(), contentDescription = "Developer avatar" ) Text(developer.name, style = MaterialTheme.typography.headlineMedium) Text(developer.biography, style = MaterialTheme.typography.bodyMedium) developer.links.forEach { link -> OutlinedButton(onClick = { /* Launch URL */ }) { Icon(painterResource(link.icon), contentDescription = null) Spacer(Modifier.width(8.dp)) Text(link.name) } } } } ``` ## Koin Module - Toolkit Dependency Injection Pre-configured Koin module with all toolkit dependencies. ```kotlin // Gradle dependency implementation("glass.yasan.toolkit:koin:") // Basic setup in your App fun initKoin() { startKoin { modules(toolkitModule) } } // Extended setup with your app modules fun Application.setupKoin() { startKoin { androidContext(this@setupKoin) modules( toolkitModule, appModule, networkModule, databaseModule ) } } // What toolkitModule provides: val appModule = module { // DispatcherProvider is already available single { NetworkClient(dispatcherProvider = get()) } // ApplicationScope is already available single { BackgroundSyncManager(applicationScope = get()) } // AboutRepository is already available factory { AboutViewModel(repository = get()) } // UrlLauncher is platform-specific and available factory { BrowserManager(urlLauncher = get()) } } // Platform-specific modules are automatically included // - Android: Includes Android-specific implementations // - iOS: Includes iOS-specific implementations // - JVM: Includes JVM-specific implementations // - JS/WASM: Includes web-specific implementations ``` ## Koin Module - Custom Module Integration Integrating toolkit with custom application modules. ```kotlin val networkModule = module { single { HttpClient { install(ContentNegotiation) { json() } } } single { ApiService( httpClient = get(), dispatcherProvider = get() // From toolkitModule ) } } val viewModelModule = module { viewModel { HomeViewModel( userRepository = get(), urlLauncher = get(), // From toolkitModule dispatcherProvider = get() // From toolkitModule ) } viewModel { ProfileViewModel( aboutRepository = get() // From toolkitModule ) } } // Initialize all modules fun initDependencyInjection() { startKoin { modules( toolkitModule, // Core toolkit dependencies networkModule, // App networking viewModelModule // App ViewModels ) } } // Use in Compose @Composable fun App() { val homeViewModel: HomeViewModel = koinViewModel() val urlLauncher: UrlLauncher = koinInject() HomeScreen( viewModel = homeViewModel, onLinkClick = { url -> urlLauncher.launch(url) } ) } ``` ## Summary The Yasan Glass Toolkit serves as a foundation for Kotlin Multiplatform projects, providing battle-tested utilities that eliminate common boilerplate. Its modular architecture allows teams to adopt individual components without committing to the entire library. The Core module's cross-platform abstractions enable writing testable business logic once and running it everywhere, while the Compose module provides a robust ViewModel pattern with built-in state management. The color utilities and spacer components accelerate UI development with accessible, consistent designs. The About module offers a drop-in solution for developer attribution, and the Koin integration ensures smooth dependency injection across all platforms. Integration patterns follow standard Kotlin conventions: add dependencies via Gradle, include the Koin module in your DI setup, and extend ToolkitViewModel for your app's screens. The toolkit works seamlessly with popular libraries like Ktor, Compose Multiplatform, and kotlinx.coroutines. Whether building a new cross-platform app or migrating existing code, the toolkit's incremental adoption path and comprehensive documentation make it a practical choice for teams prioritizing code quality and developer productivity. The library is actively maintained, follows semantic versioning, and receives regular updates to support the latest Kotlin and Compose Multiplatform releases.