Giter Club home page Giter Club logo

ycoreui's People

Contributors

devyml avatar dharmik-yml avatar karthikyml avatar mpospese avatar sahilsainiyml avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ycoreui's Issues

Log warning message when Colorable.color uses the fallback color

Our Colorable protocol helps users load (and unit test) colors from asset catalogs. It provides a fallback color to use in case the named color asset cannot be found. In that case though we should log a warning message.

Refer to the logging in ImageAsset.image and SystemImage.image, except that we should use YCoreUI.colorLogger.

  • Log warning level message from Colorable.color if and only if returning the fallbackColor.
  • Don't log anything if YCoreUI.isLoggingEnabled == false
  • Use YCoreUI.colorLogger
  • Extract the code that builds name from namespace + rawValue into an internal calculateName() method and cover it in unit tests (see ImageAsset.calculateName() and associated unit tests for reference).
  • warning message must contain the full name from calculateName()
  • In ColorableTests try to minimize use of logger. Ideally log only one message before disabling the logging for remainder of failure cases (but re-enable it at end of tests). See ImageAssetTests and SystemImageTests.
  • Keep unit test coverage at 100%

Add protocols to README

Intro

There are a few things missing from our README

Task

  1. Add a short Licensing section near the top (refer to Y—MatterType)
  2. In the contents list insert a new section as the 2nd: Protocols to aid loading string, color, and image assets
  3. Within that section detail Localizable, Colorable, and ImageAsset protocols with code examples
  4. Within the auto layout section include explanations and examples for the constrainCenter, constrainSize, and constrainAspectRatio methods.
  5. Similar to methods for constrainEdges and others, the code files for center, size, aspect ratio constraints should include code examples (can be the same ones added to the README).

Most of the info in 2-4 has been added to the Y—CoreUI corporate Notion page.

Expand Localizable with tableName

Let's expand our Localizable protocol to include tableName support.

  1. add static var tableName: String? to Localizable
  2. add a default implementation of tableName to return nil
  3. expand String.localized to add table tableName: String? = nil second parameter and pass that to the internal call to NSLocalizedString.
  4. expand the default implementation of Localizable.localized to pass Self.tableName to String.localized(bundle:tableName:)

(Basically everywhere we're using bundle in conjunction with Localizable, we should also use tableName.

  1. make sure all public interfaces are fully documented with documentation comments
  2. make sure new code paths are fully covered with unit tests (see String+LocalizedTests.swift)
  3. for testing let's add a new Settings.strings file under Tests/YCoreUITests/Assets/Strings/en.lproj and add 3 string values to it. Declare a new SettingsConstants enum which overrides tableName to find to the right strings file. Test that all the values in this enum load properly.

Add `ImageAsset` protocol

Intro

It's a common pattern to have a string-based enum to hold the names of image assets in an asset catalog. In each case you need to add some sort of computed property or func to return the image loaded from the asset catalog. It would be nice to have a protocol that we could simply have our enum conform to and skip having to write that implementation again and again. (This is especially true for cases where you might wish to organize your images into multiple enums, which would require writing that image loading property/func once per enum.)

So let's declare a public protocol named ImageAsset.
(It is patterned off the protocol Localizable that is already part of YCoreUI. ImageAsset will do for image assets what Localizable does for string assets and Colorable does for color assets).

Tasks

  • declare a public protocol ImageAsset
    • declare a static get var bundle of type Bundle
    • declare a static get var namespace of type String?
    • declare a static get var fallbackImage of type UIImage
    • declare a loadImage func that takes no parameters and returns UIImage?
    • declare a get var image of type UIImage
  • add default implementations to all 4
  • bundle defaults to Bundle.main
  • namespace defaults to nil
  • fallbackImage defaults to a custom-drawn image that will be obvious to visual QA is not correct. Perhaps a 16x16 image filled with UIColor.systemPink
  • loadImage attempts to load the named image using (optional namespace prepended to) rawValue and bundle (but returns nil if the image does not exist in the asset catalog).
  • image uses loadImage but nil-coalesces the result back to fallbackImage so that it always returns something.

Acceptance Criteria

  • Implement ImageAsset as described in Tasks above
  • SwiftLint analysis has 0 violations
  • fully unit test the new code by adding images to an asset catalog in the test target only, declaring an enum that lists the names of the images, and test that it loads. Also test expected failures (e.g. blank name or random name does not load, wrong bundle, etc)
  • the sample image assets used in our test target need to be as small as possible freely distributable. (I might just create some simple pixel art images to use.)
  • fully document all public interfaces on the new code (as per Jazzy documentation coverage tests)

Add Elevation shadows

Intro

Design specifies shadows differently than we do in code on iOS. They often refer to them as “elevations”. Let’s add a struct to encapsulate design shadows and apply them to views.

Tasks

  • declare a public struct Elevation
    • declare a let property offset: CGSize
    • declare a let property of blur: CGFloat
    • declare a let property of spread: CGFloat
    • declare a let property of color: UIColor
    • declare a let property of opacity: CGFloat
    • declare a let property of useShadowPath: Bool (defaults to true)
  • add a func apply that takes parameters layer: CALayer and cornerRadius: CGFloat that applies the elevation to a layer. This method should not set the shadowPath if useShadowPath == false.

pseudo code:

struct Elevation {
    let offset: CGSize
    let blur: CGFloat
    let spread: CGFloat
    let color: UIColor
    let opacity: CGFloat
    let useShadowPath: Bool // defaults to `true`

    func apply(layer: CALayer, cornerRadius: CGFloat) {
        layer.shadowColor = color.cgColor
        layer.shadowOffset = offset
        layer.shadowOpacity = opacity
        layer.shadowRadius = blur / 2

        guard useShadowPath else { return }
        let rect = layer.bounds.insetBy(dx: -spread, dy: -spread)
        layer.shadowPath = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).cgPath
    }
}

