Pure Kotlin CSV Reader/Writer

Overview

kotlin-csv

Version License: Apache License 2.0 CircleCI codecov CodeFactor

Pure Kotlin CSV Reader/Writer.

Design goals

1. Simple interface

  • easy to setup
  • use DSL so easy to read

2. Automatic handling of I/O

  • in Java, we always need to close file. but it's boilerplate code and not friendly for non-JVM user.
  • provide interfaces which automatically close file without being aware.

3. Multiplatform

  • kotlin multiplatform project

Usage

Download

Gradle

//gradle kotlin DSL
implementation("com.github.doyaaaaaken:kotlin-csv-jvm:1.2.0") //for JVM platform
implementation("com.github.doyaaaaaken:kotlin-csv-js:1.2.0") //for Kotlin JS platform

//gradle groovy DSL
implementation 'com.github.doyaaaaaken:kotlin-csv-jvm:1.2.0' //for JVM platform
implementation 'com.github.doyaaaaaken:kotlin-csv-js:1.2.0' //for Kotlin JS platform

Maven

<dependency>
  <groupId>com.github.doyaaaaaken</groupId>
  <artifactId>kotlin-csv-jvm</artifactId>
  <version>1.2.0</version>
</dependency>
<dependency>
  <groupId>com.github.doyaaaaaken</groupId>
  <artifactId>kotlin-csv-js</artifactId>
  <version>1.2.0</version>
</dependency>

kscript

@file:DependsOn("com.github.doyaaaaaken:kotlin-csv-jvm:1.2.0") //for JVM platform
@file:DependsOn("com.github.doyaaaaaken:kotlin-csv-js:1.2.0")

//for Kotlin JS platform

Examples

CSV Read examples

Simple case

You can read csv file from String, java.io.File or java.io.InputStream object.
No need to do any I/O handling. (No need to call use, close and flush method.)

// read from `String`
val csvData: String = "a,b,c\nd,e,f"
val rows: List<List<String>> = csvReader().readAll(csvData)

// read from `java.io.File`
val file: File = File("test.csv")
val rows: List<List<String>> = csvReader().readAll(file)

Read with header

val csvData: String = "a,b,c\nd,e,f"
val rows: List<Map<String, String>> = csvReader().readAllWithHeader(csvData)
println(rows) //[{a=d, b=e, c=f}]

Read as Sequence

Sequence type allows to execute lazily.
It starts to process each rows before reading all row data.

See detail about Sequence type on Kotlin official document.

csvReader().open("test1.csv") {
    readAllAsSequence().forEach { row: List<String> ->
        //Do something
        println(row) //[a, b, c]
    }
}

csvReader().open("test2.csv") {
    readAllWithHeaderAsSequence().forEach { row: Map<String, String> ->
        //Do something
        println(row) //{id=1, name=doyaaaaaken}
    }
}

NOTE:readAllAsSequence and readAllWithHeaderAsSequence methods can only be called within the open lambda block. The input stream is closed after the open lambda block.

Read line by line

If you want to handle line-by-line, you can do it by using open method. Use open method and then use readNext method inside nested block to read row.

csvReader().open("test.csv") {
    readNext()
}

Read in a Suspending Function

csvReader().openAsync("test.csv") {
    val container = mutalbeListOf<List<String>>()
    delay(100) //other suspending task
    readAllAsSequence().asFlow().collect { row ->
        delay(100) // other suspending task
        container.add(row)
    }
}

Note: openAsync can be and only be accessed through a coroutine or another suspending function

Customize

When you create CsvReader, you can choose read options:

// this is tsv reader's option
val tsvReader = csvReader {
    charset = "ISO_8859_1"
    quoteChar = '"'
    delimiter = '\t'
    escapeChar = '\\'
}
Opton default value description
charset UTF-8 Charset encoding. The value must be supported by java.nio.charset.Charset.
quoteChar " Character used to quote fields.
delimiter , Character used as delimiter between each field.
Use "\t" if reading TSV file.
escapeChar " Character to escape quote inside field string.
Normally, you don't have to change this option.
See detail comment on ICsvReaderContext.
skipEmptyLine false Whether to skip or error out on empty lines.
skipMissMatchedRow false Whether to skip an invalid row (different number of fields from other rows) or throw an exception.
autoRenameDuplicateHeaders false Whether to auto rename duplicate headers or throw an exception.

CSV Write examples

Simple case

You can start writing csv in one line, no need to do any I/O handling (No need to call use, close and flush method.):

val rows = listOf(listOf("a", "b", "c"), listOf("d", "e", "f"))
csvWriter().writeAll(rows, "test.csv")

// if you'd append data on the tail of the file, assign `append = true`.
csvWriter().writeAll(rows, "test.csv", append = true)

// You can also write into OutpusStream.
csvWriter().writeAll(rows, File("test.csv").outputStream())

You can also write a csv file line by line by open method:

val row1 = listOf("a", "b", "c")
val row2 = listOf("d", "e", "f")

csvWriter().open("test.csv") {
    writeRow(row1)
    writeRow(row2)
    writeRow("g", "h", "i")
    writeRows(listOf(row1, row2))
}

Write in a Suspending Function

val rows = listOf(listOf("a", "b", "c"), listOf("d", "e", "f")).asSequence()
csvWriter().openAsync(testFileName) {
    delay(100) //other suspending task
    rows.asFlow().collect {
        delay(100) // other suspending task
        writeRow(it)
    }
}

long-running write (manual control for file close)

If you want to close a file writer manually for performance reasons (e.g. streaming scenario), you can use openAndGetRawWriter and get a raw CsvFileWriter.
DO NOT forget to close the writer!

val row1 = listOf("a", "b", "c")

@OptIn(KotlinCsvExperimental::class)
val writer = csvWriter().openAndGetRawWriter("test.csv")
writer.writeRow(row1)
writer.close()

Customize

When you create a CsvWriter, you can choose write options.

val writer = csvWriter {
    charset = "ISO_8859_1"
    delimiter = '\t'
    nullCode = "NULL"
    lineTerminator = "\n"
    outputLastLineTerminator = true
    quote {
        mode = WriteQuoteMode.ALL
        char = '\''
    }
}
Option default value description
charset UTF-8 Charset encoding. The value must be supported by java.nio.charset.Charset.
delimiter , Character used as delimiter between each fields.
Use "\t" if reading TSV file.
nullCode (empty string) Character used when a written field is null value.
lineTerminator \r\n Character used as line terminator.
outputLastLineTerminator true Output line break at the end of file or not.
quote.char " Character to quote each fields.
quote.mode CANONICAL Quote mode.
- CANONICAL: Not quote normally, but quote special characters (quoteChar, delimiter, line feed). This is the specification of CSV.
- ALL: Quote all fields.
- NON_NUMERIC: Quote non-numeric fields. (ex. 1,"a",2.3)

Links

Documents

Libraries which use kotlin-csv

Miscellaneous

๐Ÿค Contributing

Contributions, issues and feature requests are welcome! If you have questions, ask away in Kotlin Slack's kotlin-csv room.

๐Ÿ’ป Development

git clone [email protected]:doyaaaaaken/kotlin-csv.git
cd kotlin-csv
./gradlew check

Show your support

Give a โญ๏ธ if this project helped you!

๐Ÿ“ License

Copyright ยฉ 2019 doyaaaaaken.
This project is licensed under Apache 2.0.


This project is inspired โค๏ธ by scala-csv

This README was generated with โค๏ธ by readme-md-generator

