Circular Frame

This commit is contained in:
adam 2021-10-29 07:50:19 -05:00
parent 0e7ed30f44
commit 66e35c2913
36 changed files with 456 additions and 21 deletions

View File

@ -27,8 +27,8 @@ import SwiftUI
{{accessModifier}} typealias {{param.colorAliasName|default:"AssetColorTypeAlias"}} = {{colorType}}.SystemColor
{% endif %}
{% if resourceCount.image > 0 %}
@available(*, deprecated, renamed: "{{imageType}}.Image", message: "This typealias will be removed in SwiftGen 7.0")
{{accessModifier}} typealias {{param.imageAliasName|default:"AssetImageTypeAlias"}} = {{imageType}}.Image
@available(*, deprecated, renamed: "{{imageType}}.UniversalImage", message: "This typealias will be removed in SwiftGen 7.0")
{{accessModifier}} typealias {{param.imageAliasName|default:"AssetImageTypeAlias"}} = {{imageType}}.UniversalImage
{% endif %}
// swiftlint:disable superfluous_disable_command file_length implicit_return
@ -224,29 +224,34 @@ import SwiftUI
{{accessModifier}} fileprivate(set) var name: String
#if os(macOS)
{{accessModifier}} typealias Image = NSImage
{{accessModifier}} typealias UniversalImage = NSImage
#elseif os(iOS) || os(tvOS) || os(watchOS)
{{accessModifier}} typealias Image = UIImage
{{accessModifier}} typealias UniversalImage = UIImage
#endif
{{accessModifier}} var image: Image {
{{accessModifier}} var systemImage: UniversalImage {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
#if os(iOS) || os(tvOS)
let image = Image(named: name, in: bundle, compatibleWith: nil)
let image = UniversalImage(named: name, in: bundle, compatibleWith: nil)
#elseif os(macOS)
let name = NSImage.Name(self.name)
let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name)
#elseif os(watchOS)
let image = Image(named: name)
let image = UniversalImage(named: name)
#endif
guard let result = image else {
fatalError("Unable to load image asset named \(name).")
}
return result
}
{{accessModifier}} var image: Image {
let bundle = {{param.bundle|default:"BundleToken.bundle"}}
return Image(name, bundle: bundle)
}
}
{{accessModifier}} extension {{imageType}}.Image {
{{accessModifier}} extension {{imageType}}.UniversalImage {
@available(macOS, deprecated,
message: "This initializer is unsafe on macOS, please use the {{imageType}}.image property")
convenience init?(asset: {{imageType}}) {

View File

@ -83,6 +83,9 @@
6654C73E2715A41300901167 /* OnboardingStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6654C73D2715A41300901167 /* OnboardingStore.swift */; };
6654C7412715A47300901167 /* Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6654C7402715A47300901167 /* Onboarding.swift */; };
6654C7442715A4AC00901167 /* OnboardingStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6654C7432715A4AC00901167 /* OnboardingStoreTests.swift */; };
665C963F272C26E600BC04FB /* CircularFrameBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = 665C963E272C26E600BC04FB /* CircularFrameBackground.swift */; };
669FDAE9272C23B3007B9422 /* CircularFrame.swift in Sources */ = {isa = PBXBuildFile; fileRef = 669FDAE8272C23B3007B9422 /* CircularFrame.swift */; };
669FDAEB272C23C2007B9422 /* CircularFrameBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 669FDAEA272C23C2007B9422 /* CircularFrameBadge.swift */; };
66A0807B271993C500118B79 /* OnboardingProgressIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66A0807A271993C500118B79 /* OnboardingProgressIndicator.swift */; };
66D50668271D9B6100E51F0D /* NavigationButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D50667271D9B6100E51F0D /* NavigationButtonStyle.swift */; };
66DC733F271D88CC0053CBB6 /* StandardButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66DC733E271D88CC0053CBB6 /* StandardButtonStyle.swift */; };
@ -187,6 +190,9 @@
6654C73D2715A41300901167 /* OnboardingStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingStore.swift; sourceTree = "<group>"; };
6654C7402715A47300901167 /* Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Onboarding.swift; sourceTree = "<group>"; };
6654C7432715A4AC00901167 /* OnboardingStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingStoreTests.swift; sourceTree = "<group>"; };
665C963E272C26E600BC04FB /* CircularFrameBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularFrameBackground.swift; sourceTree = "<group>"; };
669FDAE8272C23B3007B9422 /* CircularFrame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularFrame.swift; sourceTree = "<group>"; };
669FDAEA272C23C2007B9422 /* CircularFrameBadge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularFrameBadge.swift; sourceTree = "<group>"; };
66A0807A271993C500118B79 /* OnboardingProgressIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingProgressIndicator.swift; sourceTree = "<group>"; };
66D50667271D9B6100E51F0D /* NavigationButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationButtonStyle.swift; sourceTree = "<group>"; };
66DC733E271D88CC0053CBB6 /* StandardButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardButtonStyle.swift; sourceTree = "<group>"; };
@ -468,12 +474,13 @@
0DA13C9126C15E1900E3B610 /* UI Components */ = {
isa = PBXGroup;
children = (
669FDAE7272C239D007B9422 /* CircularFrame */,
0DB8AA80271DC7520035BC9D /* DesignGuide.swift */,
0DF2DC5227235E1F00FA31E2 /* Extensions */,
0D535FE0271F945C009A9E3E /* Chips */,
663FAB9A271D873300E495F8 /* Buttons */,
66A0807A271993C500118B79 /* OnboardingProgressIndicator.swift */,
0DB8AA80271DC7520035BC9D /* DesignGuide.swift */,
0D7DF08B271DCC0E00530046 /* ScreenBackground.swift */,
669FDAE5272C2371007B9422 /* ProgressIndicators */,
669FDAE6272C2380007B9422 /* Backgrounds */,
);
path = "UI Components";
sourceTree = "<group>";
@ -604,6 +611,32 @@
path = OnboardingTests;
sourceTree = "<group>";
};
669FDAE5272C2371007B9422 /* ProgressIndicators */ = {
isa = PBXGroup;
children = (
66A0807A271993C500118B79 /* OnboardingProgressIndicator.swift */,
);
path = ProgressIndicators;
sourceTree = "<group>";
};
669FDAE6272C2380007B9422 /* Backgrounds */ = {
isa = PBXGroup;
children = (
0D7DF08B271DCC0E00530046 /* ScreenBackground.swift */,
);
path = Backgrounds;
sourceTree = "<group>";
};
669FDAE7272C239D007B9422 /* CircularFrame */ = {
isa = PBXGroup;
children = (
669FDAE8272C23B3007B9422 /* CircularFrame.swift */,
669FDAEA272C23C2007B9422 /* CircularFrameBadge.swift */,
665C963E272C26E600BC04FB /* CircularFrameBackground.swift */,
);
path = CircularFrame;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -803,6 +836,7 @@
files = (
660558F8270C862F009D6954 /* XCAssets+Generated.swift in Sources */,
0D32281F26C5867D00262533 /* ScanQrScreenViewModel.swift in Sources */,
669FDAE9272C23B3007B9422 /* CircularFrame.swift in Sources */,
0D32282E26C5870B00262533 /* SendScreenViewModel.swift in Sources */,
0D32282D26C5870B00262533 /* SendScreen.swift in Sources */,
663FABA2271D876C00E495F8 /* SecondaryButton.swift in Sources */,
@ -814,12 +848,14 @@
0D535FE2271F9476009A9E3E /* EnumeratedChip.swift in Sources */,
6654C73E2715A41300901167 /* OnboardingStore.swift in Sources */,
0D32281E26C5867D00262533 /* ScanQrScreen.swift in Sources */,
669FDAEB272C23C2007B9422 /* CircularFrameBadge.swift in Sources */,
0D864A0E26E1583000A61879 /* LoadingScreen.swift in Sources */,
0DA13C9C26C1942100E3B610 /* BackupWalletScreen.swift in Sources */,
0DA13C9826C186FF00E3B610 /* RestoreWalletScreenViewModel.swift in Sources */,
0D32283326C5877A00262533 /* BalanceScreenViewModel.swift in Sources */,
0D5D16F526E24CCF00AD33D1 /* AppError.swift in Sources */,
0D18581B272728D60046B928 /* PhraseChip.swift in Sources */,
665C963F272C26E600BC04FB /* CircularFrameBackground.swift in Sources */,
0DB8AA81271DC7520035BC9D /* DesignGuide.swift in Sources */,
0D32282326C586A800262533 /* HistoryScreen.swift in Sources */,
0D864A0A26E154FD00A61879 /* InitFailedScreenViewModel.swift in Sources */,

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "callout0.jpg",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callout0-1.jpg",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callout0-2.jpg",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "callout1.jpg",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callout1-1.jpg",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callout1-2.jpg",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "callout2.jpg",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callout2-1.jpg",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callout2-2.jpg",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "callout3.jpg",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "callout3-1.jpg",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "callout3-2.jpg",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "finalcallout.jpg",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "finalcallout-1.jpg",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "finalcallout-2.jpg",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -13,8 +13,8 @@ import SwiftUI
// Deprecated typealiases
@available(*, deprecated, renamed: "ColorAsset.SystemColor", message: "This typealias will be removed in SwiftGen 7.0")
internal typealias AssetColorTypeAlias = ColorAsset.SystemColor
@available(*, deprecated, renamed: "ImageAsset.Image", message: "This typealias will be removed in SwiftGen 7.0")
internal typealias AssetImageTypeAlias = ImageAsset.Image
@available(*, deprecated, renamed: "ImageAsset.UniversalImage", message: "This typealias will be removed in SwiftGen 7.0")
internal typealias AssetImageTypeAlias = ImageAsset.UniversalImage
// swiftlint:disable superfluous_disable_command file_length implicit_return
@ -23,10 +23,17 @@ internal typealias AssetImageTypeAlias = ImageAsset.Image
// swiftlint:disable identifier_name line_length nesting type_body_length type_name
internal enum Asset {
internal enum Assets {
internal enum Backgrounds {
internal static let callout0 = ImageAsset(name: "callout0")
internal static let callout1 = ImageAsset(name: "callout1")
internal static let callout2 = ImageAsset(name: "callout2")
internal static let callout3 = ImageAsset(name: "callout3")
internal static let callout4 = ImageAsset(name: "callout4")
}
internal enum Icons {
internal static let badge = ImageAsset(name: "badge")
internal static let list = ImageAsset(name: "list")
internal static let person = ImageAsset(name: "person")
internal static let profile = ImageAsset(name: "profile")
internal static let shield = ImageAsset(name: "shield")
}
}
internal enum Colors {
@ -124,29 +131,34 @@ internal struct ImageAsset {
internal fileprivate(set) var name: String
#if os(macOS)
internal typealias Image = NSImage
internal typealias UniversalImage = NSImage
#elseif os(iOS) || os(tvOS) || os(watchOS)
internal typealias Image = UIImage
internal typealias UniversalImage = UIImage
#endif
internal var image: Image {
internal var systemImage: UniversalImage {
let bundle = BundleToken.bundle
#if os(iOS) || os(tvOS)
let image = Image(named: name, in: bundle, compatibleWith: nil)
let image = UniversalImage(named: name, in: bundle, compatibleWith: nil)
#elseif os(macOS)
let name = NSImage.Name(self.name)
let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name)
#elseif os(watchOS)
let image = Image(named: name)
let image = UniversalImage(named: name)
#endif
guard let result = image else {
fatalError("Unable to load image asset named \(name).")
}
return result
}
internal var image: Image {
let bundle = BundleToken.bundle
return Image(name, bundle: bundle)
}
}
internal extension ImageAsset.Image {
internal extension ImageAsset.UniversalImage {
@available(macOS, deprecated,
message: "This initializer is unsafe on macOS, please use the ImageAsset.image property")
convenience init?(asset: ImageAsset) {

View File

@ -0,0 +1,120 @@
//
// CircularImageFrame.swift
// secant-testnet
//
// Created by Adam Stener on 9/29/21.
//
import SwiftUI
struct CircularFrame: View {
var body: some View {
GeometryReader { proxy in
let lineWidth = proxy.size.width * 0.07
Circle()
.stroke(lineWidth: lineWidth)
.foregroundColor(Asset.Colors.Onboarding.circularFrame.color)
// Add two points to the frame to properly mask edges
.frame(
width: proxy.size.width - lineWidth + 2,
height: proxy.size.height - lineWidth + 2,
alignment: .center
)
// Update the offset to account for the 2 extra points
.offset(x: lineWidth / 2 - 1, y: lineWidth / 2 - 1)
.shadow(radius: 10)
}
}
}
struct OnboardingCircularFrame: View {
@Binding var index: Int
let size: CGFloat
var body: some View {
ZStack {
CircularFrame()
.frame(width: size, height: size)
switch index {
case 0:
Asset.Assets.Icons.shield.image
.onboardingBadge(parentSize: size)
case 1:
Asset.Assets.Icons.profile.image
.onboardingBadge(parentSize: size)
case 2:
Asset.Assets.Icons.list.image
.onboardingBadge(parentSize: size)
default:
EmptyView()
}
}
}
}
extension Image {
func onboardingBadge(parentSize: CGFloat) -> some View {
self
.resizable()
.frame(width: parentSize / 2, height: parentSize / 2)
.offset(y: parentSize * 0.47)
.zIndex(100)
}
}
struct CircularFramePreviewHelper: View {
@State var index = 0
private let size: CGFloat = 300
var body: some View {
VStack {
HStack(spacing: 25) {
Button("+") {
guard index < 2 else { return }
index += 1
}
Button("-") {
guard index != 0 else { return }
index -= 1
}
Text("\(index)")
}
GeometryReader { proxy in
VStack {
Spacer()
HStack {
Spacer()
OnboardingCircularFrame(index: $index, size: proxy.size.width / 2)
.animation(.easeInOut(duration: 2), value: index)
Spacer()
}
Spacer()
}
}
CircularFrame()
.backgroundImage(Asset.Assets.Backgrounds.callout1.image)
.frame(width: size, height: size)
.badgeIcon(.shield)
Spacer()
}
}
}
struct CircularFrame_Previews: PreviewProvider {
static var previews: some View {
CircularFramePreviewHelper()
.preferredColorScheme(.light)
.previewLayout(.device)
}
}

View File

@ -0,0 +1,53 @@
//
// CircularFrameBackground.swift
// secant-testnet
//
// Created by Adam Stener on 10/29/21.
//
import SwiftUI
struct CircularFrameBackgroundImage: ViewModifier {
let image: Image
func body(content: Content) -> some View {
ZStack {
image
.resizable()
.aspectRatio(1.3, contentMode: .fill)
.mask(Circle())
content
}
}
}
extension CircularFrame {
func backgroundImage(_ image: Image) -> some View {
modifier(CircularFrameBackgroundImage(image: image))
}
}
struct CircularFrameBackground_Previews: PreviewProvider {
static let size: CGFloat = 300
static var previews: some View {
Group {
CircularFrame()
.backgroundImage(Asset.Assets.Backgrounds.callout0.image)
.frame(width: 300, height: 300)
CircularFrame()
.backgroundImage(Asset.Assets.Backgrounds.callout1.image)
.frame(width: 300, height: 300)
CircularFrame()
.backgroundImage(Asset.Assets.Backgrounds.callout2.image)
.frame(width: 300, height: 300)
CircularFrame()
.backgroundImage(Asset.Assets.Backgrounds.callout3.image)
.frame(width: 300, height: 300)
}
.preferredColorScheme(.light)
.previewLayout(.fixed(width: size + 50, height: size + 50))
}
}

View File

@ -0,0 +1,82 @@
//
// CircularImageFrame.swift
// secant-testnet
//
// Created by Adam Stener on 9/29/21.
//
import SwiftUI
struct BadgeIcon: ViewModifier {
enum Badge: Equatable {
case shield
case list
case person
var image: Image {
switch self {
case .shield: return Asset.Assets.Icons.shield.image
case .list: return Asset.Assets.Icons.list.image
case .person: return Asset.Assets.Icons.profile.image
}
}
}
let badge: Badge
func body(content: Content) -> some View {
content
.overlay(
GeometryReader { proxy in
VStack {
Spacer()
HStack {
Spacer()
badge.image
.resizable()
.frame(
width: proxy.size.width * 0.5,
height: proxy.size.height * 0.5,
alignment: .center
)
.offset(
x: 0.0,
y: proxy.size.height * 0.21
)
Spacer()
}
}
}
)
}
}
extension View {
func badgeIcon(_ badge: BadgeIcon.Badge) -> some View {
modifier(BadgeIcon(badge: badge))
}
}
struct Badge_Previews: PreviewProvider {
static let size: CGFloat = 300
static var previews: some View {
Group {
CircularFrame()
.frame(width: size, height: size)
.badgeIcon(.shield)
CircularFrame()
.frame(width: size, height: size)
.badgeIcon(.list)
CircularFrame()
.frame(width: size, height: size)
.badgeIcon(.person)
}
.preferredColorScheme(.light)
.previewLayout(.fixed(width: size + 50, height: size + 50))
}
}