Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Examples/DemosApp/DemosApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@
PRODUCT_BUNDLE_IDENTIFIER = io.componentskit.examples.DemosApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
Expand Down Expand Up @@ -300,7 +300,7 @@
PRODUCT_BUNDLE_IDENTIFIER = io.componentskit.examples.DemosApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ Enim habitant laoreet inceptos scelerisque senectus, tellus molestie ut. Eros ri

// MARK: - UIKit

@MainActor
static func ukHeader(hasHeader: Bool) -> UKModalController.Content? {
guard hasHeader else {
return nil
Expand All @@ -139,6 +140,7 @@ Enim habitant laoreet inceptos scelerisque senectus, tellus molestie ut. Eros ri
}
}

@MainActor
static func ukBody(body: ContentBody) -> UKModalController.Content {
return { _ in
let subtitle = UILabel()
Expand All @@ -154,36 +156,39 @@ Enim habitant laoreet inceptos scelerisque senectus, tellus molestie ut. Eros ri
}
}

@MainActor
static func ukFooter(footer: ContentFooter?) -> UKModalController.Content? {
return footer.map { footer in
return { dismiss in
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = 16

let button = UKButton(
model: self.footerButtonVM,
action: { dismiss(true) }
)
stackView.addArrangedSubview(button)

switch footer {
case .button:
button.model.isEnabled = true
case .buttonAndCheckbox:
button.model.isEnabled = false
let checkbox = UKCheckbox(
initialValue: false,
model: self.footerCheckboxVM,
onValueChange: { isSelected in
button.model.isEnabled = isSelected
}
)
stackView.insertArrangedSubview(checkbox, at: 0)
}
guard let footer else {
return nil
}

return { dismiss in
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = 16

return stackView
let button = UKButton(
model: self.footerButtonVM,
action: { dismiss(true) }
)
stackView.addArrangedSubview(button)

switch footer {
case .button:
button.model.isEnabled = true
case .buttonAndCheckbox:
button.model.isEnabled = false
let checkbox = UKCheckbox(
initialValue: false,
model: self.footerCheckboxVM,
onValueChange: { isSelected in
button.model.isEnabled = isSelected
}
)
stackView.insertArrangedSubview(checkbox, at: 0)
}

return stackView
}
}

Expand Down Expand Up @@ -220,6 +225,7 @@ Enim habitant laoreet inceptos scelerisque senectus, tellus molestie ut. Eros ri
}
}

@MainActor
static func suFooter(
isPresented: Binding<Bool>,
isCheckboxSelected: Binding<Bool>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct UKComponentPreview<View, Model>: UIViewRepresentable where View: UKCompon
let model: Model
let view: View

@MainActor
init(view: View) {
self.view = view
self.model = view.model
Expand All @@ -53,6 +54,7 @@ struct UKComponentPreview<View, Model>: UIViewRepresentable where View: UKCompon
}

extension UKComponent {
@MainActor
var preview: some View {
UKComponentPreview(view: self)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import UIKit

@MainActor
struct AlertButtonsOrientationCalculator {
enum Orientation {
case vertical
case horizontal
}

private static let primaryButton = UKButton(model: .init())
private static let secondaryButton = UKButton(model: .init())

private init() {}

static func preferredOrientation(model: AlertVM) -> Orientation {
Expand All @@ -17,15 +15,15 @@ struct AlertButtonsOrientationCalculator {
return .vertical
}

self.primaryButton.model = primaryButtonVM.updating {
let primaryButton = UKButton(model: primaryButtonVM.updating {
$0.isFullWidth = false
}
self.secondaryButton.model = secondaryButtonVM.updating {
})
let secondaryButton = UKButton(model: secondaryButtonVM.updating {
$0.isFullWidth = false
}
})

let primaryButtonWidth = self.primaryButton.intrinsicContentSize.width
let secondaryButtonWidth = self.secondaryButton.intrinsicContentSize.width
let primaryButtonWidth = primaryButton.intrinsicContentSize.width
let secondaryButtonWidth = secondaryButton.intrinsicContentSize.width

// Since the `maxWidth` of the alert is always less than the width of the
// screen, we can assume that the width of the container is equal to this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ open class UKAlertController: UKCenterModalController {
// MARK: - Style Helpers

extension UKAlertController {
@MainActor
fileprivate enum Style {
static func titleLabel(_ label: UILabel, text: String?) {
label.text = text
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import SwiftUI
import UIKit

@MainActor
final class AvatarImageManager: ObservableObject {
@Published var avatarImage: UIImage

private var model: AvatarVM
private static var remoteImagesCache = NSCache<NSString, UIImage>()
private static let remoteImagesCache = NSCache<NSString, UIImage>()

init(model: AvatarVM) {
self.model = model
Expand Down Expand Up @@ -41,7 +42,7 @@ final class AvatarImageManager: ObservableObject {
}

private func downloadImage(url: URL) {
Task { @MainActor in
Task {
let request = URLRequest(url: url)
guard let (data, _) = try? await URLSession.shared.data(for: request),
let image = UIImage(data: data)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation

/// Defines the source options for an avatar image.
extension AvatarVM {
public enum ImageSource: Hashable {
public enum ImageSource: Hashable, Sendable {
/// An image loaded from a remote URL.
///
/// - Parameter url: The URL pointing to the remote image resource.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Foundation
///
/// It is used to provide a fallback or alternative visual representation when an image is not provided or fails to load.
extension AvatarVM {
public enum Placeholder: Hashable {
public enum Placeholder: Hashable, Sendable {
/// A placeholder that displays a text string.
///
/// This option is typically used to show initials, names, or other textual representations.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Combine
@preconcurrency import Combine
import UIKit

/// A UIKit component that displays a profile picture, initials or fallback icon for a user.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ final class AvatarContainer: UIView {
// MARK: - Style Helpers

extension AvatarContainer {
@MainActor
fileprivate enum Style {
static func mainView(_ view: UIView, model: AvatarGroupVM) {
view.backgroundColor = model.borderColor.uiColor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ open class UKAvatarGroup: UIView, UKComponent {
// MARK: - Style Helpers

extension UKAvatarGroup {
@MainActor
fileprivate enum Style {
static func stackView(_ view: UIStackView, model: Model) {
view.axis = .horizontal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation

extension BadgeVM {
/// Defines the available visual styles for a badge.
public enum Style: Equatable {
public enum Style: Equatable, Sendable {
case filled
case light
}
Expand Down
1 change: 1 addition & 0 deletions Sources/ComponentsKit/Components/Badge/UKBadge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ open class UKBadge: UIView, UKComponent {
// MARK: - Style Helpers

extension UKBadge {
@MainActor
fileprivate enum Style {
static func mainView(_ view: UIView, model: BadgeVM) {
view.backgroundColor = model.backgroundColor.uiColor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation

/// Specifies the position of the image relative to the button's title.
extension ButtonVM {
public enum ImageLocation {
public enum ImageLocation: Sendable {
/// The image is displayed before the title.
case leading
/// The image is displayed after the title.
Expand Down
1 change: 1 addition & 0 deletions Sources/ComponentsKit/Components/Button/UKButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ open class UKButton: FullWidthComponent, UKComponent {
// MARK: - Style Helpers

extension UKButton {
@MainActor
fileprivate enum Style {
static func mainView(_ view: UIView, model: Model) {
view.backgroundColor = nil
Expand Down
1 change: 1 addition & 0 deletions Sources/ComponentsKit/Components/Card/UKCard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ open class UKCard<Content: UIView>: UIView, UKComponent {
}

extension UKCard {
@MainActor
fileprivate enum Style {
static func mainView(_ view: UIView, model: Model) {
view.layer.cornerRadius = model.cornerRadius.value
Expand Down
1 change: 1 addition & 0 deletions Sources/ComponentsKit/Components/Checkbox/UKCheckbox.swift
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ open class UKCheckbox: UIView, UKComponent {
// MARK: - Style Helpers

extension UKCheckbox {
@MainActor
fileprivate enum Style {
static func stackView(_ stackView: UIStackView, model: Model) {
stackView.axis = .horizontal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation

extension CircularProgressVM {
/// Defines the shapes for the circular progress component.
public enum Shape {
public enum Shape: Sendable {
/// Renders a complete circle to represent the progress.
case circle
/// Renders only a portion of the circle (an arc) to represent progress.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ open class UKCircularProgress: UIView, UKComponent {
// MARK: - Style Helpers

extension UKCircularProgress {
@MainActor
fileprivate enum Style {
static func backgroundLayer(
_ layer: CAShapeLayer,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import UIKit

@MainActor
struct CountdownWidthCalculator {
private static let label = UILabel()

private init() {}

static func preferredWidth(
for attributedText: NSAttributedString,
model: CountdownVM
) -> CGFloat {
self.style(self.label, with: model)
self.label.attributedText = attributedText
let label = UILabel()
self.style(label, with: model)
label.attributedText = attributedText

let estimatedSize = self.label.sizeThatFits(UIView.layoutFittingExpandedSize)
let estimatedSize = label.sizeThatFits(UIView.layoutFittingExpandedSize)

return estimatedSize.width + 2
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import Foundation
// MARK: - UnitsLocalization

/// A structure that provides localized representations of time units (seconds, minutes, hours, days).
public struct UnitsLocalization: Equatable {
public struct UnitsLocalization: Equatable, Sendable {
/// A structure that represents the localized short and long forms of a single time unit.
public struct UnitItemLocalization: Equatable {
public struct UnitItemLocalization: Equatable, Sendable {
/// The short-form representation of the time unit (e.g., "s" for seconds).
public let short: String
/// The long-form representation of the time unit (e.g., "Seconds").
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import SwiftUI

class CountdownManager: ObservableObject {
class CountdownManager: ObservableObject, @unchecked Sendable {
// MARK: - Published Properties

@Published var days: Int = 0
Expand All @@ -13,6 +13,10 @@ class CountdownManager: ObservableObject {
private var timer: Timer?
private var until: Date?

deinit {
self.stop()
}

// MARK: - Methods

func start(until: Date) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import Foundation

extension CountdownVM {
/// Defines the visual styles for the countdown component.
public enum Style: Equatable {
public enum Style: Equatable, Sendable {
case plain
case light
}

/// Defines the units style for the countdown component.
public enum UnitsStyle: Equatable {
public enum UnitsStyle: Equatable, Sendable {
case hidden
case bottom
case trailing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ extension CountdownVM {
|| self.locale != oldModel.locale
}

@MainActor
func timeWidth(manager: CountdownManager) -> CGFloat {
let values: [(Int, CountdownHelpers.Unit)] = [
(manager.days, .days),
Expand Down
Loading