Comments
  • Remove logger 3rd party library

    Remove logger 3rd party library

    Quickly looking at the code it seems like there's only one log statement:

    https://github.com/doyaaaaaken/kotlin-csv/blob/8108e5bcc24d55d813868ca3a238aed59a16b628/src/commonMain/kotlin/com/github/doyaaaaaken/kotlincsv/client/CsvFileReader.kt#L48

    Do we really need to pull an entire library for logging?

    https://github.com/doyaaaaaken/kotlin-csv/blob/ed7a6783313b3d033f3ffe702227b7a3961bc72b/build.gradle.kts#L50

    I'm an Android user and currently that log would go basically nowhere.

    good first issue code quality 
    opened by vanniktech 8
  • Improvement: Read one row at a time

    Improvement: Read one row at a time

    Currently the only way to interact with a CSV is to parse all rows. Two use-cases that this does not cover are:

    • Reading only the header. This is useful if you wish to provide a breakdown of what is included in the file. While it should be trivial to do without a library, the existence of this library and its parsing logic supports the position that this is a non-trivial task.
    • Reading row-by-row, which is arguably a superset of the former use-case. This would be helpful when interacting with asynchronous workflows. One could attempt to read a single row from a piped input stream, and the library throws an exception when another line cannot be read in its entirety (as it does now with the full text). The producer can then continue to populate the input stream as data becomes available. The end result would be an asynchronous stream of rows (which I am not suggesting should be included in this library, but these changes would make this possible).
    question 
    opened by jnfeinstein 8
  • CsvFileReader#readAllAsSequence fails on non-equal sized rows

    CsvFileReader#readAllAsSequence fails on non-equal sized rows

    Describe the bug If rows are not equal-sized an exception is thrown: com.github.doyaaaaaken.kotlincsv.util.CSVFieldNumDifferentException: Fields num seems to be 4 on each row, but on 2th csv row, fields num is 3.

    To Reproduce

            csvWriter().open(csvFile) {
                writeRow(listOf("a"))
                writeRow(listOf("a", "b"))
            }
            csvReader().open(csvFile) {
               readAllAsSequence()
            }
    

    Expected behavior Missing cells are treated as nulls or empty strings.

    Environment

    • kotlin-csv version 0.11.0
    • OS: Android 10

    Screenshots N/A

    question 
    opened by koral-- 8
  • Long-running write

    Long-running write

    Please allow writing to csv file without having to close it. I have a streaming scenario where I need to write each data I get to csv. Closing and reopening after each batch would be suboptimal.

    Thanks David

    enhancement help wanted good first issue 
    opened by davidohana 7
  • java.lang.NoClassDefFoundError: mu/KotlinLogging

    java.lang.NoClassDefFoundError: mu/KotlinLogging

    Describe the problem

    It quite not a bug, but I'm stuck on this exception:

    Caused by: java.lang.NoClassDefFoundError: mu/KotlinLogging
    	at com.github.doyaaaaaken.kotlincsv.client.CsvFileReader.<init>(CsvFileReader.kt:21)
    	at com.github.doyaaaaaken.kotlincsv.client.CsvReader.open(CsvReader.kt:129)
    	at com.github.doyaaaaaken.kotlincsv.client.CsvReader.readAll(CsvReader.kt:48)
    

    It happens only on Ubuntu. MacOS is still fine.

    Environment

    • kotlin-csv version: 0.11.0
    • java version: java8
    • kotlin version: 1.4.10
    • OS: Ubuntu 18.04.5

    Any suggestion on this? Thank you!

    bug 
    opened by ltpquang 6
  • Added writing a row from variable number of arguments

    Added writing a row from variable number of arguments

    I think to be able to write a variable number of arguments is nice also without creating a list before hand.

    example:

    csvWriter().open(testFileName) {
        writeRow("a", "b", "c")
        writeRow("d", "e", "f")
        writeRow(1,2,3)
        writeRow(date1, date2, date3)
    }
    

    Although Kotlin already supports a variable argument in instantiating a list with initial values, I think this one will be cleaner and less boiler plate on the user end.

    opened by blackmo18 6
  • Parser unable to parse csv file with lower row quantity compare with header

    Parser unable to parse csv file with lower row quantity compare with header

    Describe the bug Some csv editors after creating new fields add only touched fields for example some csv editors on mac don't add extra empty fields:

    For example we have csv file: name,age,gender,hobby Steve,19,male,sport

    I'm will open this file and add one more user, but with empty gender, and hobby, in out business logic it's allowed. name,age,gender,hobby Steve,19,male,sport Emma,20

    editor will save latest record without extra empty fields, and parser with throw error something like Fields num seems to be 4 on each row, but on 3th csv row, fields num is 2.

    according configuration i'm can ignore or throw error in such case, but it's valid situation and. I'm need save this record.

    To Reproduce Steps to reproduce the behavior.

    val record = mutableListOf<List>() csvReader { charset = "UTF-8" quoteChar = '"' delimiter = separator }.open(file) { readAllAsSequence().forEach { record.add(it) } }

    1. export file: name,age,gender,hobby Steve,19,male,sport

    2. add one more user, and try to read this file name,age,gender,hobby Steve,19,male,sport Emma,20

    Actual behavior Fields num seems to be 4 on each row, but on 3th csv row, fields num is 2.

    Expected behavior Reading file successful empty fields getting considered as empty one.

    P.S. Will be good to add to class InsufficientFieldsRowBehaviour enum: IGNORE_MISSING_FIELDS and handle it, like it some fields are missing just consider them as empty one.

    Environment

    • kotlin-csv version [e.g. 0.10.0]
    • java version [e.g. java8]
    • OS: [e.g. MacOS]

    Screenshots If applicable, add screenshots to help explain your problem.

    bug 
    opened by EugeneLDT 5
  • Problem with parsing CSV file with spaces and colon

    Problem with parsing CSV file with spaces and colon

    Good morning,

    I'm trying to use kotlin-csv on a comma delimited file (input stream) but I think there is a problem with managing the spaces and colon.

    In particular, these are the first lines of the file:

    Device serial,Date ,Temperature 51 (Medium) ยฐC 11869,2021-02-09 00:14:59,7.2 11869,2021-02-09 00:30:01,7.1 11869,2021-02-09 00:44:59,7.2 11869,2021-02-09 00:59:59,7.4 11869,2021-02-09 01:14:58,7.5 11869,2021-02-09 01:29:58,7.5 11869,2021-02-09 01:44:58,7.3 11869,2021-02-09 01:59:58,7.2 11869,2021-02-09 02:14:58,7.2 11869,2021-02-09 02:29:58,7.2 11869,2021-02-09 02:44:58,7.2 11869,2021-02-09 02:59:57,7.3 11869,2021-02-09 03:14:57,7.2 11869,2021-02-09 03:29:57,7.3 11869,2021-02-09 03:44:57,7.2 11869,2021-02-09 03:59:57,7.4

    ..while this is the script:

    data class DataClass( val FirstColumn: String, val SecondColumn: String, val ThirdColumn: String )

    fun parse(data:InputStream): List?{

     val list = mutableListOf<DataClass>()
    
     try {
        val rows: List<List<String>> = csvReader().readAll(data)
    
        for (i in rows) {
    
     var firstColumn : String =  i[0]
     var secondColumn : String =  i[1]
     var thirdColumn : String =  i[2]
    
     list.add(DataClass(FirstColumn =firstColumn, SecondColumn = secondColumn,  ThirdColumn = thirdColumn))
        }
    

    } catch (e: Exception) { e.printStackTrace() } return list }

    Unfortunately only the first column of each row is correctly identified in the output, for example (first row): first column: 11869 second column: 2021-02-09 third colum: 0 No other colums detected.

    Where is my mistake? Thank you

    under discussion 
    opened by Phalaen 5
  • Optimize writeNext Method

    Optimize writeNext Method

    Current writeNext function have unnecessary map method. It cause unnecessary memory usage.

      private fun writeNext(row: List<Any?>) {
          val rowStr = row.map { field ->
              if (field == null) {
                  ctx.nullCode
              } else {
                  attachQuote(field.toString())
              }
          }.joinToString(ctx.delimiter.toString())
          writer.print(rowStr)
      }
    

    Performance test

    image

    Result : Java Heap Space out error


    Remove unnecessary map method.

      private fun writeNext(row: List<Any?>) {
          val rowStr = row.joinToString(ctx.delimiter.toString()) { field ->
              if (field == null) {
                  ctx.nullCode
              } else {
                  attachQuote(field.toString())
              }
          }
          writer.print(rowStr)
      }
    

    Performance test

    image

    The test code was excluded for fear of slow execution for test. If you want to measure performance test, the performance test must be isolate alone. Because of, All tests execute independently and pararell then they use some memory. So, it might be on unexpected result


    TEST CODE

    "does not throw java heap space exception when execute writeRows" {
        val rows = mutableListOf<String>()
    
        for (i in 0..100000000) {
            rows.add(i.toString())
        }
    
        val sequence = listOf<List<String>>(rows).asSequence()
    
        assertDoesNotThrow {
            csvWriter().open(testFileName) {
                writeRows(sequence)
            }
        }
    }
    
    opened by tmdgusya 3
  • number of fields in a row has to be based on the header

    number of fields in a row has to be based on the header

    To reproduce

    Have a csv file with header row with 3 columns and two data rows, first data row with two columns, second - with three. Like this:

    First name | Last name | Citizenship
    --------|----|---- John | Bobkins Michael| Pepkins| US

    While invoking 'readAllWithHeaderAsSequence' on this file, the CSVFieldNumDifferentException is thrown saying that two colums are expected but three are found. It happens because 'fieldsNum' variable in the CsvFileReader.kt is initialized based on the first data row, while it has to be initialized based on the header row.

    Expected behavior The following code has to return two rows:

    csvReader().open(filePath) {
                    readAllWithHeaderAsSequence().forEach {
    
    . . . 
    }
    

    Environment

    • kotlin-csv version 0.11.1
    • java version - java8
    • OS: Windows 10
    bug 
    opened by mykhaylo- 3
  • In parser, use StringBuilder.clear() instead of...

    In parser, use StringBuilder.clear() instead of...

    ...allocating new StringBuilder

    This reuses the StringBuilder's internal buffer rather than reallocating for each field. On my local benchmark this improves performance of reading 48MB file by about 20%.

    opened by jomof 3
  • Introduce `insufficientFieldsRowBehaviour =

    Introduce `insufficientFieldsRowBehaviour = "EMPTY_STRING"` option on CSV reader

    As discussed in #111 , to Introduce InsufficientFieldsRowBehaviour.EMPTY_STRING option on CSV reader seems good. This option treat field's value as empty String when the row has insufficient number of fields.

    For example, If you read the below csv,

    header1,header2,header3
    a,b,c
    x,y
    

    you could get this.

    listOf(
      listOf("header1", "header2", "header3"),
      listOf("a", "b", "c"),
      listOf("x", "y", ""),  // empty String value added on the end
    )
    
    help wanted good first issue feature request 
    opened by doyaaaaaken 0
  • Keep input stream open

    Keep input stream open

    I realize that generally it doesn't make sense to keep an input stream open when the end of the stream has been reached, but I'd like to read multiple CSV files that are inside a zip file (without extracting them first). However, that's currently not possible since the input stream gets closed when the end of the current zip entry is reached.

    good first issue feature request 
    opened by oliverClimbs 2
  • Make CsvFileReader.readNext() private

    Make CsvFileReader.readNext() private

    Problem

    If we use readNext method, some options (e.g. excessFieldsRowBehaviour option) are bypassed and invalid.

    There does not appear to be a use case for this method, so we are considering making it a private method. If you have feedback, please comment.

    under discussion 
    opened by doyaaaaaken 4
  • Introduce BOM for Microsoft applications

    Introduce BOM for Microsoft applications

    Hey there,

    thank you very much for this gerat project.

    Microsoft applications, for some reason, seem to require a BOM to parse for example UTF-8 files correctly, even though there is no byte order in UTF-8 like there is in 16/32. In order to open a created csv file correctly I suggest to add this special BOM (UTF-8 does require three special bytes 0xEF, 0xBB and 0xBF at the start of the file), even though the csvWriter is configured with the Charsets.UTF_8.name().

    Why this is undocumented and why Excel seems to require a BOM for UTF-8 I don't know; might be good questions for Excel team at Microsoft.

    What do you think or do you have any suggestion to solve this problem?

    help wanted good first issue 
    opened by theexiile1305 9
  • Feature request: Differentiate between empty string and null value

    Feature request: Differentiate between empty string and null value

    readAllWithHeader yields a List<Map<String,String>> and hence empty columns are being read as empty strings, so that we get "" for both col1 and col2 in the following example:

    "col1","col2"
    "",
    

    I'd really like to get null for col2 here (this of course only makes sense if all strings are quoted, otherwise it wouldn't be clear how to interpret empty columns). I understand that you can't change the result to List<Map<String,String?>> now, but maybe you could add a nullCode option for reading as it already exists for writing. The default value is an empty string "" (=current behavior). I could then simply do

    val nullCode = "NULL"
    val rows = csvReader(nullCode=nullCode).readAllWithHeader(inputStream)
        .map { row -> row.mapValues { col -> if (col.value == nullCode) null else col.value } }
    

    At first glance it seems that it only requires to change https://github.com/doyaaaaaken/kotlin-csv/blob/c23a51b98fbbcb1348b3928d561f1f5e11fba965/src/commonMain/kotlin/com/github/doyaaaaaken/kotlincsv/parser/ParseStateMachine.kt#L36-L48 to

                        delimiter -> {
                            field.append(nullCode)
                            flushField()
                            state = ParseState.DELIMITER
                        }
                        '\n', '\u2028', '\u2029', '\u0085' -> {
                            field.append(nullCode)
                            flushField()
                            state = ParseState.END
                        }
                        '\r' -> {
                            if (nextCh == '\n') pos += 1
                            field.append(nullCode)
                            flushField()
                            state = ParseState.END
                        }
    

    and the same for https://github.com/doyaaaaaken/kotlin-csv/blob/c23a51b98fbbcb1348b3928d561f1f5e11fba965/src/commonMain/kotlin/com/github/doyaaaaaken/kotlincsv/parser/ParseStateMachine.kt#L87-L99

    but I didn't check it thoroughly.

    enhancement feature request 
    opened by StefRe 4
Releases(1.7.0)
Owner
kenta.koyama
Full stack developer. Write Kotlin, Scala, Vue.js, Typescript. CTO at Smartround Inc.
kenta.koyama
A pure Kotlin/Multiplatform implementation of group operations on Curve25519.

curve25519-kotlin A pure Kotlin/Multiplatform implementation of group operations on Curve25519. Gradle Kotlin DSL: dependencies { implementation("

Andrey Pfau 9 Dec 22, 2022
Template (pure) for KMM application with DI support

KMM di template Template (pure) for KMM application with DI support. Uses Multiplatform-DI for Dependency Injection Features Common architecture (VIP)

Anna Zharkova 8 Oct 18, 2022
Android News Reader app. Kotlin Coroutines, Retrofit and Realm

News Reader Android News Reader app Code that follows Packt Publishing Kotlin in Practice Video Course Example of Kotlin Coroutine usage, with Realm a

Marko Devcic 22 Oct 3, 2022
KMM RSS Reader: an open-source, mobile, cross-platform application built with Kotlin Multiplatform Mobile.

KMM RSS Reader This is an open-source, mobile, cross-platform application built with Kotlin Multiplatform Mobile. It's a simple RSS reader, and you ca

Kotlin 1.4k Jan 4, 2023
A libre smart powered comic book reader for Android.

Seeneva A libre smart powered comic book reader for Android. Translation: ะ ัƒััะบะธะน โ€ข โ€ข Features โ€ข Speech balloons zooming โ€ข OCR and TTS โ€ข Performance โ€ข

Seeneva comic book reader 130 Jan 7, 2023
Run Kotlin/JS libraries in Kotlin/JVM and Kotlin/Native programs

Zipline This library streamlines using Kotlin/JS libraries from Kotlin/JVM and Kotlin/Native programs. It makes it possible to do continuous deploymen

Cash App 1.5k Dec 30, 2022
A somewhat copy past of Jetbrain's code from the kotlin plugin repo to make it humanly possible to test Intellij IDEA kotlin plugins that work on kotlin

A somewhat copy past of Jetbrain's code from the kotlin plugin repo to make it humanly possible to test Intellij IDEA kotlin plugins that work on kotlin

common sense OSS 0 Jan 20, 2022
Real life Kotlin Multiplatform project with an iOS application developed in Swift with SwiftUI, an Android application developed in Kotlin with Jetpack Compose and a backed in Kotlin hosted on AppEngine.

Conferences4Hall Real life Kotlin Multiplatform project with an iOS application developed in Swift with SwiftUI, an Android application developed in K

Gรฉrard Paligot 98 Dec 15, 2022
Android + Kotlin + Github Actions + ktlint + Detekt + Gradle Kotlin DSL + buildSrc = โค๏ธ

kotlin-android-template ?? A simple Github template that lets you create an Android/Kotlin project and be up and running in a few seconds. This templa

Nicola Corti 1.5k Jan 3, 2023
LifecycleMvp 1.2 0.0 Kotlin is MVP architecture implementation with Android Architecture Components and Kotlin language features

MinSDK 14+ Download Gradle Add to project level build.gradle allprojects { repositories { ... maven { url 'https://jitpack.io' }

Robert 20 Nov 9, 2021
Opinionated Redux-like implementation backed by Kotlin Coroutines and Kotlin Multiplatform Mobile

CoRed CoRed is Redux-like implementation that maintains the benefits of Redux's core idea without the boilerplate. No more action types, action creato

Kittinun Vantasin 28 Dec 10, 2022
๐Ÿ‘‹ A common toolkit (utils) โš’๏ธ built to help you further reduce Kotlin boilerplate code and improve development efficiency. Do you think 'kotlin-stdlib' or 'android-ktx' is not sweet enough? You need this! ๐Ÿญ

Toolkit [ ?? Work in progress โ› ?? ??๏ธ ?? ] Snapshot version: repositories { maven("https://s01.oss.sonatype.org/content/repositories/snapshots") }

ๅ‡› 35 Jul 23, 2022
An app architecture for Kotlin/Native on Android/iOS. Use Kotlin Multiplatform Mobile.

An app architecture for Kotlin/Native on Android/iOS. Use Kotlin Multiplatform Mobile. ้กน็›ฎๆžถๆž„ไธป่ฆๅˆ†ไธบๅŽŸ็”Ÿ็ณป็ปŸๅฑ‚ใ€Android/iOSไธšๅŠกSDKๅฑ‚ใ€KMM SDKๅฑ‚ใ€KMMไธšๅŠก้€ป่พ‘SDKๅฑ‚ใ€iOS sdkfra

libill 4 Nov 20, 2022
Provides Kotlin libs and some features for building Kotlin plugins

Kotlin Plugin Provides Kotlin libs and some features for building awesome Kotlin plugins. Can be used instead of CreeperFace's KotlinLib (don't use to

null 3 Dec 24, 2021
Notes-App-Kotlin - Notes App Built Using Kotlin

Notes-App-Kotlin Splash Screen Home Page Adding New Notes Filter Feature Search

Priyanka 4 Oct 2, 2022
Kotlin-client-dsl - A kotlin-based dsl project for a (Client) -> (Plugin) styled program

kotlin-client-dsl a kotlin-based dsl project for a (Client) -> (Plugin) styled p

jackson 3 Dec 10, 2022
A Kotlin Native program to show the time since a date, using Kotlin LibUI

TimeSince A Kotlin Native program to show the time since a date, using Kotlin LibUI Report Bug . Request Feature About The Project TimeSince is a Kotl

Russell Banks 2 May 6, 2022
RoomJetpackCompose is an app written in Kotlin and shows a simple solution to perform CRUD operations in the Room database using Kotlin Flow in clean architecture.

RoomJetpackCompose is an app written in Kotlin and shows a simple solution to perform CRUD operations in the Room database using Kotlin Flow in clean architecture.

Alex 27 Jan 1, 2023
Create an application with Kotlin/JVM and Kotlin/JS, and explore features around code sharing, serialization, server- and client

Practical Kotlin Multiplatform on the Web ๋ณธ ์ €์žฅ์†Œ๋Š” ์ฝ”ํ‹€๋ฆฐ ๋ฉ€ํ‹ฐํ”Œ๋žซํผ ๊ธฐ๋ฐ˜ ์›น ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์›Œํฌ์ˆ(๊ฐ•์ขŒ)์„ ์œ„ํ•ด ์ž‘์„ฑ๋œ ํ…œํ”Œ๋ฆฟ ํ”„๋กœ์ ํŠธ๊ฐ€ ์žˆ๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค. ์›Œํฌ์ˆ ๊ณผ์ •์—์„œ ์ฝ”ํ‹€๋ฆฐ ๋ฉ€ํ‹ฐํ”Œ๋žซํผ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ”„๋ก ํŠธ์—”๋“œ(front-end)๋Š” Ko

SpringRunner 14 Nov 5, 2022