Skip to content

Commit

Permalink
Support Decimal Type #2
Browse files Browse the repository at this point in the history
  • Loading branch information
Reed Es committed Apr 21, 2023
1 parent c6140c3 commit 0f4a4ea
Show file tree
Hide file tree
Showing 3 changed files with 417 additions and 18 deletions.
22 changes: 4 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ _SwiftNumberPad_ is part of the [OpenAlloc](https://github.com/openalloc) family

## Features

* Support for both integer and floating point types
* Support for integer, floating point, and Decimal types
* Presently targeting .macOS(.v13), .iOS(.v16), .watchOS(.v9)
* No external dependencies!

Expand Down Expand Up @@ -67,27 +67,13 @@ Please submit pull requests if you'd like to tackle any of these. Thanks!
* SwiftUI Preview not reliably working on macOS
* See if earlier versions of platforms can be supported
* Support for negative values
* Support for Decimal input

## See Also

* [SwiftSideways](https://github.com/openalloc/SwiftSideways) - multi-platform SwiftUI component for the horizontal scrolling of tabular data in compact areas
* [SwiftDetailer](https://github.com/openalloc/SwiftDetailer) - multi-platform SwiftUI component for editing fielded data
* [SwiftDetailerMenu](https://github.com/openalloc/SwiftDetailerMenu) - optional menu support for _SwiftDetailer_
* [SwiftCompactor](https://github.com/openalloc/SwiftCompactor) - formatters for the concise display of Numbers, Currency, and Time Intervals
* [SwiftModifiedDietz](https://github.com/openalloc/SwiftModifiedDietz) - A tool for calculating portfolio performance using the Modified Dietz method
* [SwiftNiceScale](https://github.com/openalloc/SwiftNiceScale) - generate 'nice' numbers for label ticks over a range, such as for y-axis on a chart
* [SwiftRegressor](https://github.com/openalloc/SwiftRegressor) - a linear regression tool that’s flexible and easy to use
* [SwiftSeriesResampler](https://github.com/openalloc/SwiftSeriesResampler) - transform a series of coordinate values into a new series with uniform intervals
* [SwiftSimpleTree](https://github.com/openalloc/SwiftSimpleTree) - a nested data structure that’s flexible and easy to use
This library is a member of the _OpenAlloc Project_.

And open source apps using this library (by the same author):

* [Gym Routine Tracker](https://open-trackers.github.io/grt/) - minimalist workout tracker, for the Apple Watch, iPhone, and iPad
* [Daily Calorie Tracker](https://open-trackers.github.io/dct/) - minimalist calorie tracker, for the Apple Watch, iPhone, and iPad

* [FlowAllocator](https://openalloc.github.io/FlowAllocator/index.html) - portfolio rebalancing tool for macOS
* [FlowWorth](https://openalloc.github.io/FlowWorth/index.html) - a new portfolio performance and valuation tracking tool for macOS
* [_OpenAlloc_](https://openalloc.github.io) - product website for all the _OpenAlloc_ apps and libraries
* [_OpenAlloc Project_](https://github.com/openalloc) - Github site for the development project, including full source code

## License

Expand Down
89 changes: 89 additions & 0 deletions Sources/NPDecimalConfig.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//
// NPDecimalConfig.swift
//
// Copyright 2023 OpenAlloc LLC
//
// 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.
//

import Foundation


public final class NPDecimalConfig: NPBaseConfig<Decimal>
{
// MARK: - Parameters

public let precision: Int

public init(_ val: Decimal,
precision: Int = NumberPadEnum.defaultPrecision,
upperBound: Decimal = Decimal.greatestFiniteMagnitude)
{
self.precision = precision

let formatter = {
let nf = NumberFormatter()
nf.locale = Locale.current
nf.numberStyle = .decimal
nf.usesGroupingSeparator = false
nf.isLenient = true
nf.minimumFractionDigits = 0
nf.maximumFractionDigits = precision
nf.generatesDecimalNumbers = true
return nf
}()

let sVal = Self.toString(val, upperBound: upperBound, formatter: formatter)

super.init(sValue: sVal, upperBound: upperBound, formatter: formatter)
}

// MARK: - Type-specific Actions

override public var showDecimalPoint: Bool { precision > 0 }

override public func decimalPointAction() -> Bool {
guard decimalPointIndex == nil else { return false }
sValue.append(".")

return true
}

// MARK: - Internal

internal static func toString(_ val: Decimal, upperBound: Decimal, formatter: NumberFormatter) -> String {
let clampedValue = max(0, min(val, upperBound))
return formatter.string(from: clampedValue as NSDecimalNumber) ?? "0"
}

override internal func validateDigit(_: NumberPadEnum) -> Bool {
let cp = currentPrecision
if cp > 0, cp == precision { return false } // ignore additional input
return true
}

override internal func toValue(_ str: String) -> Decimal? {
guard let val: NSNumber = formatter.number(from: str)
else { return nil }
return Decimal(val.doubleValue)
}

internal var currentPrecision: Int {
guard let di = decimalPointIndex else { return 0 }
return sValue.distance(from: di, to: sValue.endIndex) - 1
}

internal var decimalPointIndex: String.Index? {
sValue.firstIndex(of: ".")
}
}
Loading

0 comments on commit 0f4a4ea

Please sign in to comment.