• Stars
    star
    1,064
  • Rank 43,399 (Top 0.9 %)
  • Language
    Kotlin
  • License
    Apache License 2.0
  • Created about 5 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Resources access for mobile (android & ios) Kotlin Multiplatform development

moko-resources
GitHub license Download kotlin-version badge badge badge badge badge badge badge badge

Mobile Kotlin resources

This is a Kotlin MultiPlatform library (and Gradle plugin) that provides access to the resources on macOS, iOS, Android the JVM and JS/Browser with the support of the default system localization.

Also MOKO resources supports Compose Multiplatform so you can implement all you UI in Kotlin with Jetpack Compose and MOKO resources.

Table of Contents

Features

  • Strings, Plurals to access the corresponding resources from common code;
  • Colors with light/dark mode support;
  • Compose Multiplatform support;
  • Images support (svg, png, jpg);
  • Fonts support (ttf, otf);
  • Files support (as raw or assets for android);
  • StringDesc for lifecycle-aware access to resources and unified localization on both platforms;
  • Static iOS frameworks support;
  • Fat and XC frameworks support.

Requirements

  • Gradle version 7.5+
  • Android Gradle Plugin 7.4.2+
  • Android API 16+
  • iOS version 11.0+

Installation

Gradle setup

root build.gradle

buildscript {
    repositories {
        gradlePluginPortal()
    }

    dependencies {
        classpath "dev.icerock.moko:resources-generator:0.23.0"
    }
}


allprojects {
    repositories {
        mavenCentral()
    }
}

project build.gradle

apply plugin: "dev.icerock.mobile.multiplatform-resources"

dependencies {
    commonMainApi("dev.icerock.moko:resources:0.23.0")
    commonMainApi("dev.icerock.moko:resources-compose:0.23.0") // for compose multiplatform

    commonTestImplementation("dev.icerock.moko:resources-test:0.23.0")
}

multiplatformResources {
    multiplatformResourcesPackage = "org.example.library" // required
    multiplatformResourcesClassName = "SharedRes" // optional, default MR
    multiplatformResourcesVisibility = MRVisibility.Internal // optional, default Public
    iosBaseLocalizationRegion = "en" // optional, default "en"
    multiplatformResourcesSourceSet = "commonClientMain"  // optional, default "commonMain"
}

Export classes to Swift

To use toUIColor(), toUIImage(), desc() and other iOS extensions from Swift - you should add export declarations:

framework {
    export("dev.icerock.moko:resources:0.23.0")
    export("dev.icerock.moko:graphics:0.9.0") // toUIColor here
}

Xcode setup

In iOS/macOS Info.plist need to add localizations, to use localizations strings.

<key>CFBundleLocalizations</key><array>
<string>en</string>
<string>ru</string>
</array>

in array should be added all used languages.

Android build types

If your project includes a build type, for example staging which isn't in moko-resources. That isn't an issue. Use matchingFallbacks to specify alternative matches for a given build type, as shown below

buildTypes {
    staging {
        initWith debug
        matchingFallbacks = ['debug']
    }
}

JS Webpack

JS/Browser generates json files which is included in webpack by default. For more details about JS see samples/resources-gallery/web-app sample

iOS/macOS static kotlin frameworks support

Static framework can't have own resources, so we should setup additional Build Phase in Xcode that will copy resources to application.

Please replace :yourframeworkproject to kotlin project gradle path, and set correct relative path ($SRCROOT/../ in example).

With org.jetbrains.kotlin.native.cocoapods

In Xcode add Build Phase (at end of list) with script:

"$SRCROOT/../gradlew" -p "$SRCROOT/../" :yourframeworkproject:copyFrameworkResourcesToApp \
    -Pmoko.resources.BUILT_PRODUCTS_DIR="$BUILT_PRODUCTS_DIR" \
    -Pmoko.resources.CONTENTS_FOLDER_PATH="$CONTENTS_FOLDER_PATH" \
    -Pkotlin.native.cocoapods.platform="$PLATFORM_NAME" \
    -Pkotlin.native.cocoapods.archs="$ARCHS" \
    -Pkotlin.native.cocoapods.configuration="$CONFIGURATION" 

Without org.jetbrains.kotlin.native.cocoapods

In Xcode add Build Phase (at end of list) with script:

