Git Product home page Git Product logo

diffabletextviews's Introduction

GitHub Streak

diffabletextviews's People

Contributors

oscbyspro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

diffabletextviews's Issues

Locale/currency pair rhg-Rohg_MM/PAB crashes.

This is because the current implementation assumes that all formatting characters are unique, but in this case the localized currency expression contains a fraction separator.

func testVirtualCharactersAreNotAlwaysUnique() {
    let number = -1234567.89
    let currencyCode = "PAB"
    let locale = Locale(identifier: "rhg-Rohg_MM")
    let formatted = number.formatted(.currency(code: currencyCode).locale(locale))
    XCTAssertEqual(formatted, "-B/. 1,234,567.89") // currency contains fraction separator
}

Demo

A small demo app that makes it easy to preview and test each style's behavior.

Improve project's modularization.

The current structure cannot export text styles, as it would create cyclical dependencies. It is also ill suited for supporting additional platforms such as macOS, because DiffableTextViews becomes too crowded. A solution is to restructure the project as

Level 0: 
- DiffableTextKit

Level 1:
- NumericTextStyles
- PatternTextStyles
- DiffableTextViews_iOS
- DiffableTextViews_macOS

Level 2:
- DiffableTextViews [exports]

where the dependencies are Level 0 —> Level 1 —> Level 2 and the current DiffableTextViews target is split into two new targets: DiffableTextKit (models) and DiffableTextViews_iOS. A new DiffableTextViews then exports based on platform.

Improve NumericTextStyle’s public interface.

Type could be remade as:

NumericTextStyle<Double>
NumericTextStyle<Double>.Currency
NumericTextStyle<Double>.Percent

so that it looks similar to:

FloatingPointFormatStyle<Double>
FloatingPointFormatStyle<Double>.Currency
FloatingPointFormatStyle<Double>.Percent

Reduce import to a single statement.

While splitting the project into multiple modules keeps things organized

import DiffableTextViews

does effectively nothing. Instead, one must import it alongside a style

import DiffableTextViews
import NumericTextStyles
import PatternTextStyles

I think it would be worthwhile investigating the use of @_exported import.

Use ascii when parsing, maybe.

It should be possible, and many things seem to indicate that it works better.

Update 1: Actually, could probably use Value.init from String methods. Value to String is bad, but there should not be a problem converting Number to Value, since Number is ASCII-able by design. Have to think about it.

Update 2: Forgot, value.init will break the percent style due to asymmetry. That said, changing the locale to en_US or in another way using ASCII should work, and probably works better than using locales nobody knows about.

Add `measurement` styles.

I think it would be a neat addition, and it would not be too complicated to add. That said, I thought about it and decided against it. I’m unpaid and unemployed, and I have no need for it myself. Can’t eat kilometers.

Separator removal precedence.

If max value is “999” and the text is “99.”, changing the text to “999.” should remove the fraction separator. Instead, input is cancelled because “999” is the max value and cannot fit fraction digits.

DiffableTextStyle.

It can be reduced to two methods (plus localization)—one for upstream and one for downstream. All other requirements can be remade as style specific implementation details. I'll fix this first, then see how that affects the other issues.

FloatingPointFormatStyle.Percent is inaccurate for Float16 and Float32 values.

I'm not sure this is solvable on my end. Decimal and Double seem OK.

func testFloat16() {
    let value  = 1.23 as Float16
    let locale = Locale(identifier: "en_US")
    let result = FloatingPointFormatStyle<Float16>.Percent(locale: locale).format(value)
    XCTAssertEqual(result, "123.046875%")
}
func testFloat32() {
    let value  = 1.23 as Float32
    let locale = Locale(identifier: "en_US")
    let result = FloatingPointFormatStyle<Float32>.Percent(locale: locale).format(value)
    XCTAssertEqual(result, "123.000002%")
}

Glyph as struct? unsafeBitCast(glyphs, to: [UInt8].self)

On the topic of: https://www.swift.org/blog/utf8-string/

I’ve been playing around with converting wrapped UInt8 to String and the following seems to be the most performant by far (of what I have been able to come up with). This only works if each Glyph is a struct, however, because enums are zero-based and therefore mistranslated by unsafeBitCast(glyphs, to: [UInt8].self).

func testMakeStringUsingUnsafeBitCast() {
    measure {
        var accumulator: [UInt8] = []
        // capacity can be calculated O(1)
        accumulator.reserveCapacity(glyphs.count * 3)
        
        for _ in 0 ..< 3 {
            // appends 1_000_000 UTF8 characters
            accumulator.append(contentsOf: unsafeBitCast(glyphs, to: [UInt8].self))
        }

        let _ = String(bytes: accumulator, encoding: .utf8)!
    }
}

