Skip to content
Open
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
33 changes: 33 additions & 0 deletions Example/OpenSwiftUIUITests/View/ProgressViewUITests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// ProgressViewUITests.swift
// OpenSwiftUIUITests

import SnapshotTesting
import Testing
@testable import TestingHost

@MainActor
@Suite(.snapshots(record: .never, diffTool: diffTool))
struct ProgressViewUITests {
@Test
func valueBasedProgress() {
openSwiftUIAssertSnapshot(of: ProgressViewExample())
}

@Test
func indeterminateInitializers() {
openSwiftUIAssertSnapshot(of: IndeterminateProgressViewExample())
}

@Test(.disabled("ResolvableTextSegmentAttribute is not implemented yet"))
func defaultDateProgressLabelInitializers() {
openSwiftUIAssertSnapshot(of: DefaultDateProgressLabelExample())
}

@Test(
.disabled(if: attributeGraphVendor == .compute, "Temporarily disabled for IAG snapshot crash")
)
func foundationProgress() {
openSwiftUIAssertSnapshot(of: FoundationProgressViewExample())
}
}
79 changes: 79 additions & 0 deletions Example/Shared/View/ProgressViewExample.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//
// ProgressViewExample.swift
// Shared

import Foundation
#if OPENSWIFTUI
import OpenSwiftUI
#else
import SwiftUI
#endif

struct ProgressViewExample: View {
var body: some View {
VStack(alignment: .leading, spacing: 16) {
ProgressView(value: 0.25)
ProgressView("Downloading", value: 0.5)
ProgressView(value: 0.75) {
Text("Installing")
} currentValueLabel: {
Text("75%")
}
.tint(.blue)
}
.padding()
}
}

struct IndeterminateProgressViewExample: View {
private let localizedTitle: LocalizedStringKey = "Localized label"
private let title = "String label"

var body: some View {
VStack(alignment: .leading, spacing: 16) {
ProgressView()
ProgressView {
Text("Custom label")
}
ProgressView(localizedTitle)
ProgressView(title)
}
.padding()
}
}

struct DefaultDateProgressLabelExample: View {
private let timerInterval = Date(timeIntervalSinceReferenceDate: 0)...Date(
timeIntervalSinceReferenceDate: 90
)

var body: some View {
VStack(alignment: .leading, spacing: 16) {
ProgressView(timerInterval: timerInterval) {
Text("Countdown")
}
ProgressView(
timerInterval: timerInterval,
countsDown: false
)
}
.padding()
}
}

struct FoundationProgressViewExample: View {
private let progress: Progress

init() {
let progress = Progress(totalUnitCount: 100)
progress.completedUnitCount = 40
progress.localizedDescription = "Downloading"
progress.localizedAdditionalDescription = "40%"
self.progress = progress
}

var body: some View {
ProgressView(progress)
.padding()
}
}
4 changes: 4 additions & 0 deletions Sources/COpenSwiftUI/Shims/AppKit/AppKit_Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ typedef OPENSWIFTUI_ENUM(NSInteger, NSViewVibrantBlendingStyle) {
- (nullable NSAppearance *)appearanceByApplyingTintColor:(NSColor *)tintColor;
@end

@interface NSProgressIndicator (OpenSwiftUI_SPI)
@property (nullable, strong) NSFont *font;
@end

@interface NSMenu (OpenSwiftUI_SPI)
+ (void)_setAlwaysCallDelegateBeforeSidebandUpdaters_openswiftui_safe_wrapper:(BOOL)value OPENSWIFTUI_SWIFT_NAME(_setAlwaysCallDelegateBeforeSidebandUpdaters(_:));
+ (void)_setAlwaysInstallWindowTabItems_openswiftui_safe_wrapper:(BOOL)value OPENSWIFTUI_SWIFT_NAME(_setAlwaysInstallWindowTabItems(_:));
Expand Down
4 changes: 4 additions & 0 deletions Sources/COpenSwiftUI/Shims/UIKit/UIKit_Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ OPENSWIFTUI_ASSUME_NONNULL_BEGIN
@property(class, nonatomic, readonly) NSInteger _currentAnimationCurve_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(_currentAnimationCurve);
@end

@interface UIActivityIndicatorView (OpenSwiftUI_SPI)
- (void)_setCustomWidth:(CGFloat)width;
@end

@interface UIResponder (OpenSwiftUI_SPI)
- (void)_performMainMenuShortcutKeyCommand:(UIKeyCommand *)keyCommand; // FIXME
@end
Expand Down
33 changes: 33 additions & 0 deletions Sources/OpenSwiftUI/Accessibility/AccessibilityGeometry.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// AccessibilityGeometry.swift
// OpenSwiftUI
//
// Audited for 6.5.4
// Status: WIP
// ID: EE68159C4F54001FA5A3813EBA5DD945 (SwiftUI)

@_spi(Private)
import OpenSwiftUICore

// MARK: - IgnoreViewRespondersModifier

private struct IgnoreViewRespondersModifier: PrimitiveViewModifier, ViewInputsModifier {
nonisolated static func _makeViewInputs(
modifier _: _GraphValue<Self>,
inputs: inout _ViewInputs
) {
inputs.needsAccessibilityViewResponders = false
}
}

// MARK: - AccessibilityProgressViewModifier [WIP]

struct AccessibilityProgressViewModifier {
var fractionCompleted: Double?

func body<Content>(content: Content) -> some View where Content: View {
content
.modifier(IgnoreViewRespondersModifier())
// .modifier(AccessibilityAttachmentModifier())
}
}
14 changes: 1 addition & 13 deletions Sources/OpenSwiftUI/Data/Environment/PlatformEnvironment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,19 +125,7 @@ struct OpenSwiftUIFallbackFontProvider: FallbackFontProvider {

extension Font {
static func _system(controlSize: ControlSize) -> Font {
let nsControlSize: NSControl.ControlSize = switch controlSize {
case .mini: .mini
case .small: .small
case .regular: .regular
case .large: .large
case .extraLarge:
if #available(macOS 26, *) {
.extraLarge
} else {
.large
}
}
let size = NSFont.systemFontSize(for: nsControlSize)
let size = NSFont.systemFontSize(for: NSControl.ControlSize(controlSize))
return Font.system(size: size)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// AppKitConversions.swift
// OpenSwiftUI
//
// Audited for 6.5.4
// Status: WIP

#if canImport(AppKit)
import AppKit
import OpenSwiftUICore

// MARK: - ControlSize Conversions

extension NSControl.ControlSize {
init(_ controlSize: ControlSize) {
switch controlSize {
case .mini:
self = .mini
case .small:
self = .small
case .regular:
self = .regular
case .large:
self = .large
case .extraLarge:
if #available(macOS 26.0, *) {
self = .extraLarge
} else {
self = .large
}
}
}
}
#endif
21 changes: 21 additions & 0 deletions Sources/OpenSwiftUI/View/ArchivedView/ArchivableView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// ArchivableView.swift
// OpenSwiftUI
//
// Audited for 6.5.4
// Status: Blocked by ArchivableFactory

public import Foundation
public import OpenSwiftUICore

// MARK: - _ArchivableView [WIP]

protocol _ArchivableView: Codable, View {
func sizeThatFits(in proposedSize: _ProposedSize) -> CGSize
}

extension _ArchivableView {
func sizeThatFits(in proposedSize: _ProposedSize) -> CGSize {
proposedSize.fixingUnspecifiedDimensions()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//
// AppKitProgressView.swift
// OpenSwiftUI
//
// Audited for 6.5.4
// Status: Complete

#if os(macOS)
import AppKit
import COpenSwiftUI
import OpenSwiftUICore

// MARK: - AppKitProgressView

struct AppKitProgressView: NSViewRepresentable {
var fractionCompleted: Double?
var style: NSProgressIndicator.Style
var tint: Color?

@Environment(\.controlSize)
private var controlSize

@Environment(\.effectiveFont)
private var font

func makeNSView(context _: Context) -> NSProgressIndicator {
let nsView = NSProgressIndicator()
nsView.minValue = 0
nsView.maxValue = 1
return nsView
}

func updateNSView(_ nsView: NSProgressIndicator, context: Context) {
nsView.style = style
if fractionCompleted == nil {
nsView.startAnimation(nil)
} else {
nsView.stopAnimation(nil)
}
nsView.isIndeterminate = fractionCompleted == nil
nsView.doubleValue = fractionCompleted ?? 0

let controlSize = NSControl.ControlSize(controlSize)
if nsView.controlSize != controlSize {
nsView.controlSize = controlSize
}

nsView.font = font.platformFont(in: context.environment)
if let superview = nsView.superview {
let appearance = superview.effectiveAppearance
nsView.appearance = if let tint, tint != Color.accentColor {
appearance.applyingTintColor(.init(tint))
} else {
nil
}
}
}
}

// MARK: - LinearAppKitProgressView

struct LinearAppKitProgressView: View {
var configuration: ProgressViewStyleConfiguration
var tint: Color?

var body: some View {
switch configuration.value {
case let .absolute(fractionCompleted, _):
Base(
fractionCompleted: fractionCompleted,
tint: tint
)
case let .dateRelative(interval, countdown):
TimelineProgressView<Base>(
interval: interval,
updateStyle: .default,
countdown: countdown,
tint: tint,
isCircular: false,
extendedState: .init()
)
}
}

struct Base: TimelineProgressViewBase {
var fractionCompleted: Double?
var tint: Color?

init(fractionCompleted: Double?, tint: Color?) {
self.fractionCompleted = fractionCompleted
self.tint = tint
}

init(fractionCompleted: Double, tint: Color?) {
self.fractionCompleted = fractionCompleted
self.tint = tint
}

var body: some View {
AppKitProgressView(
fractionCompleted: fractionCompleted,
style: .bar,
tint: tint
)
}
}
}
#endif
Loading
Loading