Skip to content

Commit

Permalink
Merge branch 'main' into colors/new-tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
LouisBorleeAdevinta authored Aug 2, 2023
2 parents bdc67cc + 8c69052 commit 44a9965
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 233 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ import Foundation

enum BadgeConstants {
static let emptySize = CGSize(width: 12, height: 12)
static let height: CGFloat = 24
}
86 changes: 74 additions & 12 deletions core/Sources/Components/Badge/View/UIKit/BadgeUIView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ public class BadgeUIView: UIView {

// Dynamicaly sized properties for badge
// emptyBadgeSize represents size of the circle in empty state of Badge
// horizontalSpacing and verticalSpacing are properties
// that are used for space between badge background and text
// horizontalSpacing is the padding to the left and right of the text
// borderWidth is the width of the border when it's shown
// badgeHeight is the height of the badge
@ScaledUIMetric private var emptyBadgeSize: CGFloat = 0
@ScaledUIMetric private var horizontalSpacing: CGFloat = 0
@ScaledUIMetric private var verticalSpacing: CGFloat = 0
@ScaledUIMetric private var borderWidth: CGFloat = 0
@ScaledUIMetric private var badgeHeight: CGFloat = 0

// Constraints for badge size
// Thess constraints containes text size with
Expand Down Expand Up @@ -67,6 +68,66 @@ public class BadgeUIView: UIView {

private var cancellables = Set<AnyCancellable>()

// MARK: - Public variables
/// The current theme of the view
public var theme: Theme {
get {
return self.viewModel.theme
}
set {
self.viewModel.theme = newValue
}
}

/// The current intent
public var intent: BadgeIntentType {
get {
return self.viewModel.intent
}
set {
self.viewModel.intent = newValue
}
}

/// The badge size
public var size: BadgeSize {
get {
return self.viewModel.size
}
set {
self.viewModel.size = newValue
}
}

/// The current value of the badge
public var value: Int? {
get {
return self.viewModel.value
}
set {
self.viewModel.value = newValue
}
}

/// The formatter of the badge
public var format: BadgeFormat {
get {
return self.viewModel.format
}
set {
self.viewModel.format = newValue
}
}

/// Shows/hides the border around the badge
public var isBorderVisible: Bool {
get {
return self.viewModel.isBorderVisible
}
set {
self.viewModel.isBorderVisible = newValue
}
}
// MARK: - Init

public init(theme: Theme, intent: BadgeIntentType, size: BadgeSize = .normal, value: Int? = nil, format: BadgeFormat = .default, isBorderVisible: Bool = true) {
Expand Down Expand Up @@ -94,8 +155,8 @@ public class BadgeUIView: UIView {

private func setupScalables() {
self.emptyBadgeSize = BadgeConstants.emptySize.width
self.badgeHeight = BadgeConstants.height
self.horizontalSpacing = self.viewModel.horizontalOffset
self.verticalSpacing = self.viewModel.verticalOffset
self.borderWidth = self.viewModel.isBorderVisible ? self.viewModel.border.width : .zero
}

Expand Down Expand Up @@ -133,28 +194,30 @@ public class BadgeUIView: UIView {

private func setupSizeConstraint(for textSize: CGSize) {
let widht = self.viewModel.isBadgeEmpty ? self.emptyBadgeSize : textSize.width + (self.horizontalSpacing * 2)
let height = self.viewModel.isBadgeEmpty ? self.emptyBadgeSize : textSize.height + (self.verticalSpacing * 2)
let height = self.viewModel.isBadgeEmpty ? self.emptyBadgeSize : self.badgeHeight

if let widthConstraint, let heightConstraint {
widthConstraint.constant = widht
heightConstraint.constant = height
} else {
widthConstraint = self.widthAnchor.constraint(equalToConstant: widht)
heightConstraint = self.heightAnchor.constraint(equalToConstant: height)
NSLayoutConstraint.activate(sizeConstraints.compactMap({ $0 }))
self.widthConstraint = self.widthAnchor.constraint(equalToConstant: widht)
self.widthConstraint?.priority = .required
self.heightConstraint = self.heightAnchor.constraint(equalToConstant: height)
self.heightConstraint?.priority = .required
NSLayoutConstraint.activate(self.sizeConstraints.compactMap({ $0 }))
}
}

private func setupBadgeConstraintsIfNeeded(for textSize: CGSize) {
guard shouldSetupLabelConstrains else {
guard self.shouldSetupLabelConstrains else {
return
}

self.labelLeadingConstraint = self.textLabel.leadingAnchor.constraint(equalTo: leadingAnchor)
self.labelTopConstraint = self.textLabel.topAnchor.constraint(equalTo: topAnchor)
self.labelTrailingConstraint = self.textLabel.trailingAnchor.constraint(equalTo: trailingAnchor)
self.labelBottomConstraint = self.textLabel.bottomAnchor.constraint(equalTo: bottomAnchor)
NSLayoutConstraint.activate(labelConstraints.compactMap({ $0 }))
NSLayoutConstraint.activate(self.labelConstraints.compactMap({ $0 }))
}

public override func layoutSubviews() {
Expand All @@ -172,7 +235,6 @@ public class BadgeUIView: UIView {
}
}


/// Attach badge to another view by using constraints
/// Triggers detach() if it was already attached to a view
/// - Parameters:
Expand Down Expand Up @@ -290,8 +352,8 @@ extension BadgeUIView {
self._emptyBadgeSize.update(traitCollection: self.traitCollection)
} else {
self._horizontalSpacing.update(traitCollection: self.traitCollection)
self._verticalSpacing.update(traitCollection: self.traitCollection)
}
self._badgeHeight.update(traitCollection: traitCollection)
}

private func reloadBorderWidth() {
Expand Down
14 changes: 6 additions & 8 deletions core/Sources/Components/Badge/ViewModel/BadgeViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,30 +26,30 @@ import SwiftUI
/// - format -- see ``BadgeFormat`` as a formater of **Badge Text**
///
/// - theme -- represents ``Theme`` used in the app
public final class BadgeViewModel: ObservableObject {
final class BadgeViewModel: ObservableObject {

// MARK: - Badge Configuration Public Properties
public var value: Int? = nil {
var value: Int? = nil {
didSet {
updateText()
}
}
public var intent: BadgeIntentType {
var intent: BadgeIntentType {
didSet {
updateColors()
}
}
public var size: BadgeSize {
var size: BadgeSize {
didSet {
updateFont()
}
}
public var format: BadgeFormat {
var format: BadgeFormat {
didSet {
updateText()
}
}
public var theme: Theme {
var theme: Theme {
didSet {
updateColors()
updateScalings()
Expand All @@ -61,10 +61,8 @@ public final class BadgeViewModel: ObservableObject {
@Published var textFont: TypographyFontToken
@Published var textColor: any ColorToken
@Published var isBadgeEmpty: Bool

@Published var backgroundColor: any ColorToken
@Published var border: BadgeBorder

@Published var isBorderVisible: Bool

// MARK: - Internal Appearance Properties
Expand Down
76 changes: 32 additions & 44 deletions spark/Demo/Classes/View/Components/Badge/Badge+UIPresentable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
//

import Combine
import SwiftUI
import SparkCore
import Spark
import SparkCore
import SwiftUI

private struct BadgePreviewFormatter: BadgeFormatting {
func formatText(for value: Int?) -> String {
Expand All @@ -22,52 +22,40 @@ private struct BadgePreviewFormatter: BadgeFormatting {

struct UIBadgeView: UIViewRepresentable {

var views: [BadgeUIView]

@ObservedObject private var themePublisher = SparkThemePublisher.shared

var theme: Theme {
self.themePublisher.theme
let theme: Theme
let intent: BadgeIntentType
let size: BadgeSize
let value: Int?
let format: BadgeFormat
let isBorderVisible: Bool

init(theme: Theme, intent: BadgeIntentType, size: BadgeSize = .normal, value: Int? = nil, format: BadgeFormat = .default, isBorderVisible: Bool = true) {
self.theme = theme
self.intent = intent
self.size = size
self.value = value
self.format = format
self.isBorderVisible = isBorderVisible
}

func makeUIView(context: Context) -> some UIView {
let badgesStackView = UIStackView()
for view in self.views {
view.setTheme(self.theme)
}
views.enumerated().forEach { index, badgeView in
let containerView = UIView()
containerView.translatesAutoresizingMaskIntoConstraints = false
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "badge_\(index)"
containerView.addSubview(label)
containerView.addSubview(badgeView)
containerView.backgroundColor = .blue

label.activateConstraint(from: .leading, to: .leading, ofView: containerView, relation: .greaterThanOrEqual)
label.activateConstraint(from: .top, to: .top, ofView: containerView)
label.activateConstraint(from: .bottom, to: .bottom, ofView: containerView)

if index >= 3 && index <= 6 {
badgeView.activateConstraint(from: .centerX, to: .trailing, ofView: label, constant: 5)
badgeView.activateConstraint(from: .centerY, to: .top, ofView: label, constant: -5)
} else {
badgeView.activateConstraint(from: .leading, to: .trailing, ofView: label, constant: 5)
badgeView.activateConstraint(from: .centerY, to: .centerY, ofView: label)
}

badgesStackView.addArrangedSubview(containerView)
}
badgesStackView.axis = .vertical
badgesStackView.alignment = .leading
badgesStackView.spacing = 30
badgesStackView.distribution = .fill

return badgesStackView
func makeUIView(context: Context) -> BadgeUIView {
return BadgeUIView(
theme: theme,
intent: intent,
size: size,
value: value,
format: format,
isBorderVisible: isBorderVisible
)
}

func updateUIView(_ uiView: UIViewType, context: Context) {
func updateUIView(_ badge: BadgeUIView, context: Context) {
badge.theme = theme
badge.intent = intent
badge.size = size
badge.format = format
badge.value = value
badge.isBorderVisible = isBorderVisible
}
}

Loading

0 comments on commit 44a9965

Please sign in to comment.