It would improve the performance of the number.characters() call in Lexicon.swift.

Label.currency(_:_:) is incorrect.

Label is broken, but because all cases where it fails are covered by other parts of the process it is not noticed. It's kinda funny, but at the same time it is bad and should be fixed.

SwiftUI toolbar does not appear above keyboard.

SwiftUI.TextField can add a toolbar above the keyboard as shown below.

view.toolbar {
    ToolbarItemGroup(placement: .keyboard) {
        Spacer()
        Button("Done") { /* action */ }
    }
}

This does not work on DiffableTextField, however. It should be fixed, if possible, otherwise an alternative should be offered.

Improve ProxyTextField’s public interface.

The current public facing methods get the job, but they are not uniform in their design.

proxy.key(return: .done)
proxy.keyboard(.alphabet)

As an example, the above methods look like they were designed with different ideas in mind.

proxy.color(tint: .blue)

And the above method changes the selection color. It's bad.

Cleanup.

NumericTextStyles & PatternTextStyles are messy. DiffableTextViews is kinda nice, tho.

Currency tests oddities.

for currency in currencies { for locale in locales { /* style.interpret */ } } // works
for locale in locales { for currency in currencies { /* style.interpret */ } } // crash

Rounding mode should be towards zero.

In response to changes upstream, fraction digits that exceed the maximum fraction digits length may round away from zero. This rarely matters, but sometimes the behavior may be unexpected. Assume

  • diffable text field is idle
  • value == 999.999
  • bounds == max
  • integer precision == 3
  • fraction precision == 2

so that when the user interacts with the view (editing changed counts as a change upstream) the following happens

  • bounds clamping rule applies: value == 999.999
  • the style formats the value (and implicitly rounds it up): number == "1,000"
  • precision rule applies: number is trimmed to "000" then converted: value == 0.

Locale/currency pair BG/USD crashes.

When the view is editing and the locale is set to "bg" Bulgarian and the currency is set to USD, the application crashes. This is because the currency code "щ.д." is interpreted as two dots, which is invalid, then the result is force unwrapped.

Thoughts 1: This is isolated to the “value -> number -> value” section in the commit(value:) method. One solution is therefore to always use the plain number format style in that section. No formatting asymmetry would be introduced with this solution.

Thoughts 2: It is not quite so simple, actually, because doing this results not in a crash but in a state where changes are invalid—also because of those two dots.

Rework: Region.

The locale/currency pair BG/USD should work as intended.

Maybe: use a strictly localized bidirectional map, then add a another map to localize ASCII inputs.

TODO: check if it is a valid assumption that localized currency codes (and symbols) always use characters that are disjoint from the set of characters used to format numbers. For example, none of the characters in "щ.д." (as formatted by BG/USD) are used in the number formatted by the same style.

Currency style should set approprate default fraction digits precision.

Default fraction limits should depend on the currency used. It should match values provided by Foundation.NumberFormatter. Below is an example of desired behavior,

NumericTextStyle<Decimal>.Currency(code: "USD") ==
NumericTextStyle<Decimal>.Currency(code: "USD").precision(integer: 1..., fraction: 2...2)

Use proper currency symbol pattern matching.

It is needed for another feature I’m thinking about. The current solution works well, but is a bit too hack-y. The new implementation should still search directionally, as far as needed, and be skipped when not needed.

Tests.

  • Currency: test locale/currency pairs.
  • Number and percent: test all locales.

Invalid use of synchronize method (dev).

There are three parameters that affect the outcome when synchronizing the view:

  1. Value
  2. Style
  3. Mode

The contents of the synchronize method should not be called unless one or more has changed.

Awaiting improved interoperability.

Public UIKit compatible environment values

Mimicking environment values adds a lot of overhead, for library authors and especially for users. Nobody wants 12 different modules with 12 different ways of writing the same value to the environment. In an alternative universe, where environment values are exposed, there is peace and harmony and all nations sing Kumbayah because custom 3rd party iOS libraries just work as if Apple themselves had built them.

Use of SwiftUI.Font, environment \.font

Requires public SwiftUI.Font to UIKit.UIFont conversion.

Use of view.toolbar as input accessory view

Requires exposure of whatever is used behind the scenes.

Use of other environment values

Private environment values == decent 3rd party libraries.
Public environment values == amazing 3rd party libraries.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.