Skip to content

Instantly share code, notes, and snippets.

@DarrenHurst
Created March 20, 2023 15:14
Show Gist options
  • Save DarrenHurst/280a83515909496c064694ed3140d23b to your computer and use it in GitHub Desktop.
Save DarrenHurst/280a83515909496c064694ed3140d23b to your computer and use it in GitHub Desktop.
ErrorExample
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()
}
}
@DarrenHurst
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment