Add ProgressView (#425)
This adds `ProgressView` using the `<progress>` tag on the web. * Add ProgressView implementation * Fix native demo * Enable Foundation.Progress in non-WASI environments * Fix wasm build * Update progress coc * Improve snapshot copy error handling * Use RenderingTests as directory name * Fix snapshots CI script * Make test failures fail the CI job * Snapshot script debugging * Copy failed snapshots in a different way * Call `exit 1` when tests fail * Use correct directory in the upload step * Update test image * Update .github/workflows/ci.yml Co-authored-by: ezraberch <49635435+ezraberch@users.noreply.github.com> Co-authored-by: Max Desiatov <max@desiatov.com>
This commit is contained in:
parent
ab5e564ada
commit
12a6256ec0
|
@ -37,7 +37,7 @@ jobs:
|
||||||
# avoid building unrelated products for testing by specifying the test product explicitly
|
# avoid building unrelated products for testing by specifying the test product explicitly
|
||||||
swift build --product TokamakPackageTests
|
swift build --product TokamakPackageTests
|
||||||
`xcrun --find xctest` .build/debug/TokamakPackageTests.xctest ||
|
`xcrun --find xctest` .build/debug/TokamakPackageTests.xctest ||
|
||||||
find /var/folders -iname SnapshotTests -exec cp -r {} . \;
|
(cp -r `find /var/folders -iname RenderingTests` . ; exit 1)
|
||||||
|
|
||||||
rm -rf Sources/TokamakGTKCHelpers/*.c
|
rm -rf Sources/TokamakGTKCHelpers/*.c
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ jobs:
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
with:
|
with:
|
||||||
name: Failed snapshots
|
name: Failed snapshots
|
||||||
path: SnapshotTests
|
path: RenderingTests
|
||||||
|
|
||||||
gtk_macos_build:
|
gtk_macos_build:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
207C05712610E16E00BBBE54 /* DatePickerDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 207C056F2610E16E00BBBE54 /* DatePickerDemo.swift */; };
|
207C05712610E16E00BBBE54 /* DatePickerDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 207C056F2610E16E00BBBE54 /* DatePickerDemo.swift */; };
|
||||||
262DA7B32695D99500CABEAE /* ShapeStyleDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 262DA7B22695D99500CABEAE /* ShapeStyleDemo.swift */; };
|
262DA7B32695D99500CABEAE /* ShapeStyleDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 262DA7B22695D99500CABEAE /* ShapeStyleDemo.swift */; };
|
||||||
262DA7B42695D99500CABEAE /* ShapeStyleDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 262DA7B22695D99500CABEAE /* ShapeStyleDemo.swift */; };
|
262DA7B42695D99500CABEAE /* ShapeStyleDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 262DA7B22695D99500CABEAE /* ShapeStyleDemo.swift */; };
|
||||||
|
26AC04B62698D33A0057784E /* ProgressViewDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26AC04B52698D33A0057784E /* ProgressViewDemo.swift */; };
|
||||||
|
26AC04B72698D33A0057784E /* ProgressViewDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26AC04B52698D33A0057784E /* ProgressViewDemo.swift */; };
|
||||||
26A3BFB0269BD18A0004DA16 /* AnimationDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26A3BFAF269BD18A0004DA16 /* AnimationDemo.swift */; };
|
26A3BFB0269BD18A0004DA16 /* AnimationDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26A3BFAF269BD18A0004DA16 /* AnimationDemo.swift */; };
|
||||||
26A3BFB1269BD18A0004DA16 /* AnimationDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26A3BFAF269BD18A0004DA16 /* AnimationDemo.swift */; };
|
26A3BFB1269BD18A0004DA16 /* AnimationDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26A3BFAF269BD18A0004DA16 /* AnimationDemo.swift */; };
|
||||||
3DCDE44424CA6AD400910F17 /* SidebarDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCDE44324CA6AD400910F17 /* SidebarDemo.swift */; };
|
3DCDE44424CA6AD400910F17 /* SidebarDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCDE44324CA6AD400910F17 /* SidebarDemo.swift */; };
|
||||||
|
@ -102,6 +104,7 @@
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
207C056F2610E16E00BBBE54 /* DatePickerDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatePickerDemo.swift; sourceTree = "<group>"; };
|
207C056F2610E16E00BBBE54 /* DatePickerDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatePickerDemo.swift; sourceTree = "<group>"; };
|
||||||
262DA7B22695D99500CABEAE /* ShapeStyleDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShapeStyleDemo.swift; sourceTree = "<group>"; };
|
262DA7B22695D99500CABEAE /* ShapeStyleDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShapeStyleDemo.swift; sourceTree = "<group>"; };
|
||||||
|
26AC04B52698D33A0057784E /* ProgressViewDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressViewDemo.swift; sourceTree = "<group>"; };
|
||||||
26A3BFAF269BD18A0004DA16 /* AnimationDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationDemo.swift; sourceTree = "<group>"; };
|
26A3BFAF269BD18A0004DA16 /* AnimationDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationDemo.swift; sourceTree = "<group>"; };
|
||||||
3DCDE44324CA6AD400910F17 /* SidebarDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SidebarDemo.swift; sourceTree = "<group>"; };
|
3DCDE44324CA6AD400910F17 /* SidebarDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SidebarDemo.swift; sourceTree = "<group>"; };
|
||||||
4550BD5125B642B80088F4EA /* ShadowDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShadowDemo.swift; sourceTree = "<group>"; };
|
4550BD5125B642B80088F4EA /* ShadowDemo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShadowDemo.swift; sourceTree = "<group>"; };
|
||||||
|
@ -214,6 +217,7 @@
|
||||||
B51F214F24B920B400CF2583 /* PathDemo.swift */,
|
B51F214F24B920B400CF2583 /* PathDemo.swift */,
|
||||||
D1EE7EA624C0DD2100C0D127 /* PickerDemo.swift */,
|
D1EE7EA624C0DD2100C0D127 /* PickerDemo.swift */,
|
||||||
B5F2BE022571443D00FB3653 /* PreferenceKeyDemo.swift */,
|
B5F2BE022571443D00FB3653 /* PreferenceKeyDemo.swift */,
|
||||||
|
26AC04B52698D33A0057784E /* ProgressViewDemo.swift */,
|
||||||
B5DBA22A24D509B4003D3347 /* RedactDemo.swift */,
|
B5DBA22A24D509B4003D3347 /* RedactDemo.swift */,
|
||||||
3DCDE44324CA6AD400910F17 /* SidebarDemo.swift */,
|
3DCDE44324CA6AD400910F17 /* SidebarDemo.swift */,
|
||||||
8500293E24D2FF3E001A2E84 /* SliderDemo.swift */,
|
8500293E24D2FF3E001A2E84 /* SliderDemo.swift */,
|
||||||
|
@ -394,6 +398,7 @@
|
||||||
D1C726F324CB63C6003B576D /* ButtonStyleDemo.swift in Sources */,
|
D1C726F324CB63C6003B576D /* ButtonStyleDemo.swift in Sources */,
|
||||||
854A1A9124B3E3630027BC32 /* ToggleDemo.swift in Sources */,
|
854A1A9124B3E3630027BC32 /* ToggleDemo.swift in Sources */,
|
||||||
85ED18A524AD425E0085DFA0 /* TextDemo.swift in Sources */,
|
85ED18A524AD425E0085DFA0 /* TextDemo.swift in Sources */,
|
||||||
|
26AC04B62698D33A0057784E /* ProgressViewDemo.swift in Sources */,
|
||||||
85ED18AB24AD425E0085DFA0 /* Counter.swift in Sources */,
|
85ED18AB24AD425E0085DFA0 /* Counter.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -429,6 +434,7 @@
|
||||||
D1C726F424CB63C6003B576D /* ButtonStyleDemo.swift in Sources */,
|
D1C726F424CB63C6003B576D /* ButtonStyleDemo.swift in Sources */,
|
||||||
854A1A9324B3F28F0027BC32 /* ToggleDemo.swift in Sources */,
|
854A1A9324B3F28F0027BC32 /* ToggleDemo.swift in Sources */,
|
||||||
85ED18AE24AD425E0085DFA0 /* TextFieldDemo.swift in Sources */,
|
85ED18AE24AD425E0085DFA0 /* TextFieldDemo.swift in Sources */,
|
||||||
|
26AC04B72698D33A0057784E /* ProgressViewDemo.swift in Sources */,
|
||||||
85ED18A624AD425E0085DFA0 /* TextDemo.swift in Sources */,
|
85ED18A624AD425E0085DFA0 /* TextDemo.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|
|
@ -0,0 +1,212 @@
|
||||||
|
// Copyright 2020 Tokamak contributors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Created by Carson Katri on 7/9/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public struct ProgressView<Label, CurrentValueLabel>: View
|
||||||
|
where Label: View, CurrentValueLabel: View
|
||||||
|
{
|
||||||
|
let storage: Storage
|
||||||
|
|
||||||
|
enum Storage {
|
||||||
|
case custom(_CustomProgressView<Label, CurrentValueLabel>)
|
||||||
|
case foundation(_FoundationProgressView)
|
||||||
|
}
|
||||||
|
|
||||||
|
public var body: some View {
|
||||||
|
switch storage {
|
||||||
|
case let .custom(custom): custom
|
||||||
|
case let .foundation(foundation): foundation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct _CustomProgressView<Label, CurrentValueLabel>: View
|
||||||
|
where Label: View, CurrentValueLabel: View
|
||||||
|
{
|
||||||
|
var fractionCompleted: Double?
|
||||||
|
var label: Label?
|
||||||
|
var currentValueLabel: CurrentValueLabel?
|
||||||
|
|
||||||
|
@Environment(\.progressViewStyle) var style
|
||||||
|
|
||||||
|
init(
|
||||||
|
fractionCompleted: Double?,
|
||||||
|
label: Label?,
|
||||||
|
currentValueLabel: CurrentValueLabel?
|
||||||
|
) {
|
||||||
|
self.fractionCompleted = fractionCompleted
|
||||||
|
self.label = label
|
||||||
|
self.currentValueLabel = currentValueLabel
|
||||||
|
}
|
||||||
|
|
||||||
|
public var body: some View {
|
||||||
|
style.makeBody(
|
||||||
|
configuration: .init(
|
||||||
|
fractionCompleted: fractionCompleted,
|
||||||
|
label: label.map { .init(body: AnyView($0)) },
|
||||||
|
currentValueLabel: currentValueLabel.map { .init(body: AnyView($0)) }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if os(WASI)
|
||||||
|
public struct _FoundationProgressView: View {
|
||||||
|
public var body: Never {
|
||||||
|
fatalError("`Foundation.Progress` is not available.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
public struct _FoundationProgressView: View {
|
||||||
|
let progress: Progress
|
||||||
|
@State private var state: ProgressState?
|
||||||
|
|
||||||
|
struct ProgressState {
|
||||||
|
var progress: Double
|
||||||
|
var isIndeterminate: Bool
|
||||||
|
var description: String
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_ progress: Progress) {
|
||||||
|
self.progress = progress
|
||||||
|
}
|
||||||
|
|
||||||
|
public var body: some View {
|
||||||
|
ProgressView(
|
||||||
|
value: progress.isIndeterminate ? nil : progress.fractionCompleted
|
||||||
|
) {
|
||||||
|
Text("\(Int(progress.fractionCompleted * 100))% completed")
|
||||||
|
} currentValueLabel: {
|
||||||
|
Text("\(progress.completedUnitCount)/\(progress.totalUnitCount)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Override in renderers to provide a default body for determinate progress views.
|
||||||
|
public struct _FractionalProgressView: _PrimitiveView {
|
||||||
|
public let fractionCompleted: Double
|
||||||
|
init(_ fractionCompleted: Double) {
|
||||||
|
self.fractionCompleted = fractionCompleted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Override in renderers to provide a default body for indeterminate progress views.
|
||||||
|
public struct _IndeterminateProgressView: _PrimitiveView {}
|
||||||
|
|
||||||
|
public extension ProgressView where CurrentValueLabel == EmptyView {
|
||||||
|
init() where Label == EmptyView {
|
||||||
|
self.init(storage: .custom(
|
||||||
|
.init(fractionCompleted: nil, label: nil, currentValueLabel: nil)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
init(@ViewBuilder label: () -> Label) {
|
||||||
|
self.init(storage: .custom(
|
||||||
|
.init(fractionCompleted: nil, label: label(), currentValueLabel: nil)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
init<S>(_ title: S) where Label == Text, S: StringProtocol {
|
||||||
|
self.init {
|
||||||
|
Text(title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension ProgressView {
|
||||||
|
init<V>(
|
||||||
|
value: V?,
|
||||||
|
total: V = 1.0
|
||||||
|
) where Label == EmptyView, CurrentValueLabel == EmptyView, V: BinaryFloatingPoint {
|
||||||
|
self.init(storage: .custom(
|
||||||
|
.init(
|
||||||
|
fractionCompleted: value.map { Double($0 / total) },
|
||||||
|
label: nil,
|
||||||
|
currentValueLabel: nil
|
||||||
|
)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
init<V>(
|
||||||
|
value: V?,
|
||||||
|
total: V = 1.0,
|
||||||
|
@ViewBuilder label: () -> Label
|
||||||
|
) where CurrentValueLabel == EmptyView, V: BinaryFloatingPoint {
|
||||||
|
self.init(storage: .custom(
|
||||||
|
.init(
|
||||||
|
fractionCompleted: value.map { Double($0 / total) },
|
||||||
|
label: label(),
|
||||||
|
currentValueLabel: nil
|
||||||
|
)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
init<V>(
|
||||||
|
value: V?,
|
||||||
|
total: V = 1.0,
|
||||||
|
@ViewBuilder label: () -> Label,
|
||||||
|
@ViewBuilder currentValueLabel: () -> CurrentValueLabel
|
||||||
|
) where V: BinaryFloatingPoint {
|
||||||
|
self.init(storage: .custom(
|
||||||
|
.init(
|
||||||
|
fractionCompleted: value.map { Double($0 / total) },
|
||||||
|
label: label(),
|
||||||
|
currentValueLabel: currentValueLabel()
|
||||||
|
)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
init<S, V>(
|
||||||
|
_ title: S,
|
||||||
|
value: V?,
|
||||||
|
total: V = 1.0
|
||||||
|
) where Label == Text, CurrentValueLabel == EmptyView, S: StringProtocol, V: BinaryFloatingPoint {
|
||||||
|
self.init(
|
||||||
|
value: value,
|
||||||
|
total: total
|
||||||
|
) {
|
||||||
|
Text(title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !os(WASI)
|
||||||
|
public extension ProgressView {
|
||||||
|
init(_ progress: Progress) where Label == EmptyView, CurrentValueLabel == EmptyView {
|
||||||
|
self.init(storage: .foundation(.init(progress)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public extension ProgressView {
|
||||||
|
init(_ configuration: ProgressViewStyleConfiguration)
|
||||||
|
where Label == ProgressViewStyleConfiguration.Label,
|
||||||
|
CurrentValueLabel == ProgressViewStyleConfiguration.CurrentValueLabel
|
||||||
|
{
|
||||||
|
self.init(value: configuration.fractionCompleted) {
|
||||||
|
ProgressViewStyleConfiguration.Label(
|
||||||
|
body: AnyView(configuration.label)
|
||||||
|
)
|
||||||
|
} currentValueLabel: {
|
||||||
|
ProgressViewStyleConfiguration.CurrentValueLabel(
|
||||||
|
body: AnyView(configuration.currentValueLabel)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
// Copyright 2020 Tokamak contributors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Created by Carson Katri on 7/9/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
public protocol ProgressViewStyle {
|
||||||
|
associatedtype Body: View
|
||||||
|
typealias Configuration = ProgressViewStyleConfiguration
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
func makeBody(configuration: Self.Configuration) -> Self.Body
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ProgressViewStyleConfiguration {
|
||||||
|
public struct Label: View {
|
||||||
|
public let body: AnyView
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct CurrentValueLabel: View {
|
||||||
|
public let body: AnyView
|
||||||
|
}
|
||||||
|
|
||||||
|
public let fractionCompleted: Double?
|
||||||
|
public var label: ProgressViewStyleConfiguration.Label?
|
||||||
|
public var currentValueLabel: ProgressViewStyleConfiguration.CurrentValueLabel?
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct DefaultProgressViewStyle: ProgressViewStyle {
|
||||||
|
public init() {}
|
||||||
|
public func makeBody(configuration: Configuration) -> some View {
|
||||||
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
|
HStack { Spacer() }
|
||||||
|
configuration.label
|
||||||
|
.foregroundStyle(PrimaryContentStyle())
|
||||||
|
if let fractionCompleted = configuration.fractionCompleted {
|
||||||
|
_FractionalProgressView(fractionCompleted)
|
||||||
|
} else {
|
||||||
|
_IndeterminateProgressView()
|
||||||
|
}
|
||||||
|
configuration.currentValueLabel
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundStyle(PrimaryContentStyle())
|
||||||
|
.opacity(0.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct _AnyProgressViewStyle: ProgressViewStyle {
|
||||||
|
public typealias Body = AnyView
|
||||||
|
|
||||||
|
private let bodyClosure: (ProgressViewStyleConfiguration) -> AnyView
|
||||||
|
public let type: Any.Type
|
||||||
|
|
||||||
|
public init<S: ProgressViewStyle>(_ style: S) {
|
||||||
|
type = S.self
|
||||||
|
bodyClosure = { configuration in
|
||||||
|
AnyView(style.makeBody(configuration: configuration))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeBody(configuration: ProgressViewStyleConfiguration) -> AnyView {
|
||||||
|
bodyClosure(configuration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension EnvironmentValues {
|
||||||
|
private enum ProgressViewStyleKey: EnvironmentKey {
|
||||||
|
static let defaultValue = _AnyProgressViewStyle(DefaultProgressViewStyle())
|
||||||
|
}
|
||||||
|
|
||||||
|
var progressViewStyle: _AnyProgressViewStyle {
|
||||||
|
get {
|
||||||
|
self[ProgressViewStyleKey.self]
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
self[ProgressViewStyleKey.self] = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension View {
|
||||||
|
func progressViewStyle<S>(_ style: S) -> some View where S: ProgressViewStyle {
|
||||||
|
environment(\.progressViewStyle, .init(style))
|
||||||
|
}
|
||||||
|
}
|
|
@ -130,6 +130,7 @@ public typealias NavigationLink = TokamakCore.NavigationLink
|
||||||
public typealias NavigationView = TokamakCore.NavigationView
|
public typealias NavigationView = TokamakCore.NavigationView
|
||||||
public typealias OutlineGroup = TokamakCore.OutlineGroup
|
public typealias OutlineGroup = TokamakCore.OutlineGroup
|
||||||
public typealias Picker = TokamakCore.Picker
|
public typealias Picker = TokamakCore.Picker
|
||||||
|
public typealias ProgressView = TokamakCore.ProgressView
|
||||||
public typealias ScrollView = TokamakCore.ScrollView
|
public typealias ScrollView = TokamakCore.ScrollView
|
||||||
public typealias Section = TokamakCore.Section
|
public typealias Section = TokamakCore.Section
|
||||||
public typealias SecureField = TokamakCore.SecureField
|
public typealias SecureField = TokamakCore.SecureField
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright 2020 Tokamak contributors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Created by Carson Katri on 7/9/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import TokamakShim
|
||||||
|
|
||||||
|
struct ProgressViewDemo: View {
|
||||||
|
@State private var progress = 0.5
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
HStack { Spacer() }
|
||||||
|
|
||||||
|
ProgressView("Indeterminate")
|
||||||
|
ProgressView(value: progress) {
|
||||||
|
Text("Determinate")
|
||||||
|
} currentValueLabel: {
|
||||||
|
Text("\(progress)")
|
||||||
|
}
|
||||||
|
ProgressView("Increased Total", value: progress, total: 2)
|
||||||
|
Button("Make Progress") { progress += 0.1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -138,6 +138,7 @@ struct TokamakDemoView: View {
|
||||||
Section(header: Text("Misc")) {
|
Section(header: Text("Misc")) {
|
||||||
NavItem("Animation", destination: AnimationDemo())
|
NavItem("Animation", destination: AnimationDemo())
|
||||||
NavItem("Path", destination: PathDemo())
|
NavItem("Path", destination: PathDemo())
|
||||||
|
NavItem("ProgressView", destination: ProgressViewDemo())
|
||||||
NavItem("Environment", destination: EnvironmentDemo().font(.system(size: 8)))
|
NavItem("Environment", destination: EnvironmentDemo().font(.system(size: 8)))
|
||||||
if #available(macOS 11.0, iOS 14.0, *) {
|
if #available(macOS 11.0, iOS 14.0, *) {
|
||||||
NavItem("Preferences", destination: PreferenceKeyDemo())
|
NavItem("Preferences", destination: PreferenceKeyDemo())
|
||||||
|
|
|
@ -75,6 +75,7 @@ public typealias HStack = TokamakCore.HStack
|
||||||
public typealias LazyHGrid = TokamakCore.LazyHGrid
|
public typealias LazyHGrid = TokamakCore.LazyHGrid
|
||||||
public typealias LazyVGrid = TokamakCore.LazyVGrid
|
public typealias LazyVGrid = TokamakCore.LazyVGrid
|
||||||
public typealias List = TokamakCore.List
|
public typealias List = TokamakCore.List
|
||||||
|
public typealias ProgressView = TokamakCore.ProgressView
|
||||||
public typealias ScrollView = TokamakCore.ScrollView
|
public typealias ScrollView = TokamakCore.ScrollView
|
||||||
public typealias Section = TokamakCore.Section
|
public typealias Section = TokamakCore.Section
|
||||||
public typealias Spacer = TokamakCore.Spacer
|
public typealias Spacer = TokamakCore.Spacer
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright 2020 Tokamak contributors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
// Created by Carson Katri on 7/9/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import TokamakCore
|
||||||
|
|
||||||
|
extension _FractionalProgressView: _HTMLPrimitive {
|
||||||
|
public var renderedBody: AnyView {
|
||||||
|
AnyView(
|
||||||
|
HTML("progress", [
|
||||||
|
"value": "\(fractionCompleted)",
|
||||||
|
"style": "width: 100%;",
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension _IndeterminateProgressView: _HTMLPrimitive {
|
||||||
|
public var renderedBody: AnyView {
|
||||||
|
AnyView(
|
||||||
|
HTML("progress", ["style": "width: 100%;"])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -255,6 +255,21 @@ final class RenderingTests: XCTestCase {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testProgressView() {
|
||||||
|
assertSnapshot(
|
||||||
|
matching: VStack(spacing: 0) {
|
||||||
|
ProgressView(value: 0.5) {
|
||||||
|
Text("Loading")
|
||||||
|
} currentValueLabel: {
|
||||||
|
Text("0.5")
|
||||||
|
}
|
||||||
|
ProgressView(Progress(totalUnitCount: 3))
|
||||||
|
},
|
||||||
|
as: .image(size: .init(width: 200, height: 200)),
|
||||||
|
timeout: defaultSnapshotTimeout
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func testAspectRatio() {
|
func testAspectRatio() {
|
||||||
assertSnapshot(
|
assertSnapshot(
|
||||||
matching: Ellipse()
|
matching: Ellipse()
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
|
@ -53,7 +53,7 @@ Table columns:
|
||||||
|
|
||||||
| | | |
|
| | | |
|
||||||
| --- | ------------------------------------------------------------------------------ | :-: |
|
| --- | ------------------------------------------------------------------------------ | :-: |
|
||||||
| | [ProgressView](https://developer.apple.com/documentation/swiftui/progressview) | |
|
| 🚧 | [ProgressView](https://developer.apple.com/documentation/swiftui/progressview) | |
|
||||||
| | [Gauge](https://developer.apple.com/documentation/swiftui/gauge) | |
|
| | [Gauge](https://developer.apple.com/documentation/swiftui/gauge) | |
|
||||||
| | [Label](https://developer.apple.com/documentation/swiftui/label) | |
|
| | [Label](https://developer.apple.com/documentation/swiftui/label) | |
|
||||||
| ✅ | [Link](https://developer.apple.com/documentation/swiftui/link) | |
|
| ✅ | [Link](https://developer.apple.com/documentation/swiftui/link) | |
|
||||||
|
|
Loading…
Reference in New Issue