"$SRCROOT/../gradlew" -p "$SRCROOT/../" :yourframeworkproject:copyFrameworkResourcesToApp \
    -Pmoko.resources.PLATFORM_NAME="$PLATFORM_NAME" \
    -Pmoko.resources.CONFIGURATION="$CONFIGURATION" \
    -Pmoko.resources.ARCHS="$ARCHS" \
    -Pmoko.resources.BUILT_PRODUCTS_DIR="$BUILT_PRODUCTS_DIR" \
    -Pmoko.resources.CONTENTS_FOLDER_PATH="$CONTENTS_FOLDER_PATH" 

Disable warning about static framework usage

To disable warnings about static framework in gradle set flag:

multiplatformResources {
    disableStaticFrameworkWarning = true
}

iOS executable

When you use executable kotlin target you should add custom build phase to xcode, after kotlin compilation:

"$SRCROOT/../gradlew" -p "$SRCROOT/../" :shared:copyResourcesDebugExecutableIosSimulatorArm64 \
    -Pmoko.resources.BUILT_PRODUCTS_DIR=$BUILT_PRODUCTS_DIR \
    -Pmoko.resources.CONTENTS_FOLDER_PATH=$CONTENTS_FOLDER_PATH

copyResourcesDebugExecutableIosSimulatorArm64 should be configured depends on target.

Configured sample you can see in samples/kotlin-ios-app

Creating Fat Framework with resources

Just use FatFrameworkTask from kotlin plugin .

Creating XCFramework with resources

Just use XCFramework from kotlin plugin .

But if you use static frameworks required additional setup - add to Xcode build phase (at end):

"$SRCROOT/../gradlew" -p "$SRCROOT/../" :shared:copyResourcesMPLReleaseXCFrameworkToApp \
    -Pmoko.resources.BUILT_PRODUCTS_DIR=$BUILT_PRODUCTS_DIR \
    -Pmoko.resources.CONTENTS_FOLDER_PATH=$CONTENTS_FOLDER_PATH

Details you can check in sample samples/ios-static-xcframework.

Usage

Example 1 - simple localization string

The first step is a create a file strings.xml in commonMain/resources/MR/base with the following content:

<?xml version="1.0" encoding="UTF-8" ?>
<resources>
    <string name="my_string">My default localization string</string>
</resources>

Next - create a file strings.xml with localized strings in commonMain/resource/MR/<languageCode>. Here's an example of creating commonMain/resource/MR/ru for a Russian localization:

<?xml version="1.0" encoding="UTF-8" ?>
<resources>
    <string name="my_string">Моя строка Π»ΠΎΠΊΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ</string>
</resources>

After adding the resources we can call a gradle sync or execute a gradle task generateMRcommonMain. This will generate a MR class containing MR.strings.my_string, which we can use in commonMain:

fun getMyString(): StringDesc {
    return StringDesc.Resource(MR.strings.my_string)
}

After this we can use our functions on the platform side:
Android:

val string = getMyString().toString(context = this)

iOS:

let string = getMyString().localized()

JS:

val strings = MR.stringsLoader.getOrLoad() // loading localization from a remote file
val string = getMyString().localized(strings)

Note: StringDesc is a multiple-source container for Strings: in StringDesc we can use a resource, plurals, formatted variants, or raw string. To convert StringDesc to String on Android call toString(context) (a context is required for the resources usage), on iOS - call localized().

Compose Multiplatform

with compose you can just call in commonMain

val string: String = stringResource(MR.strings.my_string)

MR directly from native side

Android:

val string = MR.strings.my_string.desc().toString(context = this)

iOS:

let string = MR.strings().my_string.desc().localized()

Get resourceId for Jetpack Compose / SwiftUI

Android:

val resId = MR.strings.my_string.resourceId

for example in Compose:

text = stringResource(id = MR.strings.email.resourceId)

iOS SwiftUI:

let resource = MR.strings().email
Text(
    LocalizedStringKey(resource.resourceId),
    bundle: resource.bundle
)

Note: more info in issue #126.

Example 2 - formatted localization string

In commonMain/resources/MR/base/strings.xml add:

<?xml version="1.0" encoding="UTF-8" ?>
<resources>
    <string name="my_string_formatted">My format \'%s\'</string>
