Merge pull request #166 from SDWebImage/update_watchOS_demo_progressView
Update watchOS demo to watchOS 7, remove the custom indicator sample and use `ProgressView` instead
This commit is contained in:
commit
98372a776c
|
@ -23,6 +23,6 @@ target 'SDWebImageSwiftUIDemo-tvOS' do
|
||||||
end
|
end
|
||||||
|
|
||||||
target 'SDWebImageSwiftUIDemo-watchOS WatchKit Extension' do
|
target 'SDWebImageSwiftUIDemo-watchOS WatchKit Extension' do
|
||||||
platform :watchos, '6.0'
|
platform :watchos, '7.0'
|
||||||
all_pods
|
all_pods
|
||||||
end
|
end
|
|
@ -14,10 +14,6 @@
|
||||||
320CDC3222FADB45007CF858 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 320CDC3122FADB45007CF858 /* Assets.xcassets */; };
|
320CDC3222FADB45007CF858 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 320CDC3122FADB45007CF858 /* Assets.xcassets */; };
|
||||||
320CDC3522FADB45007CF858 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 320CDC3422FADB45007CF858 /* Preview Assets.xcassets */; };
|
320CDC3522FADB45007CF858 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 320CDC3422FADB45007CF858 /* Preview Assets.xcassets */; };
|
||||||
320CDC3822FADB45007CF858 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 320CDC3622FADB45007CF858 /* LaunchScreen.storyboard */; };
|
320CDC3822FADB45007CF858 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 320CDC3622FADB45007CF858 /* LaunchScreen.storyboard */; };
|
||||||
3243598423E05C3D006DF9C5 /* Espera.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3243598323E05C3D006DF9C5 /* Espera.swift */; };
|
|
||||||
3243598523E05C3D006DF9C5 /* Espera.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3243598323E05C3D006DF9C5 /* Espera.swift */; };
|
|
||||||
3243598623E05C3D006DF9C5 /* Espera.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3243598323E05C3D006DF9C5 /* Espera.swift */; };
|
|
||||||
3243598723E05C3D006DF9C5 /* Espera.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3243598323E05C3D006DF9C5 /* Espera.swift */; };
|
|
||||||
326B0D712345C01900D28269 /* DetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326B0D702345C01900D28269 /* DetailView.swift */; };
|
326B0D712345C01900D28269 /* DetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326B0D702345C01900D28269 /* DetailView.swift */; };
|
||||||
32E5290C2348A0C700EA46FF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32E5290B2348A0C700EA46FF /* AppDelegate.swift */; };
|
32E5290C2348A0C700EA46FF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32E5290B2348A0C700EA46FF /* AppDelegate.swift */; };
|
||||||
32E529102348A0C900EA46FF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 32E5290F2348A0C900EA46FF /* Assets.xcassets */; };
|
32E529102348A0C900EA46FF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 32E5290F2348A0C900EA46FF /* Assets.xcassets */; };
|
||||||
|
@ -98,7 +94,6 @@
|
||||||
320CDC3422FADB45007CF858 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
320CDC3422FADB45007CF858 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||||
320CDC3722FADB45007CF858 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
320CDC3722FADB45007CF858 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
320CDC3922FADB45007CF858 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
320CDC3922FADB45007CF858 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
3243598323E05C3D006DF9C5 /* Espera.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Espera.swift; sourceTree = "<group>"; };
|
|
||||||
326B0D702345C01900D28269 /* DetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailView.swift; sourceTree = "<group>"; };
|
326B0D702345C01900D28269 /* DetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailView.swift; sourceTree = "<group>"; };
|
||||||
32E529092348A0C700EA46FF /* SDWebImageSwiftUIDemo-macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SDWebImageSwiftUIDemo-macOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
32E529092348A0C700EA46FF /* SDWebImageSwiftUIDemo-macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SDWebImageSwiftUIDemo-macOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
32E5290B2348A0C700EA46FF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
32E5290B2348A0C700EA46FF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
@ -212,7 +207,6 @@
|
||||||
320CDC2D22FADB44007CF858 /* SceneDelegate.swift */,
|
320CDC2D22FADB44007CF858 /* SceneDelegate.swift */,
|
||||||
320CDC2F22FADB44007CF858 /* ContentView.swift */,
|
320CDC2F22FADB44007CF858 /* ContentView.swift */,
|
||||||
326B0D702345C01900D28269 /* DetailView.swift */,
|
326B0D702345C01900D28269 /* DetailView.swift */,
|
||||||
3243598323E05C3D006DF9C5 /* Espera.swift */,
|
|
||||||
320CDC3122FADB45007CF858 /* Assets.xcassets */,
|
320CDC3122FADB45007CF858 /* Assets.xcassets */,
|
||||||
320CDC3622FADB45007CF858 /* LaunchScreen.storyboard */,
|
320CDC3622FADB45007CF858 /* LaunchScreen.storyboard */,
|
||||||
320CDC3922FADB45007CF858 /* Info.plist */,
|
320CDC3922FADB45007CF858 /* Info.plist */,
|
||||||
|
@ -792,7 +786,6 @@
|
||||||
320CDC2C22FADB44007CF858 /* AppDelegate.swift in Sources */,
|
320CDC2C22FADB44007CF858 /* AppDelegate.swift in Sources */,
|
||||||
326B0D712345C01900D28269 /* DetailView.swift in Sources */,
|
326B0D712345C01900D28269 /* DetailView.swift in Sources */,
|
||||||
320CDC2E22FADB44007CF858 /* SceneDelegate.swift in Sources */,
|
320CDC2E22FADB44007CF858 /* SceneDelegate.swift in Sources */,
|
||||||
3243598423E05C3D006DF9C5 /* Espera.swift in Sources */,
|
|
||||||
320CDC3022FADB44007CF858 /* ContentView.swift in Sources */,
|
320CDC3022FADB44007CF858 /* ContentView.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -804,7 +797,6 @@
|
||||||
32E529622348A10B00EA46FF /* ContentView.swift in Sources */,
|
32E529622348A10B00EA46FF /* ContentView.swift in Sources */,
|
||||||
32E529632348A10B00EA46FF /* DetailView.swift in Sources */,
|
32E529632348A10B00EA46FF /* DetailView.swift in Sources */,
|
||||||
32E5290C2348A0C700EA46FF /* AppDelegate.swift in Sources */,
|
32E5290C2348A0C700EA46FF /* AppDelegate.swift in Sources */,
|
||||||
3243598523E05C3D006DF9C5 /* Espera.swift in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -815,7 +807,6 @@
|
||||||
32E529652348A10B00EA46FF /* ContentView.swift in Sources */,
|
32E529652348A10B00EA46FF /* ContentView.swift in Sources */,
|
||||||
32E529662348A10B00EA46FF /* DetailView.swift in Sources */,
|
32E529662348A10B00EA46FF /* DetailView.swift in Sources */,
|
||||||
32E529232348A0D300EA46FF /* AppDelegate.swift in Sources */,
|
32E529232348A0D300EA46FF /* AppDelegate.swift in Sources */,
|
||||||
3243598623E05C3D006DF9C5 /* Espera.swift in Sources */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -826,7 +817,6 @@
|
||||||
32E5294E2348A0DE00EA46FF /* HostingController.swift in Sources */,
|
32E5294E2348A0DE00EA46FF /* HostingController.swift in Sources */,
|
||||||
32E529692348A10C00EA46FF /* DetailView.swift in Sources */,
|
32E529692348A10C00EA46FF /* DetailView.swift in Sources */,
|
||||||
32E529502348A0DE00EA46FF /* ExtensionDelegate.swift in Sources */,
|
32E529502348A0DE00EA46FF /* ExtensionDelegate.swift in Sources */,
|
||||||
3243598723E05C3D006DF9C5 /* Espera.swift in Sources */,
|
|
||||||
32E529682348A10C00EA46FF /* ContentView.swift in Sources */,
|
32E529682348A10C00EA46FF /* ContentView.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -1102,7 +1092,7 @@
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = 4;
|
TARGETED_DEVICE_FAMILY = 4;
|
||||||
WATCHOS_DEPLOYMENT_TARGET = 6.0;
|
WATCHOS_DEPLOYMENT_TARGET = 7.0;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
@ -1132,7 +1122,7 @@
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = 4;
|
TARGETED_DEVICE_FAMILY = 4;
|
||||||
WATCHOS_DEPLOYMENT_TARGET = 6.0;
|
WATCHOS_DEPLOYMENT_TARGET = 7.0;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
@ -1163,7 +1153,7 @@
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = 4;
|
TARGETED_DEVICE_FAMILY = 4;
|
||||||
WATCHOS_DEPLOYMENT_TARGET = 6.0;
|
WATCHOS_DEPLOYMENT_TARGET = 7.0;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
@ -1191,7 +1181,7 @@
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = 4;
|
TARGETED_DEVICE_FAMILY = 4;
|
||||||
WATCHOS_DEPLOYMENT_TARGET = 6.0;
|
WATCHOS_DEPLOYMENT_TARGET = 7.0;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
@ -1217,6 +1207,7 @@
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
WATCHOS_DEPLOYMENT_TARGET = 7.0;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
@ -1239,6 +1230,7 @@
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "com.dreampiggy.SDWebImageSwiftUIDemo-watchOS";
|
PRODUCT_BUNDLE_IDENTIFIER = "com.dreampiggy.SDWebImageSwiftUIDemo-watchOS";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
WATCHOS_DEPLOYMENT_TARGET = 7.0;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
@ -1287,7 +1279,6 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
@ -1333,7 +1324,6 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||||
|
|
|
@ -54,10 +54,8 @@
|
||||||
debugDocumentVersioning = "YES"
|
debugDocumentVersioning = "YES"
|
||||||
debugServiceExtension = "internal"
|
debugServiceExtension = "internal"
|
||||||
allowLocationSimulation = "YES">
|
allowLocationSimulation = "YES">
|
||||||
<RemoteRunnable
|
<BuildableProductRunnable
|
||||||
runnableDebuggingMode = "2"
|
runnableDebuggingMode = "0">
|
||||||
BundleIdentifier = "com.apple.Carousel"
|
|
||||||
RemotePath = "/SDWebImageSwiftUIDemo-watchOS WatchKit App">
|
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "32E529362348A0DD00EA46FF"
|
BlueprintIdentifier = "32E529362348A0DD00EA46FF"
|
||||||
|
@ -65,7 +63,7 @@
|
||||||
BlueprintName = "SDWebImageSwiftUIDemo-watchOS WatchKit App"
|
BlueprintName = "SDWebImageSwiftUIDemo-watchOS WatchKit App"
|
||||||
ReferencedContainer = "container:SDWebImageSwiftUI.xcodeproj">
|
ReferencedContainer = "container:SDWebImageSwiftUI.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</RemoteRunnable>
|
</BuildableProductRunnable>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Release"
|
||||||
|
@ -73,10 +71,8 @@
|
||||||
savedToolIdentifier = ""
|
savedToolIdentifier = ""
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
debugDocumentVersioning = "YES">
|
debugDocumentVersioning = "YES">
|
||||||
<RemoteRunnable
|
<BuildableProductRunnable
|
||||||
runnableDebuggingMode = "2"
|
runnableDebuggingMode = "0">
|
||||||
BundleIdentifier = "com.apple.Carousel"
|
|
||||||
RemotePath = "/SDWebImageSwiftUIDemo-watchOS WatchKit App">
|
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "32E529362348A0DD00EA46FF"
|
BlueprintIdentifier = "32E529362348A0DD00EA46FF"
|
||||||
|
@ -84,16 +80,7 @@
|
||||||
BlueprintName = "SDWebImageSwiftUIDemo-watchOS WatchKit App"
|
BlueprintName = "SDWebImageSwiftUIDemo-watchOS WatchKit App"
|
||||||
ReferencedContainer = "container:SDWebImageSwiftUI.xcodeproj">
|
ReferencedContainer = "container:SDWebImageSwiftUI.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</RemoteRunnable>
|
</BuildableProductRunnable>
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "32E529362348A0DD00EA46FF"
|
|
||||||
BuildableName = "SDWebImageSwiftUIDemo-watchOS WatchKit App.app"
|
|
||||||
BlueprintName = "SDWebImageSwiftUIDemo-watchOS WatchKit App"
|
|
||||||
ReferencedContainer = "container:SDWebImageSwiftUI.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
</ProfileAction>
|
</ProfileAction>
|
||||||
<AnalyzeAction
|
<AnalyzeAction
|
||||||
buildConfiguration = "Debug">
|
buildConfiguration = "Debug">
|
||||||
|
|
|
@ -17,53 +17,20 @@ class UserSettings: ObservableObject {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if os(watchOS)
|
@available(iOS 14.0, OSX 11.0, tvOS 14.0, watchOS 7.0, *)
|
||||||
// watchOS does not provide built-in indicator, use Espera's custom indicator
|
extension Indicator where T == ProgressView<EmptyView, EmptyView> {
|
||||||
struct ActivityIndicator : View {
|
|
||||||
@Binding var isAnimating: Bool
|
|
||||||
var body: some View {
|
|
||||||
if isAnimating {
|
|
||||||
return AnyView(LoadingFlowerView()
|
|
||||||
.frame(width: 30, height: 30))
|
|
||||||
} else {
|
|
||||||
return AnyView(EmptyView()
|
|
||||||
.frame(width: 30, height: 30))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ProgressIndicator : View {
|
|
||||||
@Binding var isAnimating: Bool
|
|
||||||
@Binding var progress: Double
|
|
||||||
var body: some View {
|
|
||||||
if isAnimating {
|
|
||||||
return AnyView(StretchProgressView(progress: $progress)
|
|
||||||
.frame(width: 140, height: 10))
|
|
||||||
} else {
|
|
||||||
return AnyView(EmptyView()
|
|
||||||
.frame(width: 140, height: 10))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Indicator where T == ActivityIndicator {
|
|
||||||
/// Activity Indicator
|
|
||||||
static var activity: Indicator {
|
static var activity: Indicator {
|
||||||
Indicator { isAnimating, _ in
|
Indicator { isAnimating, progress in
|
||||||
ActivityIndicator(isAnimating: isAnimating)
|
ProgressView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
extension Indicator where T == ProgressIndicator {
|
|
||||||
/// Progress Indicator
|
|
||||||
static var progress: Indicator {
|
static var progress: Indicator {
|
||||||
Indicator { isAnimating, progress in
|
Indicator { isAnimating, progress in
|
||||||
ProgressIndicator(isAnimating: isAnimating, progress: progress)
|
ProgressView(value: progress.wrappedValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
@State var imageURLs = [
|
@State var imageURLs = [
|
||||||
|
|
|
@ -1,234 +0,0 @@
|
||||||
//
|
|
||||||
// Espera.swift
|
|
||||||
// Espera
|
|
||||||
//
|
|
||||||
// Created by jagcesar on 2019-12-29.
|
|
||||||
// Copyright © 2019 Ambi. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
public struct RotatingCircleWithGap: View {
|
|
||||||
@State private var angle: Double = 270
|
|
||||||
@State var isAnimating = false
|
|
||||||
private let lineWidth: CGFloat = 2
|
|
||||||
|
|
||||||
var foreverAnimation: Animation {
|
|
||||||
Animation.linear(duration: 1)
|
|
||||||
.repeatForever(autoreverses: false)
|
|
||||||
}
|
|
||||||
|
|
||||||
public init() { }
|
|
||||||
|
|
||||||
public var body: some View {
|
|
||||||
Circle()
|
|
||||||
.trim(from: 0.15, to: 1)
|
|
||||||
.stroke(Color.gray, style: StrokeStyle(lineWidth: self.lineWidth, lineCap: .round, lineJoin: CGLineJoin.round))
|
|
||||||
.rotationEffect((Angle(degrees: self.isAnimating ? 360.0 : 0)))
|
|
||||||
.padding(EdgeInsets(top: lineWidth/2, leading: lineWidth/2, bottom: lineWidth/2, trailing: lineWidth/2))
|
|
||||||
.animation(foreverAnimation)
|
|
||||||
.onAppear {
|
|
||||||
self.isAnimating = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct LoadingCircle: View {
|
|
||||||
let circleColor: Color
|
|
||||||
let scale: CGFloat
|
|
||||||
let circleWidth: CGFloat
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Circle()
|
|
||||||
.fill(circleColor)
|
|
||||||
.frame(width: circleWidth, height: circleWidth, alignment: .center)
|
|
||||||
.scaleEffect(scale)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct LoadingFlowerView: View {
|
|
||||||
|
|
||||||
private let animationDuration: Double = 0.6
|
|
||||||
private var singleCircleAnimationDuration: Double {
|
|
||||||
return animationDuration/3
|
|
||||||
}
|
|
||||||
private var foreverAnimation: Animation {
|
|
||||||
Animation.linear(duration: animationDuration)
|
|
||||||
.repeatForever(autoreverses: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private let originalColor: Color
|
|
||||||
public init(color: Color = .white) {
|
|
||||||
self.originalColor = color
|
|
||||||
self.color = color.opacity(0.3)
|
|
||||||
}
|
|
||||||
|
|
||||||
@State private var color = Color.white.opacity(0.3)
|
|
||||||
@State private var scale: CGFloat = 0.98
|
|
||||||
|
|
||||||
public var body: some View {
|
|
||||||
GeometryReader { [color, scale, singleCircleAnimationDuration, foreverAnimation] reader -> AnyView in
|
|
||||||
|
|
||||||
let minLength = min(reader.size.width, reader.size.height)
|
|
||||||
let thirdOfMinLength = minLength / 3
|
|
||||||
|
|
||||||
let proportionalSpacing: CGFloat = 1 / 26
|
|
||||||
let spacing = minLength * proportionalSpacing
|
|
||||||
|
|
||||||
// THIS IS FINE :D
|
|
||||||
// Fix later, ok?
|
|
||||||
let leafDiameter = thirdOfMinLength - (spacing - proportionalSpacing * thirdOfMinLength)
|
|
||||||
|
|
||||||
return AnyView(
|
|
||||||
HStack(spacing: spacing) {
|
|
||||||
VStack(spacing: spacing) {
|
|
||||||
LoadingCircle(circleColor: color, scale: scale, circleWidth: leafDiameter)
|
|
||||||
.animation(foreverAnimation.delay(singleCircleAnimationDuration*5))
|
|
||||||
LoadingCircle(circleColor: color, scale: scale, circleWidth: leafDiameter)
|
|
||||||
.animation(foreverAnimation.delay(singleCircleAnimationDuration*4))
|
|
||||||
}
|
|
||||||
VStack(alignment: .center, spacing: spacing) {
|
|
||||||
LoadingCircle(circleColor: color, scale: scale, circleWidth: leafDiameter)
|
|
||||||
.animation(foreverAnimation)
|
|
||||||
LoadingCircle(circleColor: .clear, scale: 1, circleWidth: leafDiameter)
|
|
||||||
LoadingCircle(circleColor: color, scale: scale, circleWidth: leafDiameter)
|
|
||||||
.animation(foreverAnimation.delay(singleCircleAnimationDuration*3))
|
|
||||||
}
|
|
||||||
VStack(alignment: .center, spacing: spacing) {
|
|
||||||
LoadingCircle(circleColor: color, scale: scale, circleWidth: leafDiameter)
|
|
||||||
.animation(foreverAnimation.delay(singleCircleAnimationDuration*1))
|
|
||||||
LoadingCircle(circleColor: color, scale: scale, circleWidth: leafDiameter)
|
|
||||||
.animation(foreverAnimation.delay(singleCircleAnimationDuration*2))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.onAppear {
|
|
||||||
self.color = self.originalColor
|
|
||||||
self.scale = 1
|
|
||||||
}
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
.frame(idealWidth: 26)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class StretchyShapeModel {
|
|
||||||
var forwards = true
|
|
||||||
}
|
|
||||||
|
|
||||||
extension StretchyShape {
|
|
||||||
enum Side {
|
|
||||||
case front, back
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Mode {
|
|
||||||
case lagged, stretchy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct StretchyShape: Shape {
|
|
||||||
|
|
||||||
var progress: Double
|
|
||||||
var mode: Mode
|
|
||||||
init(progress: Double, mode: Mode = .lagged) {
|
|
||||||
self.progress = progress
|
|
||||||
self.mode = mode
|
|
||||||
}
|
|
||||||
|
|
||||||
private var model = StretchyShapeModel()
|
|
||||||
|
|
||||||
func path(in rect: CGRect) -> Path {
|
|
||||||
Path { path in
|
|
||||||
|
|
||||||
addSide(.back, to: &path, rect: rect)
|
|
||||||
addSide(.front, to: &path, rect: rect)
|
|
||||||
|
|
||||||
if progress >= 1 {
|
|
||||||
model.forwards.toggle()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var animatableData: Double {
|
|
||||||
set { progress = newValue }
|
|
||||||
get { progress }
|
|
||||||
}
|
|
||||||
|
|
||||||
private func easeInOutQuad(_ x: CGFloat) -> CGFloat {
|
|
||||||
if x <= 0.5 {
|
|
||||||
return pow(x, 2) * 2
|
|
||||||
}
|
|
||||||
|
|
||||||
let x = x - 0.5
|
|
||||||
return 2 * x * (1 - x) + 0.5
|
|
||||||
}
|
|
||||||
|
|
||||||
private func addSide(_ side: Side, to path: inout Path, rect: CGRect) {
|
|
||||||
let lag = 0.1
|
|
||||||
|
|
||||||
let laggedProgress: CGFloat
|
|
||||||
let startAngle: Angle
|
|
||||||
let endAngle: Angle
|
|
||||||
switch side {
|
|
||||||
case .front:
|
|
||||||
laggedProgress = CGFloat(progress + lag)
|
|
||||||
startAngle = Angle(degrees: 90)
|
|
||||||
endAngle = Angle(degrees: -90)
|
|
||||||
case .back:
|
|
||||||
if mode == .stretchy {
|
|
||||||
laggedProgress = 0
|
|
||||||
} else {
|
|
||||||
laggedProgress = CGFloat(progress - lag)
|
|
||||||
}
|
|
||||||
startAngle = Angle(degrees: -90)
|
|
||||||
endAngle = Angle(degrees: 90)
|
|
||||||
}
|
|
||||||
|
|
||||||
var progress = max(0, min(1, laggedProgress))
|
|
||||||
|
|
||||||
if !model.forwards {
|
|
||||||
progress = 1 - progress
|
|
||||||
}
|
|
||||||
|
|
||||||
let radius = rect.height / 2
|
|
||||||
let offset = easeInOutQuad(progress) * (rect.width - rect.height)
|
|
||||||
|
|
||||||
path.addArc(center: CGPoint(x: radius + offset, y: radius), radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: model.forwards)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct StretchLoadingView: View {
|
|
||||||
|
|
||||||
@State private var progress: Double = 0
|
|
||||||
|
|
||||||
public init() { }
|
|
||||||
|
|
||||||
public var body: some View {
|
|
||||||
StretchyShape(progress: progress)
|
|
||||||
.animation(Animation.linear(duration: 0.6).repeatForever(autoreverses: false))
|
|
||||||
.onAppear {
|
|
||||||
withAnimation {
|
|
||||||
self.progress = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct StretchProgressView: View {
|
|
||||||
|
|
||||||
@Binding public var progress: Double
|
|
||||||
|
|
||||||
public var body: some View {
|
|
||||||
StretchyShape(progress: progress, mode: .stretchy)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
Group {
|
|
||||||
RotatingCircleWithGap()
|
|
||||||
LoadingFlowerView()
|
|
||||||
StretchLoadingView().frame(width: 60, height: 14)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
15
README.md
15
README.md
|
@ -149,7 +149,9 @@ var body: some View {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: This `WebImage` using `Image` for internal implementation, which is the best compatible for SwiftUI layout and animation system. But unlike SwiftUI's `Image` which does not support animated image or vector image, `WebImage` supports animated image as well (by defaults from v1.6.0)
|
Note: This `WebImage` using `Image` for internal implementation, which is the best compatible for SwiftUI layout and animation system. But unlike SwiftUI's `Image` which does not support animated image or vector image, `WebImage` supports animated image as well (by defaults from v1.6.0).
|
||||||
|
|
||||||
|
However, The `WebImage` animation provide simple common use case, so it's still recommend to use `AnimatedImage` for advanced controls like progressive animation rendering, or vector image rendering.
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
@State var isAnimating: Bool = true
|
@State var isAnimating: Bool = true
|
||||||
|
@ -162,7 +164,16 @@ var body: some View {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: The `WebImage` animation provide common use case, so it's still recommend to use `AnimatedImage` for advanced controls like progressive animation rendering, or vector image rendering. In a word, `WebImage` can render animated image, but not always the best choice.
|
Note: For indicator, you can custom your own as well. For example, iOS 14/watchOS 7 introduce the new `ProgressView`, which can replace our built-in `ProgressIndicator/ActivityIndicator` (where watchOS does not provide).
|
||||||
|
|
||||||
|
```swift
|
||||||
|
WebImage(url: url)
|
||||||
|
.indicator {
|
||||||
|
Indicator { _, _ in
|
||||||
|
ProgressView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Using `AnimatedImage` to play animation
|
### Using `AnimatedImage` to play animation
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue