Implemented platform specific wrapper classes for BigDecimal, Date, File and UUID
This commit is contained in:
parent
2281d1758d
commit
1bef1904f9
|
@ -0,0 +1,21 @@
|
||||||
|
package net.dankito.utils.multiplatform
|
||||||
|
|
||||||
|
|
||||||
|
expect fun Collection<BigDecimal>.sum(): BigDecimal
|
||||||
|
|
||||||
|
|
||||||
|
expect class BigDecimal {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val Zero: BigDecimal
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
constructor(decimal: String)
|
||||||
|
|
||||||
|
constructor(double: Double)
|
||||||
|
|
||||||
|
|
||||||
|
fun format(pattern: String): String
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package net.dankito.utils.multiplatform
|
||||||
|
|
||||||
|
|
||||||
|
enum class DateFormatStyle {
|
||||||
|
|
||||||
|
Short,
|
||||||
|
|
||||||
|
Medium,
|
||||||
|
|
||||||
|
Long,
|
||||||
|
|
||||||
|
Full
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package net.dankito.utils.multiplatform
|
||||||
|
|
||||||
|
|
||||||
|
expect class UUID {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
fun random(): String
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,17 +1,18 @@
|
||||||
package net.dankito.utils.multiplatform.log
|
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) {
|
open class ConsoleLogger(name: String) : LoggerBase(name) {
|
||||||
|
|
||||||
companion object {
|
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) {
|
override fun log(level: LogLevel, message: String) {
|
||||||
println("${DateTime.nowLocal().toString(DateFormat)} $level $name - $message")
|
println("${DateFormatter.format(Date())} $level $name - $message")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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<BigDecimal>.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`)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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()
|
||||||
|
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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<BigDecimal>.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?
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package net.dankito.utils.multiplatform
|
||||||
|
|
||||||
|
|
||||||
|
fun java.util.Date.toDate(): Date {
|
||||||
|
return Date(this.time)
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue