diff --git a/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/BigDecimal.kt b/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/BigDecimal.kt new file mode 100644 index 00000000..6e7432ad --- /dev/null +++ b/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/BigDecimal.kt @@ -0,0 +1,21 @@ +package net.dankito.utils.multiplatform + + +expect fun Collection.sum(): BigDecimal + + +expect class BigDecimal { + + companion object { + val Zero: BigDecimal + } + + + constructor(decimal: String) + + constructor(double: Double) + + + fun format(pattern: String): String + +} \ No newline at end of file diff --git a/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/Date.kt b/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/Date.kt new file mode 100644 index 00000000..c2977776 --- /dev/null +++ b/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/Date.kt @@ -0,0 +1,20 @@ +package net.dankito.utils.multiplatform + + +fun Date.format(format: DateFormatter): String { + return format.format(this) +} + +fun Date.format(pattern: String): String { + return this.format(DateFormatter(pattern)) +} + + +expect class Date(millisSinceEpoch: Long) { + + constructor() + + + val millisSinceEpoch: Long + +} \ No newline at end of file diff --git a/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/DateFormatStyle.kt b/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/DateFormatStyle.kt new file mode 100644 index 00000000..cdc20e94 --- /dev/null +++ b/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/DateFormatStyle.kt @@ -0,0 +1,14 @@ +package net.dankito.utils.multiplatform + + +enum class DateFormatStyle { + + Short, + + Medium, + + Long, + + Full + +} \ No newline at end of file diff --git a/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/DateFormatter.kt b/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/DateFormatter.kt new file mode 100644 index 00000000..48f23686 --- /dev/null +++ b/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/DateFormatter.kt @@ -0,0 +1,13 @@ +package net.dankito.utils.multiplatform + + +expect class DateFormatter constructor(pattern: String) { + + constructor(dateStyle: DateFormatStyle) + + constructor(dateStyle: DateFormatStyle, timeStyle: DateFormatStyle) + + + fun format(date: Date): String + +} \ No newline at end of file diff --git a/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/File.kt b/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/File.kt new file mode 100644 index 00000000..02a302e4 --- /dev/null +++ b/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/File.kt @@ -0,0 +1,19 @@ +package net.dankito.utils.multiplatform + + +expect class File(path: String) { + + constructor(folder: File, filename: String) + + + // have to specify it as method as property would conflict with java.io.File's getAbsolutePath + fun getAbsolutePath(): String + + val filename: String + + val fileExtension: String + + + fun mkdirs(): Boolean + +} \ No newline at end of file diff --git a/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/UUID.kt b/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/UUID.kt new file mode 100644 index 00000000..8b77b083 --- /dev/null +++ b/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/UUID.kt @@ -0,0 +1,12 @@ +package net.dankito.utils.multiplatform + + +expect class UUID { + + companion object { + + fun random(): String + + } + +} \ No newline at end of file diff --git a/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/log/ConsoleLogger.kt b/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/log/ConsoleLogger.kt index 654242fd..fc6b9997 100644 --- a/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/log/ConsoleLogger.kt +++ b/common/src/commonMain/kotlin/net/dankito/utils/multiplatform/log/ConsoleLogger.kt @@ -1,17 +1,18 @@ package net.dankito.utils.multiplatform.log -import com.soywiz.klock.DateTime +import net.dankito.utils.multiplatform.Date +import net.dankito.utils.multiplatform.DateFormatter open class ConsoleLogger(name: String) : LoggerBase(name) { companion object { - private val DateFormat = com.soywiz.klock.DateFormat.invoke("HH:mm:ss.SSS") + private val DateFormatter = DateFormatter("HH:mm:ss.SSS") } override fun log(level: LogLevel, message: String) { - println("${DateTime.nowLocal().toString(DateFormat)} $level $name - $message") + println("${DateFormatter.format(Date())} $level $name - $message") } } \ No newline at end of file diff --git a/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/BigDecimal.kt b/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/BigDecimal.kt new file mode 100644 index 00000000..b33f34d8 --- /dev/null +++ b/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/BigDecimal.kt @@ -0,0 +1,51 @@ +package net.dankito.utils.multiplatform + +import platform.Foundation.NSCoder +import platform.Foundation.NSDecimalNumber +import platform.Foundation.NSNumberFormatter +import platform.Foundation.NSOrderedSame + + +fun NSDecimalNumber.toBigDecimal(): BigDecimal { + return BigDecimal(this.stringValue) // TODO: find a better way than double string conversion +} + +actual fun Collection.sum(): BigDecimal { + return this.fold(NSDecimalNumber.zero) { acc, e -> acc.decimalNumberByAdding(e) }.toBigDecimal() +} + + +actual class BigDecimal actual constructor(decimal: String) : NSDecimalNumber(NSCoder()) { + + actual companion object { + actual val Zero = BigDecimal("0") // TODO: is this correct? + } + + + actual constructor(double: Double) : this(NSDecimalNumber(double).stringValue) + + + init { + super.decimalNumberByAdding(NSDecimalNumber(decimal)) + } + + + actual fun format(pattern: String): String { + val formatter = NSNumberFormatter() + + formatter.positiveFormat = pattern + formatter.negativeFormat = pattern + + return formatter.stringFromNumber(this) ?: "" + } + + + override fun isEqual(`object`: Any?): Boolean { + if (`object` is BigDecimal) { + return this.compare(`object`) == NSOrderedSame + } + + return super.equals(`object`) + } + +} \ No newline at end of file diff --git a/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/Date.kt b/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/Date.kt new file mode 100644 index 00000000..41810fd9 --- /dev/null +++ b/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/Date.kt @@ -0,0 +1,25 @@ +package net.dankito.utils.multiplatform + +import platform.Foundation.* + + +fun NSTimeInterval.toMillis(): Long { + return this.toLong() * 1000 +} + + +actual class Date actual constructor(millisSinceEpoch: Long) + : NSDate(timeIntervalSinceReferenceDate = ((millisSinceEpoch - DiffBetweenEpochTimeAndReferenceDate) / 1000).toDouble()) { // TODO: does this work? + + companion object { + val DiffBetweenEpochTimeAndReferenceDate = (NSDate.timeIntervalSinceReferenceDate - NSTimeIntervalSince1970).toMillis() + } + + + actual constructor() : this(NSDate().timeIntervalSince1970.toMillis()) + + + actual val millisSinceEpoch: Long + get() = timeIntervalSince1970.toMillis() + +} \ No newline at end of file diff --git a/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/DateFormatter.kt b/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/DateFormatter.kt new file mode 100644 index 00000000..251431f9 --- /dev/null +++ b/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/DateFormatter.kt @@ -0,0 +1,40 @@ +package net.dankito.utils.multiplatform + +import platform.Foundation.* + + +fun DateFormatStyle.convert(): ULong { + return when (this) { + DateFormatStyle.Short -> NSDateFormatterShortStyle + DateFormatStyle.Medium -> NSDateFormatterMediumStyle + DateFormatStyle.Long -> NSDateFormatterLongStyle + DateFormatStyle.Full -> NSDateFormatterFullStyle + } +} + + + +actual class DateFormatter actual constructor(val pattern: String): NSDateFormatter() { + + actual constructor(dateStyle: DateFormatStyle) : this(NSDateFormatter().apply { + this.dateStyle = dateStyle.convert() + }.dateFormat) // TODO: does this work? + + actual constructor(dateStyle: DateFormatStyle, timeStyle: DateFormatStyle) : this(NSDateFormatter().apply { + this.dateStyle = dateStyle.convert() + this.timeStyle = timeStyle.convert() + }.dateFormat) // TODO: does this work? + + + init { + this.dateFormat = pattern + + this.timeZone = NSTimeZone.localTimeZone // TODO: needed? + } + + + actual fun format(date: Date): String { + return stringFromDate(date) + } + +} \ No newline at end of file diff --git a/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/File.kt b/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/File.kt new file mode 100644 index 00000000..4c9c8b43 --- /dev/null +++ b/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/File.kt @@ -0,0 +1,29 @@ +package net.dankito.utils.multiplatform + +import platform.Foundation.NSFileManager +import platform.Foundation.NSURL +import platform.Foundation.lastPathComponent + + +actual class File actual constructor(path: String) : NSURL(fileURLWithPath = path) { + + actual constructor(folder: File, filename: String) + : this(NSURL(string = filename, relativeToURL = folder).absoluteString ?: "") // TODO: or use 'fileURLWithPath'? + + + actual fun getAbsolutePath(): String { + return absoluteString ?: absoluteURL?.absoluteString ?: path ?: "" + } + + actual val filename: String + get() = lastPathComponent ?: "" + + actual val fileExtension: String + get() = filename.substringAfterLast('.', "") + + + actual fun mkdirs(): Boolean { + return NSFileManager.defaultManager.createDirectoryAtURL(this, true, null, null) + } + +} \ No newline at end of file diff --git a/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/UUID.kt b/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/UUID.kt new file mode 100644 index 00000000..0f46238e --- /dev/null +++ b/common/src/iosMain/kotlin/net/dankito/utils/multiplatform/UUID.kt @@ -0,0 +1,16 @@ +package net.dankito.utils.multiplatform + +import platform.Foundation.NSUUID + + +actual class UUID { + + actual companion object { + + actual fun random(): String { + return NSUUID().UUIDString + } + + } + +} \ No newline at end of file diff --git a/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/BigDecimal.kt b/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/BigDecimal.kt new file mode 100644 index 00000000..b4468d4e --- /dev/null +++ b/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/BigDecimal.kt @@ -0,0 +1,54 @@ +package net.dankito.utils.multiplatform + + +fun java.math.BigDecimal.toBigDecimal(): BigDecimal { + return BigDecimal(this.toPlainString()) // TODO: find a better way than double string conversion +} + +actual fun Collection.sum(): BigDecimal { + return this.fold(java.math.BigDecimal.ZERO) { acc, e -> (acc + e) }.toBigDecimal() +} + + +actual class BigDecimal actual constructor(decimal: String) : java.math.BigDecimal(decimal) { + + actual companion object { + actual val Zero = + BigDecimal("0") // TODO: is this correct? + } + + + internal constructor() : this("0") // for object deserializers + + actual constructor(double: Double) : this(java.math.BigDecimal.valueOf(double).toPlainString()) // for object deserializers + + + actual fun format(pattern: String): String { + return String.format(pattern, this) + } + + + override fun equals(other: Any?): Boolean { + if (other is BigDecimal) { + return this.compareTo(other) == 0 + } + + return super.equals(other) + } + + + /* TODO: where are these methods coming from? */ + + override fun toByte(): Byte { + return 0 // will never be called; where is this method coming from? + } + + override fun toChar(): Char { + return 0.toChar() // will never be called; where is this method coming from? + } + + override fun toShort(): Short { + return 0 // will never be called; where is this method coming from? + } + +} \ No newline at end of file diff --git a/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/Date.kt b/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/Date.kt new file mode 100644 index 00000000..09416b05 --- /dev/null +++ b/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/Date.kt @@ -0,0 +1,12 @@ +package net.dankito.utils.multiplatform + + +actual class Date actual constructor(millisSinceEpoch: Long) : java.util.Date(millisSinceEpoch) { + + actual constructor() : this(System.currentTimeMillis()) + + + actual val millisSinceEpoch: Long + get() = time + +} \ No newline at end of file diff --git a/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/DateFormatter.kt b/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/DateFormatter.kt new file mode 100644 index 00000000..0985663a --- /dev/null +++ b/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/DateFormatter.kt @@ -0,0 +1,30 @@ +package net.dankito.utils.multiplatform + +import java.text.DateFormat +import java.text.SimpleDateFormat + + +fun DateFormatStyle.convert(): Int { + return when (this) { + DateFormatStyle.Short -> DateFormat.SHORT + DateFormatStyle.Medium -> DateFormat.MEDIUM + DateFormatStyle.Long -> DateFormat.LONG + DateFormatStyle.Full -> DateFormat.FULL + } +} + + +actual class DateFormatter actual constructor(val pattern: String): SimpleDateFormat(pattern) { + + actual constructor(dateStyle: DateFormatStyle) + : this((DateFormat.getDateInstance(dateStyle.convert()) as? SimpleDateFormat)?.toPattern() ?: "") + + actual constructor(dateStyle: DateFormatStyle, timeStyle: DateFormatStyle) + : this((DateFormat.getDateTimeInstance(dateStyle.convert(), timeStyle.convert()) as? SimpleDateFormat)?.toPattern() ?: "") + + + actual fun format(date: Date): String { + return super.format(date) + } + +} \ No newline at end of file diff --git a/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/Extensions.kt b/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/Extensions.kt new file mode 100644 index 00000000..f1a30fbd --- /dev/null +++ b/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/Extensions.kt @@ -0,0 +1,6 @@ +package net.dankito.utils.multiplatform + + +fun java.util.Date.toDate(): Date { + return Date(this.time) +} \ No newline at end of file diff --git a/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/File.kt b/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/File.kt new file mode 100644 index 00000000..e6fd6b1f --- /dev/null +++ b/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/File.kt @@ -0,0 +1,35 @@ +package net.dankito.utils.multiplatform + +import java.io.File + + +fun File.toFile(): net.dankito.utils.multiplatform.File { + return net.dankito.utils.multiplatform.File(this.absolutePath) +} + + +actual class File actual constructor(path: String) : File(path) { + + actual constructor(folder: net.dankito.utils.multiplatform.File, filename: String) + : this(File(folder, filename).absolutePath) + + + internal constructor() : this("") // for object deserializers + + + actual override fun getAbsolutePath(): String { + return super.getAbsolutePath() + } + + actual val filename: String + get() = super.getName() + + actual val fileExtension: String + get() = this.extension + + + actual override fun mkdirs(): Boolean { + return super.mkdirs() + } + +} \ No newline at end of file diff --git a/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/UUID.kt b/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/UUID.kt new file mode 100644 index 00000000..9de050ae --- /dev/null +++ b/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/UUID.kt @@ -0,0 +1,16 @@ +package net.dankito.utils.multiplatform + +import java.util.UUID + + +actual class UUID { + + actual companion object { + + actual fun random(): String { + return UUID.randomUUID().toString() + } + + } + +} \ No newline at end of file diff --git a/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/log/DefaultLoggerFactory.kt b/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/log/DefaultLoggerFactory.kt new file mode 100644 index 00000000..a32e4901 --- /dev/null +++ b/common/src/jvmMain/kotlin/net/dankito/utils/multiplatform/log/DefaultLoggerFactory.kt @@ -0,0 +1,24 @@ +package net.dankito.utils.multiplatform.log + + +actual class DefaultLoggerFactory { + + actual fun createDefaultLoggerFactory(): ILoggerFactory { + if (isClassAvailable("org.slf4j.Logger")) { + return Slf4jLoggerFactory() + } + + return LogToConsoleLoggerFactory() + } + + private fun isClassAvailable(qualifiedClassName: String): Boolean { + try { + Class.forName(qualifiedClassName) + + return true + } catch (ignored: Exception) { } + + return false + } + +} \ No newline at end of file