Discussion

Because the implementation of spread requires a shadow path, we will not be able to implement a shadow with spread for a view whose shape we do not know (e.g. useShadowPath == false).

Acceptance Criteria

  • Implement Elevation as described in Tasks above
  • SwiftLint analysis has 0 violations
  • fully unit test the new code
  • fully document all public interfaces on the new code (as per Jazzy documentation coverage tests)

`constrainCenter` return value should be discardable

Intro

All of our constrain methods return either constraints or dictionaries of constraints but these are always discardable (they do not need to be retained because the constraint's parent view retains them).

constrainCenter was supposed to be marked @discardableResult (it was part of the acceptance criteria for the ticket), but it got overlooked.

Task

mark constrainCenter function return as @discardableResult

Add Usage information and code samples to README

Intro

Our README should contain all necessary summary information about our framework. Currently we're missing usage information.

Task

Copy the usage information from this Notion page (restricted) into the README. Add a new h2 section "Usage" and place that information within (using h3 and h4 subsections as appropriate). The "Usage" section should be between "Documentation" and "Installation". Do not copy over the section with the video links (because those are private).

AC

  • README updated with all usage information

Add tvOS support

Intro

tvOS uses many of the same UIKit components as iOS, so we should expand Y—CoreUI to support tvOS.

Task

  • add .tvOS(.v14) platform to Swift package
  • Port YCoreUI to compile on tvOS
  • Port YCoreUI to pass unit tests on tvOS
  • Unsupported functionality (if any) should be excluded from tvOS using #if !os(tvOS) or if os(iOS) (keep future watchOS support in mind)
  • Functionality that is supported but does not work (if any) should be excluded from tvOS

AC

  • Project compiles for iOS and tvOS without warnings
  • SwiftLint returns 0 violations
  • All unit tests pass on both platforms
  • 100% documentation coverage of all public interfaces as determined by Jazzy

Add Animation struct to support customizing animations

Intro

We allow users to customize the appearance of our various components via an Appearance structure.
We should also allow them to customize the animation parameters (duration, delay, options, type of curve, etc). Would be nice if users could choose either spring damping animation or a regular animation curve and we could execute either one (even though they map to two different UIView class methods).

Task

  • Add an Animation struct, which should have the following properties:
    1. duration
    2. delay
    3. curve type: which can be regular (with options), or spring (with dampingRatio, initialVelocity, and options). Use an enum with associated values.
  • Extend UIView with a new animate class func that takes Animation plus animations block and optional completion block as parameters. This method will call the appropriate animate override and pass through the various parameters.
  • Unit test

Discussion

We can use this in YSnackbar to fully customize the add, rearrange, and remove animations.

Add SystemImage protocol

We have ImageAsset protocol to allow users to load images from asset catalogs, unit test them, and have a fallback image (so that we can return a non-optional UIImage. We should do the same thing for system images, e.g. for UIImage(systemName:) optional initializer.

We could declare a new protocol SystemImage and either derive it from ImageAsset or just copy the needed functionality. While we would need:

    static var fallbackImage: UIImage { get }
    var image: UIImage { get }
    func loadImage() -> UIImage?

we do not need (not applicable):

    static var bundle: Bundle { get }
    static var namespace: String? { get }

loadImage would have default implementation:

func loadImage() -> UIImage? { UIImage(systemName: rawValue) }

fix SPI documentation configuration

Intro

Our repo contains a config file that tells the Swift Package Index where to point for our documentation, but it has a typo in it and so does not work.

Task

Fix the typo in .spi.yml config file

current text:

version: 1
external_links:
  documentation: "<https://yml-org.github.io/YCoreUI/">

new text:

version: 1
external_links:
  documentation: "https://yml-org.github.io/YCoreUI/"

Add `constrainCenter` auto layout extension to UIView

Create a new source file under Sources/YCoreUI/Extensions/UIKit named UIView+constrainCenter.swift
Publicly extend UIView to add the following two items:

  1. struct Center which is an OptionSet (type Uint). It should have the following values:
    a. x = 1 << 0
    b. y = 1 << 1
    c. all = [.x, .y]
  2. method constrainCenter takes the following parameters:
    a. _ center: Center = .all
    b. to view2: Anchorable? = nil
    c. offset: UIOffset = .zero
    d. priority: UILayoutPriority = .required
    e. isActive: Bool = true
    This method creates centerX and/or centerY constraints using constrain anchor overrides (so .centerXAnchor and .centerYAnchor) and returns the one or two created constraints in a dictionary keyed by .centerX and/or .centerY, respectively. The result is discardable. When view2 == nil pass superview to constrain anchor (see otherView in UIView+constrainEdges.swift implementation). Generally refer to constrainEdges implementation as it will be similar only you are creating up to two constraints instead of up to four.
  3. Create a new XCTest file under Tests/YCoreUITests/Extensions/UIKit named UIView+constrainCenterTests.swift
    a. name the test UIViewContrainCenterTests and mark it final
    b. add three test cases to test creating only center x, only center y, and both.
  4. Ensure that all public interfaces are fully documented with documentation comments (including parameters and returns)

Add optional rendering mode to SystemImage

Let's expand the functionality of our system image loading protocol to include rendering mode.
(Theoretically we could also expand this to ImageAsset, but catalog assets can already specify rendering mode in the asset.)

  • Add property public static var renderingMode: UIImage.RenderingMode? { get }
  • Default implementation is { nil }
  • Modify loadImage() to check renderingMode and if non-nil, modify the returned image with .withRenderingMode(:)

This will let users set the rendering mode on an entire group (enum) of images.
This will be useful in YStepper and YCalendarPicker.

Add `constrainAspectRatio` auto layout extension method to UIView

Create a new source file under Sources/YCoreUI/Extensions/UIKit named UIView+constrainAspectRatio.swift
Publicly extend UIView to add the following method:

  1. constrainAspectRatio takes parameters
    a. _ ratio: CGFloat
    b. offset: CGFloat = 0
    b. relatedBy relation: NSLayoutConstraint.Relation = .equal
    c, priority: UILayoutPriority = .required
    d, isActive: Bool = true
  2. it creates a constraint on the receiving view, constraining its widthAnchor to its heightAnchor using ratio as the multiplier and optional offset as the constant.
  3. it returns the single created NSLayoutConstraint but it is @discardableResult
  4. Create a new XCTest file under Tests/YCoreUITests/Extensions/UIKit named UIView+constrainAspectRatioTests.swift
    a. name the test UIViewContrainAspectRatioTests and mark it final
    b. add test case for the method created above.
  5. Ensure that the new method is fully documented with documentation comments (including parameters and returns)
  6. Add file comment example of how to set the aspect ratio of an image view (see UIView+constrainAnchor.swift Use-case examples)
  7. Add same example to README
  8. Add same example to Notion page: https://www.notion.so/ymedialabs/Y-CoreUI-882275f4b88a408dba83f93539433d44

Add `Colorable` protocol

Intro

It's a common pattern to have a string-based enum to hold the names of color assets in an asset catalog. In each case you need to add some sort of computed property or func to return the color loaded from the asset catalog. It would be nice to have a protocol that we could simply have our enum conform to and skip having to write that implementation again and again. (This is especially true for cases where you might wish to organize your colors into multiple enums, which would require writing that color loading property/func once per enum.)

So let's declare a public protocol named Colorable.
(It is patterned off the protocol Localizable that is already part of YCoreUI. Colorable will do for color assets what Localizable does for string assets).

Tasks

  • declare a public protocol Colorable
    • declare a static get var bundle of type Bundle
    • declare a static get var namespace of type String?
    • declare a static get var fallbackColor of type UIColor
    • declare a loadColor func that takes no parameters and returns UIColor?
    • declare a get var color of type UIColor
  • add default implementations to all 4
  • bundle defaults to Bundle.main
  • namespace defaults to nil
  • fallbackColor defaults to UIColor.systemPink (we want something obvious to flag errors but also something unlikely to be actually used, so that we can unit tests that our colors load without fallback)
  • loadColor attempts to load the named color using (optional namespace prepended to) rawValue and bundle (but returns nil if the color does not exist in the asset catalog).
  • color uses loadColor but nil-coalesces the result back to fallbackColor so that it always returns something.

Acceptance Criteria

  • Implement Colorable as described in Tasks above
  • SwiftLint analysis has 0 violations
  • fully unit test the new code by adding colors to an asset catalog in the test target only, declaring an enum that lists the names of the colors, and test that it loads. Also test expected failures (e.g. blank name or random name does not load, wrong bundle, etc)
  • fully document all public interfaces on the new code (as per Jazzy documentation coverage tests)

Add `constrainSize` auto layout extension to UIView

Create a new source file under Sources/YCoreUI/Extensions/UIKit named UIView+constrainSize.swift
Publicly extend UIView to add the following three methods:

  1. constrainSize takes parameters _ size: CGSize, relatedBy relation: NSLayoutConstraint.Relation = .equal, priority: UILayoutPriority = .required, isActive: Bool = true and returns a dictionary [NSLayoutConstraint.Attribute: NSLayoutConstraint]
    a. creates width and height constraints using constrain anchor overrides (so .widthAnchor and .heightAnchor)
    b. returns the two created constraints in a dictionary keyed by .width and .height, respectively.
    c. result is discardable
  2. constrainSize takes parameters width: CGFloat, height: CGFloat, relatedBy relation: NSLayoutConstraint.Relation = .equal, priority: UILayoutPriority = .required, isActive: Bool = true and returns same dictionary as 1.
    a. creates a CGSize using width and height and then calls the override from 1.
  3. constrainSize takes parameter _ dimension: CGFloat, relatedBy relation: NSLayoutConstraint.Relation = .equal, priority: UILayoutPriority = .required, isActive: Bool = true and returns same dictionary as 1.
    a. creates a CGSize where width and height both equal dimension and then calls the override from 1.
  4. Create a new XCTest file under Tests/YCoreUITests/Extensions/UIKit named UIView+constrainSizeTests.swift
    a. name the test UIViewContrainSizeTests and mark it final
    b. add test case for each of the three methods created above.
  5. Ensure that the three new methods are fully documented with documentation comments (including parameters and returns)

Fix SwiftLint config warnings

Intro

The unused_import rule is not actually being enforced because it runs during the analysis phase and not during the build phase.
(And I've tried running it as part of analysis and even then it doesn't work: if you satisfy the rule when analyzing the package, then imports are missing when trying to use the package.)

The current lint run warns about this rule not being run. We should just remove it.

Also the anyobject_protocol warning is now enforced by Xcode itself and so no longer needs to be checked with SwiftLint. Again we should just remove it.

warning: 'unused_import' should be listed in the 'analyzer_rules' configuration section for more clarity as it is only run by 'swiftlint analyze'
The `anyobject_protocol` rule is now deprecated and will be completely removed in a future release.

Task

  • Remove the unused_import and anyobject_protocol rules from .swiftlint.yml config file

Account for transparency when calculating WCAG color contrast

Intro

When we perform our color contrast checking, we only look at the RGB channels and not the A. When the foreground color has alpha, it becomes blended with the background color, and it is this blended color that we should perform the check against. (If the background color has alpha, then it becomes blended with whatever is behind it, which is unknown to our package).

Tasks

  • If neither color have alpha values < 1.0 then no change
  • If both colors have alpha values < 1.0 we should return .nan for the contrast ratio and fail any comparisons.
  • If one color has an alpha value, we will treat it as the foreground color (although it may not be) and blend it with the other color, and then compare contrast with the second color.

Example

UIColor.secondaryLabel when compared to UIColor.systemBackground seems to meet AA contrast requirements across all color spaces (light/dark modes, normal/high contrast) but that's only because we're ignoring .secondaryLabel's alpha channel. It is in fact transparent and the composite of it with .systemBackground does not meet AA contrast requirements for normal text.

Cover Foundation / UIKit extensions in documentation comments

Intro

In our generated documentation, the top-level pages for extensions look very sparse. Like this:
image

By adding documentation comments to public extensions, we could improve the readability of both the source code and the generated documentation. The documentation shown above with extension comments added, becomes this:
image

Task

  1. Add documentation comments to the following public extensions:
  • Foundation/CGFloat+rounded.swift
  • Foundation/CGSize+inset.swift
  • Foundation/String+Localizable.swift
  • UIKit/UIScreen+scaleFactor.swift
  • UIKit/UITraitCollection+colorSpaces.swift
  • UIKit/UIView+constrainEdges.swift (NSDirectionalRectEdge extension only)
  1. Unify how we declare these extensions: move the public declaration to the extension itself and remove it from the individual public methods (any properties/methods declared as internal/private need to remain so) Do this only for the extensions you document in Step 1 above

AC

  • Task (above) completed
  • 0 SwiftLint violations
  • compiles with 0 warnings for iOS and tvOS
  • unit tests pass for iOS and tvOS
  • 100% documentation coverage as per Jazzy

Discussion

Jazzy combines all extended properties / methods from multiple extensions into a single documentation page. e.g. for UIColor we have 8 properties / methods spread across 5 separate extensions but they are all documented together on a single page. In this case Jazzy will not generate documentation for the extension (how would it know to combine the comments from the 5 extensions?). Documenting the extensions still has value though, but for now we will focus on classes that only have a single extension in our package. In a later ticket we can document the multiple extensions for UIColor, UIView, etc.

Add Swift Package Index Integration

Add config file to point Swift Package Index to our GH page.

Add config file .spi.yml to root

version: 1
external_links:
  documentation: "https://yml-org.github.io/YCoreUI/"

Clamp rgb channel values to {0...1} (i.e. 0x00 – 0xFF) when displaying as hex string

Because we support extended RGB color space, individual channels can have values less than zero or greater than one. These do not format well for hexadecimal strings. For UIColor.rgbDisplayString we should clamp the channel values to {0...1} to avoid issues (and maybe append a ⚠️ emoji to the end of the string to indicate that its actual value is outside the bounds of the sRGB color space).

Add support for LCh color space to UIColor

Add a UIColor initializer that supports the LCh color space.
This will require importing a couple of gists to support CieLAB colors but also creating a new "friendly" UIColor initializer to refer to the CieLAB version internally.

public func init(luminance: CGFloat, chroma: CGFloat, hue: CGFloat)

where luminance is 0.0 – 1.0
chroma is 0 – ~180
hue is in degrees not radians

`Localizable.tableName` needs a public default implementation

Intro

In Issue #7 we expanded the Localizable protocol with optional tableName. This was intended to have a default implementation (returns nil) but we forgot to mark it as public, so effectively it has no default implementation.

Task

mark Localizable.tableName default implementation (in the extension) as public.

Expand SystemImage protocol to load scalable system images by default

Our SystemImage protocol should load scalable system images by default. We do that by loading the image with UIImage.SymbolConfiguration(textStyle: aTextStyle). This allows the image scale according to the specified text style when Dynamic Type changes. And it will respond to Bold Text as well (to use heavier strokes).

  1. add a static var textStyle: UIFont.TextStyle? with default implementation = .body
  2. add a static var configuration: UIImage.Configuration with default implementation = UIImage.SymbolConfiguration(textStyle: textStyle) when textStyle != nil (need to see what configuration to use when it's nil. Maybe nil or maybe some default configuration that does nothing)

Idea is the following:

  1. By default system images will scale according to .body
  2. It's simple to override and specify a different text style if you need it a bit bigger or smaller; e.g. callout or title
  3. If needed you can also provide any configuration. e.g. in addition to textStyle you might also want to configure weight (e.g. ultralight or bold) to adjust the appearance of the symbol. It's also an opportunity to apply hierarchical or palette information.

Log warnings in ImageAsset.image and SystemImage.image when loadImage() fails

Let's log to console from var image: UIImage when loadImage() returns nil and we resort to the fallback image.
(This is preferable to logging from loadImage() which can be expected to return nil under certain unit tests.)

See how YMatterType logs when fonts don't load and let's adopt a similar pattern for declaring the Logger to use.
This will be iOS 14+.

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.