</resources>

Then add the localized values for other languages like in example #1. Now create the following function in commonMain:

fun getMyFormatDesc(input: String): StringDesc {
    return StringDesc.ResourceFormatted(MR.strings.my_string_formatted, input)
}

To create formatted strings from resources you can also use extension format:

fun getMyFormatDesc(input: String): StringDesc {
    return MR.strings.my_string_formatted.format(input)
}

Now add support on the platform side like in example #1:
Android:

val string = getMyFormatDesc("hello").toString(context = this)

iOS:

let string = getMyFormatDesc(input: "hello").localized()

Warning: Do no mix positioned placeholders with unpositioned ones within a string, as this may lead to different behaviour on different platforms. Stick to one style for each string.

Example 3 - plural string

The first step is to create a file plurals.xml in commonMain/resources/MR/base with the following content:

<?xml version="1.0" encoding="UTF-8" ?>
<resources>
    <plural name="my_plural">
        <item quantity="zero">zero</item>
        <item quantity="one">one</item>
        <item quantity="two">two</item>
        <item quantity="few">few</item>
        <item quantity="many">many</item>
        <item quantity="other">other</item>
    </plural>
</resources>

Then add the localized values for other languages like in example #1.
Next, create a function in commonMain:

fun getMyPluralDesc(quantity: Int): StringDesc {
    return StringDesc.Plural(MR.plurals.my_plural, quantity)
}

Now add support on the platform side like in example #1:
Android:

val string = getMyPluralDesc(10).toString(context = this)

iOS:

let string = getMyPluralDesc(quantity: 10).localized()

Example 4 - plural formatted string

The first step is to create file plurals.xml in commonMain/resources/MR/base with the following content:

<?xml version="1.0" encoding="UTF-8" ?>
<resources>
    <plural name="my_plural">
        <item quantity="zero">no items</item>
        <item quantity="one">%d item</item>
        <item quantity="two">%d items</item>
        <item quantity="few">%d items</item>
        <item quantity="many">%d items</item>
        <item quantity="other">%d items</item>
    </plural>
</resources>

Then add the localized values for other languages like in example #1.
Next, create a function in commonMain:

fun getMyPluralFormattedDesc(quantity: Int): StringDesc {
    // we pass quantity as selector for correct plural string and for pass quantity as argument for formatting
    return StringDesc.PluralFormatted(MR.plurals.my_plural, quantity, quantity)
}

To create formatted plural strings from resources you can also use extension format:

fun getMyPluralFormattedDesc(quantity: Int): StringDesc {
    // we pass quantity as selector for correct plural string and for pass quantity as argument for formatting
    return MR.plurals.my_plural.format(quantity, quantity)
}

And like in example #1, add the platform-side support:
Android:

val string = getMyPluralFormattedDesc(10).toString(context = this)

iOS:

let string = getMyPluralFormattedDesc(quantity: 10).localized()

Example 5 - pass raw string or resource

If we already use some resources as a placeholder value, we can use StringDesc to change the string source:

fun getUserName(user: User?): StringDesc {
    if (user != null) {
        return StringDesc.Raw(user.name)
    } else {
        return StringDesc.Resource(MR.strings.name_placeholder)
    }
}

And just like in example 1 usage on platform side:
Android:

val string1 = getUserName(user).toString(context = this) // we got name from User model
val string2 = getUserName(null).toString(context = this) // we got name_placeholder from resources

iOS:

let string1 = getUserName(user: user).localized() // we got name from User model
let string2 = getUserName(user: null).localized() // we got name_placeholder from resources

Example 6 - Select localization in runtime

You can force StringDesc to use preferred localization in common code:

StringDesc.localeType = StringDesc.LocaleType.Custom("es")

and return to system behaviour (when localization depends on device settings):

StringDesc.localeType = StringDesc.LocaleType.System

Example 7 - Shared Images

Place images in the commonMain/resources/MR/images directory. Nested directories are also supported.

png and jpg

Image names should end with one of:

  • @0.75x - android ldpi;
  • @1x - android mdpi, ios 1x;
  • @1.5x - android hdpi;
  • @2x - android xhdpi, ios 2x;
  • @3x - android xxhdpi, ios 3x;
  • @4x - android xxxhdpi.

If we add the following files to commonMain/resources/MR/images:

