ConfirmationView.swift 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import SwiftUI
  2. struct ConfirmationView: View {
  3. @Binding var success: Bool?
  4. var body: some View {
  5. ZStack {
  6. Group {
  7. Image(systemName: "checkmark.circle.fill")
  8. .resizable()
  9. .foregroundColor(.loopGreen)
  10. .opacity(success == true ? 1.0 : 0.0)
  11. .scaleEffect(success == true ? 1.0 : 0.0)
  12. Image(systemName: "xmark.circle.fill")
  13. .resizable()
  14. .foregroundColor(.loopRed)
  15. .opacity(success == false ? 1.0 : 0.0)
  16. .scaleEffect(success == false ? 1.0 : 0.0)
  17. BlinkingView(count: 10, size: 10)
  18. .opacity(success == nil ? 1.0 : 0.0)
  19. .scaleEffect(success == nil ? 1.0 : 0.0)
  20. }
  21. .frame(width: 50, height: 50)
  22. }
  23. .frame(maxWidth: .infinity, maxHeight: .infinity)
  24. }
  25. }
  26. struct ConfirmationView_Previews: PreviewProvider {
  27. struct Container: View {
  28. @State var success: Bool?
  29. var body: some View {
  30. ConfirmationView(success: $success)
  31. }
  32. }
  33. static var previews: some View {
  34. Container()
  35. }
  36. }
  37. struct BlinkingView: View {
  38. let count: UInt
  39. let size: CGFloat
  40. var body: some View {
  41. GeometryReader { geometry in
  42. ForEach(0 ..< Int(count)) { index in
  43. item(forIndex: index, in: geometry.size)
  44. .frame(width: geometry.size.width, height: geometry.size.height)
  45. }
  46. }
  47. .animation(.none, value: false)
  48. .aspectRatio(contentMode: .fit)
  49. .onAppear {
  50. scale = 1
  51. opacity = 1
  52. }
  53. }
  54. @State var scale = 0.5
  55. @State var opacity = 0.25
  56. func animation(index: Int) -> Animation {
  57. Animation
  58. .default
  59. .repeatCount(.max, autoreverses: true)
  60. .delay(Double(index) / Double(count) / 2)
  61. }
  62. private func item(forIndex index: Int, in geometrySize: CGSize) -> some View {
  63. let angle = 2 * CGFloat.pi / CGFloat(count) * CGFloat(index)
  64. let x = (geometrySize.width / 2 - size / 2) * cos(angle)
  65. let y = (geometrySize.height / 2 - size / 2) * sin(angle)
  66. return Circle()
  67. .frame(width: size, height: size)
  68. .scaleEffect(scale)
  69. .opacity(opacity)
  70. .animation(animation(index: index), value: scale)
  71. .animation(animation(index: index), value: opacity)
  72. .offset(x: x, y: y)
  73. }
  74. }