Created
March 20, 2023 15:14
-
-
Save DarrenHurst/280a83515909496c064694ed3140d23b to your computer and use it in GitHub Desktop.
ErrorExample
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import SwiftUI | |
import PhotosUI | |
@available(iOS 16.0, *) | |
struct Photos: View { | |
@ObservedObject var viewModel = PhotosModel() | |
@State var selectedItems: PhotosPickerItem? | |
enum ImageState { | |
case empty, loading(Progress), success(Image), failure(Error) | |
} | |
@State var profileImage: ErrorExample? | |
var body: some View { | |
VStack{ | |
VStack { | |
ErrorExample(imageState: viewModel.imageState) | |
}.shadow(radius: 5) | |
PhotosPicker(selection: $viewModel.imageSelection, matching: .images, photoLibrary: .shared()) { | |
Image(systemName: "pencil.circle.fill") | |
.symbolRenderingMode(.multicolor) | |
.font(.system(size: 40)) | |
.foregroundColor(.accentColor) | |
Text("Select Resolution Image").foregroundColor(.black) | |
}.padding(.top, 20) | |
} | |
} | |
} | |
@available(iOS 16.0, *) | |
struct ErrorExample: View { | |
@State var blink: Bool = false | |
let imageState: PhotosModel.ImageState | |
var body: some View { | |
switch imageState { | |
case .empty: | |
triangleError().controlSize(.small) | |
Text("Level 3 Error: Line 1").foregroundColor(.black) | |
case .loading: | |
ProgressView() | |
case let .success(image): | |
image.resizable() | |
.scaledToFit() | |
.shadow(color: .black, radius: 5) | |
case .failure: | |
triangleError().scaledToFit() | |
} | |
} | |
} | |
@available(iOS 16.0, *) | |
extension ErrorExample { | |
fileprivate func emptyViewState() -> some View { | |
ZStack { | |
ZStack { | |
Circle() | |
.fill(RadialGradient.init(colors: [.pink.opacity(0.8), .clear.opacity(1), .red.opacity(1.9)], center: .top, startRadius: 10.0, endRadius: 90.0)) | |
//.rotationEffect(blink ? Angle(degrees: 0.0) : Angle(degrees: 45.0)) | |
.opacity(blink ? 1 : 0.9) | |
.animation(.default.speed(0.5).repeatForever(), value: blink) | |
Circle().fill().frame(height: 5).offset(x: -1, y: 10) | |
Circle().fill().frame(height: 5).offset(x: 3, y: -10) | |
Circle().stroke(style: StrokeStyle(lineWidth: 5)) | |
.fill(RadialGradient.init(colors: [.black.opacity(0.2)], center: .top, startRadius: 10.0, endRadius: 40.0)) | |
//.rotationEffect(blink ? Angle(degrees: 0.0) : Angle(degrees: 45.0)) | |
.opacity(blink ? 1 : 0.125) | |
.animation(.default.speed(0.2).repeatForever(), value: blink) | |
}.zIndex(0.05) | |
.shadow(radius: blink ? 0 : 5) | |
.animation(.default.speed(0.1).repeatForever(), value: blink) | |
.onAppear() { | |
blink = blink ? false : true | |
}.zIndex(0.1) | |
Image(systemName: "pencil").resizable().foregroundColor(.white).mask(Circle()).rotationEffect(Angle(degrees: 145.0)) | |
} | |
} | |
fileprivate func triangleError() -> some View { | |
VStack { | |
HStack { | |
emptyViewState().scaledToFit().frame(width:80).rotationEffect(blink ? Angle(degrees: 90) : Angle(degrees: 180)) | |
emptyViewState().scaledToFit().frame(width:80).rotationEffect(blink ? Angle(degrees: 90) : Angle(degrees: 180)) | |
emptyViewState().scaledToFit().frame(width:80).rotationEffect(blink ? Angle(degrees: 90) : Angle(degrees: 180)) | |
}.zIndex(0.1) | |
HStack { | |
emptyViewState().scaledToFit().frame(width:80).rotationEffect(blink ? Angle(degrees: 90) : Angle(degrees: 180)) | |
emptyViewState().scaledToFit().frame(width:80).rotationEffect(blink ? Angle(degrees: 90) : Angle(degrees: 180)) | |
}.zIndex(0.1) | |
HStack { | |
emptyViewState().scaledToFit().frame(width:80).rotationEffect(blink ? Angle(degrees: 90) : Angle(degrees: 180)) | |
} .onAppear() { | |
blink = blink ? false : true | |
}.zIndex(0.2) | |
} | |
} | |
} | |
enum TransferError : Error { | |
case importFailed | |
} | |
@available(iOS 16.0, *) | |
class PhotosModel : ObservableObject { | |
enum ImageState { | |
case empty, loading(Progress), success(Image), failure(Error) | |
} | |
@Published private(set) var imageState: ImageState = .empty | |
@Published var imageSelection: PhotosPickerItem? { | |
didSet { | |
if let imageSelection { | |
let progress = loadTransferable(from: imageSelection) | |
imageState = .loading(progress) | |
} else { | |
imageState = .empty | |
} | |
} | |
} | |
private func loadTransferable(from imageSelection: PhotosPickerItem) -> Progress { | |
return imageSelection.loadTransferable(type: Data.self) { result in | |
DispatchQueue.main.async { | |
guard imageSelection == self.imageSelection else { return } | |
switch result { | |
case let .success(data?): | |
guard let uiImage = UIImage(data: data) else { | |
self.imageState = .empty | |
return | |
} | |
self.imageState = .success(Image(uiImage: uiImage)) | |
case .success(.none): | |
self.imageState = .empty | |
case let .failure(error): | |
self.imageState = .failure(error) | |
} | |
} | |
} | |
} | |
} | |
@available(iOS 16.0, *) | |
struct PhotosPreview: PreviewProvider { | |
static var previews: some View { | |
Photos() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is the photo picker example out of the SDK docs, with a little idea around blinking the drop shadow.
you can do a simple .shadow(radius: blink ? 0 : 5) or you can also control the stroke vs fill
Super excited to see all the use case scenarios for subtle notifications in our future client UI designs. Also I was at Comicon this weekend and yes they look like the Red Storm Troopers
test.mov