Then we get an autogenerated MR.images.home_black_18 ImageResource in code. Usage:

  • Android: imageView.setImageResource(image.drawableResId)
  • iOS: imageView.image = image.toUIImage()

svg

The Image generator also supports svg files.

If we add the following file to commonMain/resources/MR/images:

  • car_black.svg

Then we get an autogenerated MR.images.car_black ImageResource in code. Usage:

  • Android: imageView.setImageResource(image.drawableResId)
  • iOS: imageView.image = image.toUIImage()

On Android it is a VectorDrawable,

On iOS iOS 13 or later it is a UIImage in the Assets catalog with preserves-vector-representation set to true.

images by name

You can get images by their name, too.

In commonMain create a Resources.kt file with the content below.

fun getImageByFileName(name: String): ImageResource {
    val fallbackImage = MR.images.transparent
    return MR.images.getImageByFileName(name) ?: fallbackImage
}

Usage:

  • Android: imageView.setImageResource(getImageByFileName("image_name"))
  • iOS: imageView.image = ResourcesKt.getImageByFileName(name: "image_name").toUIImage()!

Compose Multiplatform

With compose, you can simply use a painterResource in commonMain

val painter: Painter = painterResource(MR.images.home_black_18)

SwiftUI

For SwiftUI, create this Image extension:

extension Image {
    init(resource: KeyPath<MR.images, ImageResource>) {
        self.init(uiImage: MR.images()[keyPath: resource].toUIImage()!)
    }
}

Then, you can refer to ImageResources directly by their key path, which provides compiler errors for typos or missing resources:

Image(resource: \.home_black_18)

Example 8 - pass font

Fonts resources directory is commonMain/resources/MR/fonts.
Font name should be this pattern: <fontFamily>-<fontStyle> like:

  • Raleway-Bold.ttf
  • Raleway-Regular.ttf
  • Raleway-Italic.ttf Supports ttf and otf resources.

If we add to commonMain/resources/MR/fonts files:

  • Raleway-Bold.ttf
  • Raleway-Regular.ttf
  • Raleway-Italic.ttf

We got autogenerated MR.fonts.Raleway.italic, MR.fonts.Raleway.regular, MR.fonts.Raleway.bold FontResource in code, that we can use:

  • Android: textView.typeface = font.getTypeface(context = this)
  • iOS: textView.font = font.uiFont(withSize: 14.0)

Compose Multiplatform

with compose you can just call in commonMain

val fontFamily: FontFamily = fontFamilyResource(MR.fonts.Raleway.italic)

or you can get Font

val font: Font = MR.fonts.Raleway.italic.asFont(
  weight = FontWeight.Normal, // optional
  style = FontStyle.Normal // optional
)

Example 9 - pass colors

Colors resources directory is commonMain/resources/MR/colors.
Colors files is xml with format:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- format: #RRGGBB[AA] or 0xRRGGBB[AA] or RRGGBB[AA] where [AA] - optional -->
    <color name="valueColor">#B02743FF</color>
    <color name="referenceColor">@color/valueColor</color>
    <color name="themedColor">
        <light>0xB92743FF</light>
        <dark>7CCFEEFF</dark>
    </color>
    <color name="themedReferenceColor">
        <light>@color/valueColor</light>
        <dark>@color/referenceColor</dark>
    </color>
</resources>

If you want use one color without light/dark theme selection:

<color name="valueColor">#B02743FF</color>

If you want use value of other color - use references:

<color name="referenceColor">@color/valueColor</color>

If you want different colors in light/dark themes:

<color name="themedColor">
    <light>0xB92743FF</light>
    <dark>7CCFEEFF</dark>
</color>

Also themed colors can be referenced too:

<color name="themedReferenceColor">
    <light>@color/valueColor</light>
    <dark>@color/referenceColor</dark>
</color>

Colors available in common code insode MR.colors.** as ColorResource.
ColorResource can be read from platform side:

android:

val color: Int = MR.colors.valueColor.getColor(context = this)

iOS:

val color: UIColor = MR.colors.valueColor.getUIColor()

macOS:

val color: NSColor = MR.colors.valueColor.getNSColor()

jvm:

val light: Color = MR.colors.valueColor.lightColor
val dark: Color = MR.colors.valueColor.darkColor

web:

val light: Color = MR.colors.valueColor.lightColor
val dark: Color = MR.colors.valueColor.darkColor

Compose Multiplatform

with compose you can just call in commonMain

val color: Color = colorResource(MR.colors.valueColor)

Example 10 - plain file resource access

The first step is a create a resource file test.txt for example, in commonMain/resources/MR/files After gradle sync we can get file by id MR.files.test Moko-resources has out of box implementation function for read text files from common code - readText()

Usage on Android:

val text = MR.files.test.getText(context = this)

Usage on Apple:

val text = MR.files.test.readText()

If you want to read files not as text, add your own implementation to expect/actual FileResource

Compose Multiplatform

with compose you can just call in commonMain

val fileContent: String? by MR.files.test.readTextAsState()

Example 11 - assets access

Assets allow you save directories hierarchy (in files structure is plain). Locate files to commonMain/resources/MR/assets and access to it by MR.assets.*

Compose Multiplatform

with compose you can just call in commonMain

val assetContent: String? by MR.assets.test.readTextAsState()

Samples

In samples directory you can find multiple projects showed different usages.

Set Up Locally

In root of repository contains moko-resources gradle project - libraries and gradle plugin. You can just open project in IDE and develop. Then for tests in samples you should run run ./gradlew publishToMavenLocal gradle task. After this you can open any sample from samples in IDE and test your local version of moko-resources.

To check your changes before pull request run:

# check lib & plugin
./local-check.sh
# check samples
./local-samples-check.sh

Contributing

All development (both new features and bug fixes) is performed in the develop branch. This way master always contains the sources of the most recently released version. Please send PRs with bug fixes to the develop branch. Documentation fixes in the markdown files are an exception to this rule. They are updated directly in master.

The develop branch is pushed to master on release.

For more details on contributing please see the contributing guide.

License

Copyright 2019 IceRock MAG Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

More Repositories

1

moko-mvvm

Model-View-ViewModel architecture components for mobile (android & ios) Kotlin Multiplatform development
Kotlin
1,016
star
2

moko-template

Template project of a Mobile (Android & iOS) Kotlin MultiPlatform project with the MOKO libraries and modularized architecture
Kotlin
460
star
3

moko-widgets

Multiplatform UI DSL with screen management in common code for mobile (android & ios) Kotlin Multiplatform development
Kotlin
387
star
4

moko-kswift

Swift-friendly api generator for Kotlin/Native frameworks
Kotlin
350
star
5

moko-permissions

Runtime permissions controls for mobile (android & ios) Kotlin Multiplatform development
Kotlin
349
star
6

libs.kmp.icerock.dev

Kotlin Multiplatform libraries list with info auto-fetch
JavaScript
244
star
7

moko-network

Network components with codegeneration of rest api for mobile (android & ios) Kotlin Multiplatform development
Kotlin
151
star
8

moko-geo

Geolocation access for mobile (android & ios) Kotlin Multiplatform development
Kotlin
149
star
9

moko-socket-io

MOKO SocketIo by IceRock is Socket.IO implementation Kotlin Multiplatform library
Kotlin
122
star
10

moko-media

Media selection & presenting for mobile (android & ios) Kotlin Multiplatform development
Kotlin
116
star
11

mobile-multiplatform-gradle-plugin

Gradle plugin for simplify Kotlin Multiplatform mobile configurations
Kotlin
94
star
12

moko-maps

Control your map from common code for mobile (android & ios) Kotlin Multiplatform development
Kotlin
83
star
13

moko-parcelize

@Parcelize support for mobile (android & ios) Kotlin Multiplatform development
Kotlin
64
star
14

moko-paging

Pagination logic in common code for mobile (android & ios) Kotlin Multiplatform development
Kotlin
59
star
15

moko-errors

Automated exceptions handler for mobile (android & ios) Kotlin Multiplatform development.
Kotlin
52
star
16

moko-biometry

Biometry authentication with Touch ID, Face ID from common code with Kotlin Multiplatform Mobile
Kotlin
43
star
17

moko-web3

Ethereum Web3 implementation for mobile (android & ios) Kotlin Multiplatform development
Kotlin
41
star
18

moko-crash-reporting

Fatal and Non-Fatal reporting to Crashlytics for Kotlin Multiplatform Mobile
Kotlin
27
star
19

moko-units

Composing units into list and show in RecyclerView/UITableView/UICollectionView. Control your lists from common code for mobile (android & ios) Kotlin Multiplatform development
Kotlin
25
star
20

kmm.icerock.dev

JavaScript
24
star
21

redwood-sample

Kotlin
21
star
22

moko-tensorflow

Tensorflow Lite bindings for mobile (android & ios) Kotlin Multiplatform development
Kotlin
21
star
23

moko-fields

Input forms for mobile (android & ios) Kotlin Multiplatform development
Kotlin
20
star
24

moko-graphics

Graphics primitives for mobile (android & ios) Kotlin Multiplatform development
Kotlin
19
star
25

moko-javascript

JavaScript evaluation from kotlin common code for android & iOS
Kotlin
15
star
26

moko-core

Core classes for mobile (android & ios) Kotlin Multiplatform development
Kotlin
13
star
27

shaper

File structure generation tool from templates on Handlebars
Kotlin
12
star
28

moko-test

Test utilities for mobile (android & ios) Kotlin Multiplatform development
Kotlin
11
star
29

moko-widgets-template

Template project of a Mobile (Android & iOS) Kotlin MultiPlatform project with the MOKO widgets and other MOKO libs
Kotlin
10
star
30

kotlin-version-badge

badge with kotlin version, automatically fetched from mavenCentral package of latest version
Kotlin
10
star
31

moko

MOKO libraries umbrella project
9
star
32

gpuimage-filters-editor

iPad application photo editor with filters by GPUImage
Objective-C
9
star
33

email-service

Email sending service for kotlin - part of BOKO libs
Kotlin
8
star
34

codelabs.kmp.icerock.dev

Education of Kotlin Multiplatform Mobile
JavaScript
8
star
35

mobile-multiplatform-education

Internal lessons of mobile multiplatform development
Kotlin
8
star
36

moko.icerock.dev

Home page of moko libraries
HTML
7
star
37

moko-doctor

doctor script for checking the KMM developer's environment
Shell
6
star
38

admin-toolkit

Toolkit to create admin panels - part of BOKO libs
TypeScript
6
star
39

binance-futures-kotlin-api

Kotlin
6
star
40

fcm-push-service

Tools for sending fcm push by kotlin - part of BOKO libs
Kotlin
5
star
41

sms-service

Sms sending service for kotlin - part of BOKO libs
Kotlin
5
star
42

yellowdoor-app

Kotlin
4
star
43

storage-service

Tools for work with s3 storage and generate preview - part of BOKO libs
Kotlin
4
star
44

prototyping.icerock.dev

JavaScript
4
star
45

moko-time

Timestamp and timers for mobile (android & ios) Kotlin Multiplatform development
Kotlin
4
star
46

moko-gradle-plugin

Kotlin
3
star
47

moko-utils

Utilities for mobile (android & ios) Kotlin Multiplatform development
Kotlin
3
star
48

db-utils

Common tools for work with postgres via exposed - part of BOKO libs
Kotlin
3
star
49

web-utils

Common tools for create web application (ktor based) - part of BOKO libs
Kotlin
3
star
50

tinkoff-merchant-api

Tinkoff Merchant API Kotlin Client - part of BOKO libs
Kotlin
3
star
51

moko-intellij-plugin

Kotlin
3
star
52

slackbot-gitlab-ci

GitLab CI slackbot (beepboophq.com version)
JavaScript
2
star
53

auth-service

Common tools for JWT auth - part of BOKO libs
Kotlin
2
star
54

icerock-talaiot-config-plugin

Kotlin
2
star
55

PopupBottomNavigation

Popup menu with additional tabs for UITabBarController
Swift
2
star
56

IRPDFKit

PDF viewer with search for iOS
JavaScript
2
star
57

kafka-service

Common tools for kafka - part of BOKO libs
Kotlin
2
star
58

boko-validation

Konform based validation for Kotlin/JVM - part of BOKO libs
Kotlin
2
star
59

kmp.icerock.dev

Kotlin Mobile MultiPlatform materials landing
HTML
2
star
60

delivery.icerock.dev

Handlebars
1
star
61

shaper-templates

Templates for Shaper generation tool
Handlebars
1
star