From 1fa3bb1c7d1b190234b7cf0f159ac737459a37dc Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Fri, 19 Jun 2020 09:29:44 -0300 Subject: [PATCH] Added Card, Glow Refactor --- Zircles.xcodeproj/project.pbxproj | 22 +- .../{Glow.swift => Glow_Preview.swift} | 71 ----- Zircles/Neumorphic/Card.swift | 39 +++ Zircles/Neumorphic/GlowEffect.swift | 79 ++++++ Zircles/Neumorphic/NeumorphicButtons.swift | 258 ++++++++++++++++++ 5 files changed, 394 insertions(+), 75 deletions(-) rename Zircles/Components/{Glow.swift => Glow_Preview.swift} (68%) create mode 100644 Zircles/Neumorphic/Card.swift create mode 100644 Zircles/Neumorphic/GlowEffect.swift create mode 100644 Zircles/Neumorphic/NeumorphicButtons.swift diff --git a/Zircles.xcodeproj/project.pbxproj b/Zircles.xcodeproj/project.pbxproj index 4112841..794c22c 100644 --- a/Zircles.xcodeproj/project.pbxproj +++ b/Zircles.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 0D11D3CE249C294E00223146 /* NeumorphicButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D11D3CD249C294E00223146 /* NeumorphicButtons.swift */; }; + 0D11D3D0249C3AE400223146 /* Card.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D11D3CF249C3AE300223146 /* Card.swift */; }; + 0D11D3D2249CE6C800223146 /* GlowEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D11D3D1249CE6C800223146 /* GlowEffect.swift */; }; 0D1366AC24991A6000F0EB54 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1366AB24991A6000F0EB54 /* AppDelegate.swift */; }; 0D1366AE24991A6000F0EB54 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1366AD24991A6000F0EB54 /* SceneDelegate.swift */; }; 0D1366B024991A6000F0EB54 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1366AF24991A6000F0EB54 /* ContentView.swift */; }; @@ -19,7 +22,7 @@ 0D6A22C5249AB1FC00B4E946 /* ZcashSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D6A22C4249AB1FC00B4E946 /* ZcashSymbol.swift */; }; 0D6A22C7249AB36100B4E946 /* ZcashButtonBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D6A22C6249AB36100B4E946 /* ZcashButtonBackground.swift */; }; 0D6A22C9249AB3CA00B4E946 /* ZcashButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D6A22C8249AB3CA00B4E946 /* ZcashButton.swift */; }; - 0D6A22CB249AB61200B4E946 /* Glow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D6A22CA249AB61200B4E946 /* Glow.swift */; }; + 0D6A22CB249AB61200B4E946 /* Glow_Preview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D6A22CA249AB61200B4E946 /* Glow_Preview.swift */; }; 4A79AF7FBA1F1ABC33BDD0DD /* Pods_Zircles.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0EF685DA606F425B52CC5DC2 /* Pods_Zircles.framework */; }; 9DE24A8E04467408269AD782 /* Pods_ZirclesTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBBDF5C4ADB5C51259A3817D /* Pods_ZirclesTests.framework */; }; A78732A65E5555C51A0C4D44 /* Pods_Zircles_ZirclesUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6205D6783F82D4352213AE76 /* Pods_Zircles_ZirclesUITests.framework */; }; @@ -44,6 +47,9 @@ /* Begin PBXFileReference section */ 08F4F839AA82F245159E5A95 /* Pods-ZirclesUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ZirclesUITests.release.xcconfig"; path = "Target Support Files/Pods-ZirclesUITests/Pods-ZirclesUITests.release.xcconfig"; sourceTree = ""; }; + 0D11D3CD249C294E00223146 /* NeumorphicButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeumorphicButtons.swift; sourceTree = ""; }; + 0D11D3CF249C3AE300223146 /* Card.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Card.swift; sourceTree = ""; }; + 0D11D3D1249CE6C800223146 /* GlowEffect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlowEffect.swift; sourceTree = ""; }; 0D1366A824991A6000F0EB54 /* Zircles.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Zircles.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0D1366AB24991A6000F0EB54 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 0D1366AD24991A6000F0EB54 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -62,7 +68,7 @@ 0D6A22C4249AB1FC00B4E946 /* ZcashSymbol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZcashSymbol.swift; sourceTree = ""; }; 0D6A22C6249AB36100B4E946 /* ZcashButtonBackground.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZcashButtonBackground.swift; sourceTree = ""; }; 0D6A22C8249AB3CA00B4E946 /* ZcashButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZcashButton.swift; sourceTree = ""; }; - 0D6A22CA249AB61200B4E946 /* Glow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Glow.swift; sourceTree = ""; }; + 0D6A22CA249AB61200B4E946 /* Glow_Preview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Glow_Preview.swift; sourceTree = ""; }; 0EF685DA606F425B52CC5DC2 /* Pods_Zircles.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Zircles.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1F41B44F15E6B8B8AC35DA82 /* Pods-ZirclesUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ZirclesUITests.debug.xcconfig"; path = "Target Support Files/Pods-ZirclesUITests/Pods-ZirclesUITests.debug.xcconfig"; sourceTree = ""; }; 215B95DF0D4FE064A7C4BD8D /* Pods-ZirclesTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ZirclesTests.debug.xcconfig"; path = "Target Support Files/Pods-ZirclesTests/Pods-ZirclesTests.debug.xcconfig"; sourceTree = ""; }; @@ -174,7 +180,7 @@ 0D6A22C8249AB3CA00B4E946 /* ZcashButton.swift */, 0D6A22C6249AB36100B4E946 /* ZcashButtonBackground.swift */, 0D6A22C4249AB1FC00B4E946 /* ZcashSymbol.swift */, - 0D6A22CA249AB61200B4E946 /* Glow.swift */, + 0D6A22CA249AB61200B4E946 /* Glow_Preview.swift */, ); path = Components; sourceTree = ""; @@ -182,6 +188,9 @@ 0D6A22CC249ACD6C00B4E946 /* Neumorphic */ = { isa = PBXGroup; children = ( + 0D11D3CD249C294E00223146 /* NeumorphicButtons.swift */, + 0D11D3CF249C3AE300223146 /* Card.swift */, + 0D11D3D1249CE6C800223146 /* GlowEffect.swift */, ); path = Neumorphic; sourceTree = ""; @@ -454,9 +463,12 @@ 0D6A22C0249A9C3000B4E946 /* Colors+Zircles.swift in Sources */, 0D6A22C5249AB1FC00B4E946 /* ZcashSymbol.swift in Sources */, 0D1366AC24991A6000F0EB54 /* AppDelegate.swift in Sources */, + 0D11D3CE249C294E00223146 /* NeumorphicButtons.swift in Sources */, 0D6A22C7249AB36100B4E946 /* ZcashButtonBackground.swift in Sources */, 0D1366AE24991A6000F0EB54 /* SceneDelegate.swift in Sources */, - 0D6A22CB249AB61200B4E946 /* Glow.swift in Sources */, + 0D11D3D0249C3AE400223146 /* Card.swift in Sources */, + 0D6A22CB249AB61200B4E946 /* Glow_Preview.swift in Sources */, + 0D11D3D2249CE6C800223146 /* GlowEffect.swift in Sources */, 0D1366B024991A6000F0EB54 /* ContentView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -512,6 +524,7 @@ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_CODE_COVERAGE = NO; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; @@ -572,6 +585,7 @@ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_CODE_COVERAGE = NO; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; diff --git a/Zircles/Components/Glow.swift b/Zircles/Components/Glow_Preview.swift similarity index 68% rename from Zircles/Components/Glow.swift rename to Zircles/Components/Glow_Preview.swift index 92e323f..4a63dd2 100644 --- a/Zircles/Components/Glow.swift +++ b/Zircles/Components/Glow_Preview.swift @@ -9,77 +9,6 @@ import Foundation import SwiftUI -typealias GlowVibe = GlowModifier.GlowVibe -typealias GlowSoul = GlowModifier.GlowSoul - -struct GlowModifier: ViewModifier { - enum GlowVibe { - case mild - case cool - case heavy - } - - enum GlowSoul { - case solid(color: Color) - case split(left: Color, right: Color) - } - - var vibe: GlowVibe - - var soul: GlowSoul - - func body(content: Content) -> some View { - - let colors = color(soul: soul) - - return content - .shadow(color:colors.0.opacity(0.7), radius: radius(vibe), x: -offsetX(vibe), y: 0) - .shadow(color:colors.1.opacity(0.7), radius: radius(vibe), x: offsetX(vibe), y: 0) - - } - - func color(soul: GlowSoul) -> (Color, Color) { - switch soul { - case .solid(let color): - return (color,color) - case .split(let left,let right): - return (left, right) - } - } - - func radius(_ vibe: GlowVibe) -> CGFloat { - switch vibe { - case .mild: - return 6 - case .cool: - return 20 - case .heavy: - return 40 - } - } - - func offsetX(_ vibe: GlowVibe) -> CGFloat { - switch vibe { - case .mild: - return 3 - case .cool: - return 12 - case .heavy: - return 24 - } - } -} - -extension View { - func glow(vibe: GlowVibe, soul: GlowSoul) -> some View { - - self.modifier( - GlowModifier(vibe: vibe, soul: soul) - ) - } -} - - struct GlowButtons_Previews: PreviewProvider { static var previews: some View { ZStack { diff --git a/Zircles/Neumorphic/Card.swift b/Zircles/Neumorphic/Card.swift new file mode 100644 index 0000000..708a98f --- /dev/null +++ b/Zircles/Neumorphic/Card.swift @@ -0,0 +1,39 @@ +// +// Card.swift +// Zircles +// +// Created by Francisco Gindre on 6/18/20. +// Copyright © 2020 Electric Coin Company. All rights reserved. +// + +import SwiftUI + +struct Card: View { + @Binding var isToggled: Bool + + let content: Content + init(isOn: Binding, @ViewBuilder content: () -> Content) { + self._isToggled = isOn + self.content = content() + } + var body: some View { + Toggle(isOn: $isToggled) { + content + } + .toggleStyle(SimpleToggleStyle(cornerRadius: 25)) + } +} + +struct Card_Previews: PreviewProvider { + @State static var isToggled: Bool = false + static var previews: some View { + ZStack { + Color.background + Card(isOn: $isToggled) { + Image(systemName: "heart.fill") + .foregroundColor(.gray) + .frame(width: 200, height: 200) + } + } + } +} diff --git a/Zircles/Neumorphic/GlowEffect.swift b/Zircles/Neumorphic/GlowEffect.swift new file mode 100644 index 0000000..6059d58 --- /dev/null +++ b/Zircles/Neumorphic/GlowEffect.swift @@ -0,0 +1,79 @@ +// +// GlowEffect.swift +// Zircles +// +// Created by Francisco Gindre on 6/19/20. +// Copyright © 2020 Electric Coin Company. All rights reserved. +// + +import SwiftUI + +typealias GlowVibe = GlowEffect.Vibe +typealias GlowSoul = GlowEffect.Soul + +struct GlowEffect: ViewModifier { + enum Vibe { + case mild + case cool + case heavy + } + + enum Soul { + case solid(color: Color) + case split(left: Color, right: Color) + } + + var vibe: Vibe + + var soul: Soul + + func body(content: Content) -> some View { + + let colors = color(soul: soul) + + return content + .shadow(color:colors.0.opacity(0.7), radius: radius(vibe), x: -offsetX(vibe), y: 0) + .shadow(color:colors.1.opacity(0.7), radius: radius(vibe), x: offsetX(vibe), y: 0) + + } + + func color(soul: Soul) -> (Color, Color) { + switch soul { + case .solid(let color): + return (color,color) + case .split(let left,let right): + return (left, right) + } + } + + func radius(_ vibe: Vibe) -> CGFloat { + switch vibe { + case .mild: + return 6 + case .cool: + return 20 + case .heavy: + return 40 + } + } + + func offsetX(_ vibe: Vibe) -> CGFloat { + switch vibe { + case .mild: + return 3 + case .cool: + return 12 + case .heavy: + return 24 + } + } +} + +extension View { + func glow(vibe: GlowVibe, soul: GlowSoul) -> some View { + + self.modifier( + GlowEffect(vibe: vibe, soul: soul) + ) + } +} diff --git a/Zircles/Neumorphic/NeumorphicButtons.swift b/Zircles/Neumorphic/NeumorphicButtons.swift new file mode 100644 index 0000000..a42c44b --- /dev/null +++ b/Zircles/Neumorphic/NeumorphicButtons.swift @@ -0,0 +1,258 @@ +import SwiftUI + +extension Color { + static let offWhite = Color(red: 225 / 255, green: 225 / 255, blue: 235 / 255) + + static let darkStart = Color(red: 50 / 255, green: 60 / 255, blue: 65 / 255) + static let darkEnd = Color(red: 25 / 255, green: 25 / 255, blue: 30 / 255) + + static let lightStart = Color(red: 60 / 255, green: 160 / 255, blue: 240 / 255) + static let lightEnd = Color(red: 30 / 255, green: 80 / 255, blue: 120 / 255) +} + +extension LinearGradient { + init(_ colors: Color...) { + self.init(gradient: Gradient(colors: colors), startPoint: .topLeading, endPoint: .bottomTrailing) + } +} + +struct SimpleButtonStyle: ButtonStyle { + func makeBody(configuration: Self.Configuration) -> some View { + configuration.label + .padding(30) + .contentShape(Circle()) + .background( + Group { + if configuration.isPressed { + Circle() + .fill(Color.offWhite) + .overlay( + Circle() + .stroke(Color.gray, lineWidth: 4) + .blur(radius: 4) + .offset(x: 2, y: 2) + .mask(Circle().fill(LinearGradient(Color.black, Color.clear))) + ) + .overlay( + Circle() + .stroke(Color.white, lineWidth: 8) + .blur(radius: 4) + .offset(x: -2, y: -2) + .mask(Circle().fill(LinearGradient(Color.clear, Color.black))) + ) + } else { + Circle() + .fill(Color.offWhite) + .shadow(color: Color.black.opacity(0.2), radius: 10, x: 10, y: 10) + .shadow(color: Color.white.opacity(0.7), radius: 10, x: -5, y: -5) + } + } + ) + } +} +struct SimpleBackground: View { + var isHighlighted: Bool + var shape: S + + var body: some View { + ZStack { + if isHighlighted { + shape + .fill(Color.offWhite) + .overlay( + shape + .stroke(Color.gray, lineWidth: 4) + .blur(radius: 4) + .offset(x: 2, y: 2) + .mask(shape.fill(LinearGradient(Color.black, Color.clear))) + ) + .overlay( + shape + .stroke(Color.white, lineWidth: 8) + .blur(radius: 4) + .offset(x: -2, y: -2) + .mask(shape.fill(LinearGradient(Color.clear, Color.black))) + ) + } else { + shape + .fill(Color.offWhite) + .shadow(color: Color.black.opacity(0.2), radius: 10, x: 10, y: 10) + .shadow(color: Color.white.opacity(0.7), radius: 10, x: -5, y: -5) + } + } + } +} + +struct DarkBackground: View { + var isHighlighted: Bool + var shape: S + + var body: some View { + ZStack { + if isHighlighted { + shape + .fill(LinearGradient(Color.darkEnd, Color.darkStart)) + .overlay(shape.stroke(LinearGradient(Color.darkStart, Color.darkEnd), lineWidth: 4)) + .shadow(color: Color.darkStart, radius: 10, x: 5, y: 5) + .shadow(color: Color.darkEnd, radius: 10, x: -5, y: -5) + } else { + shape + .fill(LinearGradient(Color.darkStart, Color.darkEnd)) + .overlay(shape.stroke(Color.darkEnd, lineWidth: 4)) + .shadow(color: Color.darkStart, radius: 10, x: -10, y: -10) + .shadow(color: Color.darkEnd, radius: 10, x: 10, y: 10) + } + } + } +} + +struct ColorfulBackground: View { + var isHighlighted: Bool + var shape: S + + var body: some View { + ZStack { + if isHighlighted { + shape + .fill(LinearGradient(Color.lightEnd, Color.lightStart)) + .overlay(shape.stroke(LinearGradient(Color.lightStart, Color.lightEnd), lineWidth: 4)) + .shadow(color: Color.darkStart, radius: 10, x: 5, y: 5) + .shadow(color: Color.darkEnd, radius: 10, x: -5, y: -5) + } else { + shape + .fill(LinearGradient(Color.darkStart, Color.darkEnd)) + .overlay(shape.stroke(LinearGradient(Color.lightStart, Color.lightEnd), lineWidth: 4)) + .shadow(color: Color.darkStart, radius: 10, x: -10, y: -10) + .shadow(color: Color.darkEnd, radius: 10, x: 10, y: 10) + } + } + } +} + +struct DarkButtonStyle: ButtonStyle { + func makeBody(configuration: Self.Configuration) -> some View { + configuration.label + .padding(30) + .contentShape(Circle()) + .background( + DarkBackground(isHighlighted: configuration.isPressed, shape: Circle()) + ) + .animation(nil) + } +} + +struct DarkToggleStyle: ToggleStyle { + func makeBody(configuration: Self.Configuration) -> some View { + Button(action: { + configuration.isOn.toggle() + }) { + configuration.label + .padding(30) + .contentShape(Circle()) + } + .background( + DarkBackground(isHighlighted: configuration.isOn, shape: Circle()) + ) + } +} + +struct ColorfulButtonStyle: ButtonStyle { + func makeBody(configuration: Self.Configuration) -> some View { + configuration.label + .padding(30) + .contentShape(Circle()) + .background( + ColorfulBackground(isHighlighted: configuration.isPressed, shape: Circle()) + ) + .animation(nil) + } +} +struct SimpleToggleStyle: ToggleStyle { + var cornerRadius: CGFloat = 5 + + func makeBody(configuration: Self.Configuration) -> some View { + Button(action: { + configuration.isOn.toggle() + }) { + configuration.label + .contentShape(RoundedRectangle(cornerRadius: cornerRadius)) + .padding(30) + } + .background( + SimpleBackground(isHighlighted: configuration.isOn, shape: RoundedRectangle(cornerRadius: cornerRadius)) + ) + } +} + +struct ColorfulToggleStyle: ToggleStyle { + + + func makeBody(configuration: Self.Configuration) -> some View { + Button(action: { + configuration.isOn.toggle() + }) { + configuration.label + .padding(30) + .contentShape(RoundedRectangle(cornerRadius: 5)) + } + .background( + ColorfulBackground(isHighlighted: configuration.isOn, shape: RoundedRectangle(cornerRadius: 5)) + ) + } +} + +struct NeumorphicContentView: View { + @State private var isToggled = false + + var body: some View { + VStack { + ZStack { + LinearGradient(Color.darkStart, Color.darkEnd) + + VStack(spacing: 40) { + Button(action: { + print("Button tapped") + }) { + Image(systemName: "heart.fill") + .foregroundColor(.white) + } + .buttonStyle(ColorfulButtonStyle()) + + Toggle(isOn: $isToggled) { + Image(systemName: "heart.fill") + .foregroundColor(.white) + } + .toggleStyle(ColorfulToggleStyle()) + } + } + ZStack { + Color.offWhite + + VStack(spacing: 40) { + Button(action: { + print("Button tapped") + }) { + Image(systemName: "heart.fill") + .foregroundColor(.gray) + } + .buttonStyle(SimpleButtonStyle()) + + Toggle(isOn: $isToggled) { + Image(systemName: "heart.fill") + .foregroundColor(.gray) + .frame(width: 200, height: 200) + } + .toggleStyle(SimpleToggleStyle(cornerRadius: 50)) + } + } + } + + .edgesIgnoringSafeArea(.all) + } +} + +struct ButtonsView_Previews: PreviewProvider { + static var previews: some View { + NeumorphicContentView() + } +}