First batch of UI updates

The focus was on neumorphic buttons that work for both light and dark as well as state of the button (pressed)

Device specific enhancements

Colors and texts updated. Device specific paddings, margins and sizes enhanced

Dark appearance

Tweaks for the dark version of the onboarding UI

Update of the comments

Button UI updates

Colors updated, pressed button simulated and present in the DesignGuide.swift

Optimised Button's Layout

Onboarding footer was using the same settings for 3 buttons.
This commit is contained in:
Lukas Korba 2022-02-21 21:17:49 +01:00
parent 23126eb97b
commit 277c8b33fd
46 changed files with 905 additions and 140 deletions

View File

@ -82,6 +82,8 @@
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 */; };
9E4DC6E027C409A100E657F4 /* NeumorphicDesignModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */; };
9E4DC6E227C4C6B700E657F4 /* SecantButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4DC6E127C4C6B700E657F4 /* SecantButtonStyles.swift */; };
F9322DC0273B555C00C105B5 /* NavigationLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9322DBF273B555C00C105B5 /* NavigationLinks.swift */; };
F93673D62742CB840099C6AF /* Previews.swift in Sources */ = {isa = PBXBuildFile; fileRef = F93673D52742CB840099C6AF /* Previews.swift */; };
F93874F0273C4DE200F0E875 /* HomeStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F93874ED273C4DE200F0E875 /* HomeStore.swift */; };
@ -209,6 +211,8 @@
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>"; };
9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeumorphicDesignModifier.swift; sourceTree = "<group>"; };
9E4DC6E127C4C6B700E657F4 /* SecantButtonStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecantButtonStyles.swift; sourceTree = "<group>"; };
F9322DBF273B555C00C105B5 /* NavigationLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationLinks.swift; sourceTree = "<group>"; };
F93673D52742CB840099C6AF /* Previews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Previews.swift; sourceTree = "<group>"; };
F93874ED273C4DE200F0E875 /* HomeStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeStore.swift; sourceTree = "<group>"; };
@ -445,6 +449,7 @@
isa = PBXGroup;
children = (
0D8A43C3272AEEDE005A6414 /* SecantTextStyles.swift */,
9E4DC6E127C4C6B700E657F4 /* SecantButtonStyles.swift */,
);
path = FontStyles;
sourceTree = "<group>";
@ -562,6 +567,7 @@
663FAB9F271D876200E495F8 /* PrimaryButton.swift */,
663FABA1271D876C00E495F8 /* SecondaryButton.swift */,
66D50667271D9B6100E51F0D /* NavigationButtonStyle.swift */,
9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */,
);
path = Buttons;
sourceTree = "<group>";
@ -1000,11 +1006,13 @@
0DC487C32772574C00BE6A63 /* ValidationSucceededView.swift in Sources */,
0D8A43C4272AEEDE005A6414 /* SecantTextStyles.swift in Sources */,
0D1922F226BDE29300052649 /* ZcashSDKStubs.swift in Sources */,
9E4DC6E027C409A100E657F4 /* NeumorphicDesignModifier.swift in Sources */,
0DACFA7F27208CE00039EEA5 /* Clamped.swift in Sources */,
0DFE93E3272CA1AA000FCCA5 /* RecoveryPhraseValidation.swift in Sources */,
0D354A0B26D5A9D000315F45 /* MnemonicSeedPhraseHandling.swift in Sources */,
0D535FE2271F9476009A9E3E /* EnumeratedChip.swift in Sources */,
6654C73E2715A41300901167 /* OnboardingStore.swift in Sources */,
9E4DC6E227C4C6B700E657F4 /* SecantButtonStyles.swift in Sources */,
0DDB6A5127737D4A0012A410 /* ValidationFailedView.swift in Sources */,
0D6D628B276A528E002FB4CC /* DropDelegate.swift in Sources */,
F9971A5327680DD000A2DB75 /* Profile.swift in Sources */,

View File

@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.000",
"green" : "0.725",
"red" : "1.000"
"blue" : "0x00",
"green" : "0xB9",
"red" : "0xFF"
}
},
"idiom" : "universal"

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.341",
"green" : "0.200",
"red" : "0.149"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.200",
"blue" : "0x28",
"green" : "0xB7",
"red" : "0xF4"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.902",
"green" : "0.867",
"red" : "0.804"
"blue" : "0x57",
"green" : "0x33",
"red" : "0x26"
}
},
"idiom" : "universal"
@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.514",
"green" : "0.486",
"red" : "0.443"
"blue" : "0.000",
"green" : "0.847",
"red" : "1.000"
}
},
"idiom" : "universal"

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.330",
"blue" : "0x36",
"green" : "0x2C",
"red" : "0x27"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.000",
"blue" : "0x36",
"green" : "0x2C",
"red" : "0x27"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.820",
"green" : "0.722",
"red" : "0.631"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.150",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.992",
"green" : "0.980",
"red" : "0.969"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.150",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xD1",
"green" : "0xB8",
"red" : "0xA1"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "69",
"green" : "32",
"red" : "19"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xFD",
"green" : "0xFA",
"red" : "0xF7"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "88",
"green" : "50",
"red" : "40"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -2,12 +2,12 @@
"colors" : [
{
"color" : {
"color-space" : "srgb",
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0.937",
"green" : "0.863",
"red" : "0.784"
"blue" : "0xFD",
"green" : "0xF7",
"red" : "0xF1"
}
},
"idiom" : "universal"
@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.937",
"green" : "0.863",
"red" : "0.784"
"blue" : "217",
"green" : "192",
"red" : "167"
}
},
"idiom" : "universal"

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xD9",
"green" : "0xC0",
"red" : "0xA7"
"blue" : "0xFC",
"green" : "0xF8",
"red" : "0xF5"
}
},
"idiom" : "universal"
@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xD9",
"green" : "0xC0",
"red" : "0xA7"
"blue" : "0xEF",
"green" : "0xDC",
"red" : "0xC8"
}
},
"idiom" : "universal"

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.984",
"green" : "0.953",
"red" : "0.910"
"blue" : "0xFD",
"green" : "0xF7",
"red" : "0xF1"
}
},
"idiom" : "universal"
@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.851",
"green" : "0.753",
"red" : "0.655"
"blue" : "217",
"green" : "192",
"red" : "167"
}
},
"idiom" : "universal"

View File

@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "0.200",
"blue" : "0.933",
"green" : "0.863",
"red" : "0.780"
"blue" : "0xEF",
"green" : "0xDC",
"red" : "0xC8"
}
},
"idiom" : "universal"

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.996",
"green" : "0.988",
"red" : "0.984"
"blue" : "253",
"green" : "250",
"red" : "244"
}
},
"idiom" : "universal"

View File

@ -4,7 +4,7 @@
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"alpha" : "0.000",
"blue" : "0xFF",
"green" : "0xFF",
"red" : "0xFF"

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
"blue" : "246",
"green" : "234",
"red" : "222"
}
},
"idiom" : "universal"
@ -22,10 +22,10 @@
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.200",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
"alpha" : "1.000",
"blue" : "106",
"green" : "72",
"red" : "61"
}
},
"idiom" : "universal"

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "69",
"green" : "32",
"red" : "19"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "66",
"green" : "30",
"red" : "21"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "117",
"green" : "80",
"red" : "69"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "233",
"green" : "221",
"red" : "209"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "106",
"green" : "63",
"red" : "44"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xFD",
"green" : "0xF7",
"red" : "0xF1"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x62",
"green" : "0x33",
"red" : "0x22"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

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

View File

@ -2,12 +2,12 @@
"colors" : [
{
"color" : {
"color-space" : "extended-linear-srgb",
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xF3",
"green" : "0xE4",
"red" : "0xD2"
"blue" : "243",
"green" : "228",
"red" : "210"
}
},
"idiom" : "universal"
@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x5A",
"green" : "0x36",
"red" : "0x29"
"blue" : "0x55",
"green" : "0x31",
"red" : "0x24"
}
},
"idiom" : "universal"

View File

@ -2,12 +2,12 @@
"colors" : [
{
"color" : {
"color-space" : "display-p3",
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xF9",
"green" : "0xEF",
"red" : "0xE3"
"blue" : "249",
"green" : "239",
"red" : "227"
}
},
"idiom" : "universal"
@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x55",
"green" : "0x31",
"red" : "0x24"
"blue" : "0x5A",
"green" : "0x36",
"red" : "0x29"
}
},
"idiom" : "universal"

View File

@ -20,12 +20,12 @@
}
],
"color" : {
"color-space" : "srgb",
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0.333",
"green" : "0.192",
"red" : "0.141"
"blue" : "0x52",
"green" : "0x31",
"red" : "0x26"
}
},
"idiom" : "universal"

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x59",
"green" : "0x35",
"red" : "0x28"
"blue" : "0x47",
"green" : "0x37",
"red" : "0x2D"
}
},
"idiom" : "universal"
@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
"blue" : "0x00",
"green" : "0x00",
"red" : "0x00"
}
},
"idiom" : "universal"

View File

@ -39,6 +39,7 @@ enum OnboardingAction: Equatable {
case back
case skip
case createNewWallet
case importExistingWallet
}
typealias OnboardingReducer = Reducer<OnboardingState, OnboardingAction, Void>
@ -69,6 +70,9 @@ extension OnboardingReducer {
case .createNewWallet:
return .none
case .importExistingWallet:
return .none
}
}
}

View File

@ -44,9 +44,16 @@ internal enum Asset {
}
internal enum Buttons {
internal static let activeButton = ColorAsset(name: "ActiveButton")
internal static let activeButtonDisabled = ColorAsset(name: "ActiveButtonDisabled")
internal static let activeButtonPressed = ColorAsset(name: "ActiveButtonPressed")
internal static let buttonsTitleShadow = ColorAsset(name: "ButtonsTitleShadow")
internal static let createButton = ColorAsset(name: "CreateButton")
internal static let createButtonDisabled = ColorAsset(name: "CreateButtonDisabled")
internal static let createButtonPressed = ColorAsset(name: "CreateButtonPressed")
internal static let neumorphicButtonDarkSide = ColorAsset(name: "NeumorphicButtonDarkSide")
internal static let neumorphicButtonLightSide = ColorAsset(name: "NeumorphicButtonLightSide")
internal static let neumorphicDarkSide = ColorAsset(name: "NeumorphicDarkSide")
internal static let neumorphicLightSide = ColorAsset(name: "NeumorphicLightSide")
internal static let onboardingNavigation = ColorAsset(name: "OnboardingNavigation")
internal static let onboardingNavigationPressed = ColorAsset(name: "OnboardingNavigationPressed")
internal static let primaryButton = ColorAsset(name: "PrimaryButton")
@ -56,7 +63,11 @@ internal enum Asset {
internal static let secondaryButtonPressed = ColorAsset(name: "SecondaryButtonPressed")
}
internal enum Onboarding {
internal static let circularFrame = ColorAsset(name: "CircularFrame")
internal static let badgeShadow = ColorAsset(name: "BadgeShadow")
internal static let circularFrameDarkOutlineGradientEnd = ColorAsset(name: "CircularFrameDarkOutlineGradientEnd")
internal static let circularFrameDarkOutlineGradientStart = ColorAsset(name: "CircularFrameDarkOutlineGradientStart")
internal static let circularFrameGradientEnd = ColorAsset(name: "CircularFrameGradientEnd")
internal static let circularFrameGradientStart = ColorAsset(name: "CircularFrameGradientStart")
internal static let navigationButtonDisabled = ColorAsset(name: "NavigationButtonDisabled")
internal static let navigationButtonEnabled = ColorAsset(name: "NavigationButtonEnabled")
}

View File

@ -41,7 +41,7 @@ struct OnboardingContentView: View {
}
)
)
.frame(width: width * 0.85, height: width * 0.85)
.frame(width: circularFrameUniformSize(), height: circularFrameUniformSize())
.badgeIcons(
store.actionless.scope(
state: { state in
@ -52,7 +52,7 @@ struct OnboardingContentView: View {
}
)
)
.offset(y: viewStore.offset - height / 7)
.offset(y: viewStore.offset - height / circularFrameOffsetCoeff())
.transition(.scale(scale: 2).combined(with: .opacity))
}
}
@ -61,34 +61,76 @@ struct OnboardingContentView: View {
VStack(spacing: viewStore.isFinalStep ? 50 : 15) {
HStack {
Text(viewStore.steps[stepIndex].title)
.font(.custom(FontFamily.Roboto.bold.name, size: 30))
.fontWeight(.regular)
.titleText()
.lineLimit(0)
.minimumScaleFactor(0.1)
if !viewStore.isFinalStep {
Spacer()
}
}
Text(viewStore.steps[stepIndex].description)
.font(.custom(FontFamily.Roboto.regular.name, size: 15))
.lineSpacing(5)
.synopsisText()
.lineSpacing(2)
.opacity(0.53)
}
.opacity(stepIndex == viewStore.index ? 1: 0)
.padding(.horizontal, 35)
.frame(width: width, height: height)
}
}
.offset(y: viewStore.isFinalStep ? width / 2.3 : viewStore.offset + width / 2.3)
.offset(y: viewStore.isFinalStep ? width / 2.5 : viewStore.offset + height / descriptionOffsetCoeff())
}
}
}
/// Following computations are necessary to handle properly sizing and positioning of elements
/// on different devices (apects). iPhone SE and iPhone 8 are similar aspect family devices
/// while iPhone X, 11, etc are different family devices, capable to use more of the space.
extension OnboardingContentView {
func circularFrameUniformSize() -> CGFloat {
let aspect = height / width
let deviceMultiplier = 1.0 + (((aspect / 1.725) - 1.0) * 2.0)
return width * (0.6 * deviceMultiplier)
}
func circularFrameOffsetCoeff() -> CGFloat {
let aspect = height / width
let deviceMultiplier = aspect / 1.725
return 4.4 * deviceMultiplier
}
func descriptionOffsetCoeff() -> Double {
let aspect = height / width
let deviceMultiplier = 1.0 + (((aspect / 1.725) - 1.0) * 2.5)
return 8.0 / deviceMultiplier
}
}
struct OnboardingContentView_Previews: PreviewProvider {
static var previews: some View {
let store = Store(
initialState: OnboardingState(index: 2),
initialState: OnboardingState(index: 0),
reducer: OnboardingReducer.default,
environment: ()
)
OnboardingContentView_Previews.example(store)
.previewDevice(PreviewDevice(rawValue: "iPhone SE (2nd generation)"))
OnboardingContentView_Previews.example(store)
.previewDevice(PreviewDevice(rawValue: "iPhone 8"))
OnboardingContentView_Previews.example(store)
.previewDevice(PreviewDevice(rawValue: "iPhone 12 Pro"))
}
}
extension OnboardingContentView_Previews {
static func example(_ store: Store<OnboardingState, OnboardingAction>) -> some View {
GeometryReader { proxy in
ZStack {
OnboardingHeaderView(
@ -114,8 +156,9 @@ struct OnboardingContentView_Previews: PreviewProvider {
width: proxy.size.width,
height: proxy.size.height
)
.preferredColorScheme(.light)
}
}
.applyScreenBackground()
.preferredColorScheme(.light)
}
}

View File

@ -13,61 +13,85 @@ struct OnboardingFooterView: View {
let animationDuration: CGFloat = 0.8
var body: some View {
GeometryReader { proxy in
WithViewStore(self.store) { viewStore in
VStack(spacing: 5) {
Spacer()
if viewStore.isFinalStep {
Button("Create New Wallet") {
withAnimation(.easeInOut(duration: animationDuration)) {
viewStore.send(.createNewWallet)
}
WithViewStore(self.store) { viewStore in
VStack(spacing: 5) {
Spacer()
if viewStore.isFinalStep {
Button("Create New Wallet") {
withAnimation(.easeInOut(duration: animationDuration)) {
viewStore.send(.createNewWallet)
}
.primaryButtonStyle
.frame(height: proxy.size.height / 12)
.padding(.horizontal, 15)
.transition(.opacity)
} else {
Button("Next") {
withAnimation(.easeInOut(duration: animationDuration)) {
viewStore.send(.next)
}
}
.primaryButtonStyle
.frame(height: proxy.size.height / 12)
.padding(.horizontal, 15)
.transition(.opacity)
}
.createButtonStyle
.buttonLayout()
Button("Import an Existing Wallet") {
withAnimation(.easeInOut(duration: animationDuration)) {
viewStore.send(.createNewWallet)
}
}
.secondaryButtonStyle
.buttonLayout()
} else {
Button("Next") {
withAnimation(.easeInOut(duration: animationDuration)) {
viewStore.send(.next)
}
}
.primaryButtonStyle
.buttonLayout()
ProgressView(
"\(viewStore.index + 1)/\(viewStore.steps.count)",
"0\(viewStore.index + 1)",
value: Double(viewStore.index + 1),
total: Double(viewStore.steps.count)
)
.onboardingProgressStyle
.padding(.horizontal, 30)
.padding([.vertical], 20)
.onboardingProgressStyle
.padding(.horizontal, 30)
.padding(.vertical, 20)
}
}
}
}
}
struct OnboardingFooterButtonLayout: ViewModifier {
func body(content: Content) -> some View {
content
.frame(height: 60)
.padding(.horizontal, 28)
.transition(.opacity)
}
}
extension View {
func buttonLayout() -> some View {
modifier(OnboardingFooterButtonLayout())
}
}
struct OnboardingFooterView_Previews: PreviewProvider {
static var previews: some View {
let store = Store<OnboardingState, OnboardingAction>(
initialState: OnboardingState(index: 0),
initialState: OnboardingState(index: 3),
reducer: OnboardingReducer.default,
environment: ()
)
Group {
OnboardingFooterView(store: store)
.applyScreenBackground()
.preferredColorScheme(.light)
.previewDevice("iPhone 13 Pro Max")
OnboardingFooterView(store: store)
.applyScreenBackground()
.preferredColorScheme(.dark)
.previewDevice("iPhone 13 Pro Max")
OnboardingFooterView(store: store)
.applyScreenBackground()
.preferredColorScheme(.dark)
.previewDevice("iPhone 13 mini")
}

View File

@ -55,7 +55,7 @@ struct OnboardingHeaderView: View {
Spacer()
}
.padding(.top, 20)
.padding(.top, 5)
}
}
}
@ -85,5 +85,6 @@ struct OnboardingHeaderView_Previews: PreviewProvider {
)
)
.preferredColorScheme(.light)
.applyScreenBackground()
}
}

View File

@ -56,5 +56,56 @@ struct OnboardingScreen_Previews: PreviewProvider {
)
)
.preferredColorScheme(.light)
.previewDevice(PreviewDevice(rawValue: "iPhone SE (2nd generation)"))
OnboardingScreen(
store: Store(
initialState: OnboardingState(),
reducer: OnboardingReducer.default,
environment: ()
)
)
.preferredColorScheme(.light)
.previewDevice(PreviewDevice(rawValue: "iPhone 8"))
OnboardingScreen(
store: Store(
initialState: OnboardingState(),
reducer: OnboardingReducer.default,
environment: ()
)
)
.preferredColorScheme(.light)
.previewDevice(PreviewDevice(rawValue: "iPhone 12 Pro"))
OnboardingScreen(
store: Store(
initialState: OnboardingState(),
reducer: OnboardingReducer.default,
environment: ()
)
)
.preferredColorScheme(.dark)
.previewDevice(PreviewDevice(rawValue: "iPhone SE (2nd generation)"))
OnboardingScreen(
store: Store(
initialState: OnboardingState(),
reducer: OnboardingReducer.default,
environment: ()
)
)
.preferredColorScheme(.dark)
.previewDevice(PreviewDevice(rawValue: "iPhone 8"))
OnboardingScreen(
store: Store(
initialState: OnboardingState(),
reducer: OnboardingReducer.default,
environment: ()
)
)
.preferredColorScheme(.dark)
.previewDevice(PreviewDevice(rawValue: "iPhone 12 Pro"))
}
}

View File

@ -13,7 +13,8 @@ extension Button {
StandardButtonStyle(
foregroundColor: Asset.Colors.Text.activeButtonText.color,
background: Asset.Colors.Buttons.activeButton.color,
pressedBackgroundColor: Asset.Colors.Buttons.activeButton.color
pressedBackgroundColor: Asset.Colors.Buttons.activeButtonPressed.color,
disabledBackgroundColor: Asset.Colors.Buttons.activeButtonDisabled.color
)
)
}

View File

@ -13,7 +13,8 @@ extension Button {
StandardButtonStyle(
foregroundColor: Asset.Colors.Text.button.color,
background: Asset.Colors.Buttons.createButton.color,
pressedBackgroundColor: Asset.Colors.Buttons.createButtonPressed.color
pressedBackgroundColor: Asset.Colors.Buttons.createButtonPressed.color,
disabledBackgroundColor: Asset.Colors.Buttons.createButtonDisabled.color
)
)
}

View File

@ -8,6 +8,8 @@
import SwiftUI
struct NavigationButtonStyle: ButtonStyle {
@Environment(\.colorScheme) var colorScheme
func makeBody(configuration: Configuration) -> some View {
configuration.label
.frame(
@ -23,6 +25,7 @@ struct NavigationButtonStyle: ButtonStyle {
Asset.Colors.Buttons.onboardingNavigation.color
)
.cornerRadius(.infinity)
.neumorphicButtonDesign(configuration.isPressed)
}
}
@ -39,12 +42,14 @@ struct NavigationModifier_Previews: PreviewProvider {
Button("Back") { dump("Example button") }
.navigationButtonStyle
.frame(width: 80, height: 40)
.applyScreenBackground()
.previewLayout(.fixed(width: 300, height: 100))
.preferredColorScheme(.dark)
Button("Skip") { dump("Example button") }
.navigationButtonStyle
.frame(width: 80, height: 40)
.applyScreenBackground()
.previewLayout(.fixed(width: 300, height: 100))
.preferredColorScheme(.light)
}

View File

@ -0,0 +1,79 @@
//
// NeumorphicDesignModifier.swift
// secant-testnet
//
// Created by Lukáš Korba on 02/21/22.
//
import SwiftUI
/// Neumorphic design is charasterictical with two shadows (light & dark) around the view
/// Appereance in our case is influenced by two parameters:
/// - Parameters:
/// - colorScheme: The light is using full neumorphic design while dark is limited to soft shadow only
/// - isPressed: When the button is pressed, there are different behaviours for light vs. dark colorScheme
/// This design is mostly used for CircularFrame, not designed for a button (see NeumorphicButtonDesign)
struct NeumorphicDesign: ViewModifier {
@Environment(\.colorScheme) var colorScheme
let isPressed: Bool
init(_ isPressed: Bool) {
self.isPressed = isPressed
}
func body(content: Content) -> some View {
content
.shadow(
color: Asset.Colors.Buttons.neumorphicDarkSide.color,
radius: 15,
x: colorScheme == .light && !isPressed ? 10 : -10,
y: colorScheme == .light && !isPressed ? 10 : 10
)
.shadow(
color: Asset.Colors.Buttons.neumorphicLightSide.color,
radius: 10,
x: colorScheme == .light && !isPressed ? -12 : 12,
y: colorScheme == .light && !isPressed ? -12 : -12
)
}
}
/// Neumorphic design is charasterictical with two shadows (light & dark) around the button
/// Appereance in our case is influenced by two parameters:
/// - Parameters:
/// - colorScheme: The light is using full neumorphic design while dark is limited to soft shadow only
/// - isPressed: When the button is pressed, there are different behaviours for light vs. dark colorScheme
/// This design is specifically crafted for buttons. The colors and positions of the shadows are different.
struct NeumorphicButtonDesign: ViewModifier {
@Environment(\.colorScheme) var colorScheme
let isPressed: Bool
init(_ isPressed: Bool) {
self.isPressed = isPressed
}
func body(content: Content) -> some View {
content
.shadow(
color: Asset.Colors.Buttons.neumorphicButtonDarkSide.color,
radius: 15,
x: colorScheme == .light && !isPressed ? 10 : 0,
y: colorScheme == .light && !isPressed ? 10 : 0
)
.shadow(
color: Asset.Colors.Buttons.neumorphicButtonLightSide.color,
radius: 10,
x: colorScheme == .light && !isPressed ? -12 : 0,
y: colorScheme == .light && !isPressed ? -12 : 0
)
}
}
extension View {
func neumorphicDesign(_ isPressed: Bool = false) -> some View {
self.modifier(NeumorphicDesign(isPressed))
}
func neumorphicButtonDesign(_ isPressed: Bool = false) -> some View {
self.modifier(NeumorphicButtonDesign(isPressed))
}
}

View File

@ -12,8 +12,9 @@ extension Button {
buttonStyle(
StandardButtonStyle(
foregroundColor: Asset.Colors.Text.button.color,
background: Asset.Colors.Buttons.primaryButtonPressed.color,
pressedBackgroundColor: Asset.Colors.Buttons.primaryButtonPressed.color
background: Asset.Colors.Buttons.primaryButton.color,
pressedBackgroundColor: Asset.Colors.Buttons.primaryButtonPressed.color,
disabledBackgroundColor: Asset.Colors.Buttons.primaryButtonDisabled.color
)
)
}
@ -26,11 +27,13 @@ struct PrimaryButton_Previews: PreviewProvider {
.frame(width: 250, height: 50)
.previewLayout(.fixed(width: 300, height: 100))
.preferredColorScheme(.light)
.applyScreenBackground()
Button("Primary Button") { dump("Primary button") }
.primaryButtonStyle
.frame(width: 250, height: 50)
.previewLayout(.fixed(width: 300, height: 100))
.preferredColorScheme(.dark)
.applyScreenBackground()
}
}

View File

@ -13,7 +13,8 @@ extension Button {
StandardButtonStyle(
foregroundColor: Asset.Colors.Text.secondaryButtonText.color,
background: Asset.Colors.Buttons.secondaryButton.color,
pressedBackgroundColor: Asset.Colors.Buttons.secondaryButtonPressed.color
pressedBackgroundColor: Asset.Colors.Buttons.secondaryButtonPressed.color,
disabledBackgroundColor: Asset.Colors.Buttons.secondaryButton.color
)
)
}

View File

@ -8,12 +8,16 @@
import SwiftUI
struct StandardButtonStyle: ButtonStyle {
@Environment(\.isEnabled) private var isEnabled: Bool
let foregroundColor: Color
let background: Color
let pressedBackgroundColor: Color
let disabledBackgroundColor: Color
func makeBody(configuration: Configuration) -> some View {
configuration.label
.shadow(color: Asset.Colors.Buttons.buttonsTitleShadow.color, radius: 2, x: 0, y: 2)
.frame(
minWidth: 0,
maxWidth: .infinity,
@ -22,9 +26,12 @@ struct StandardButtonStyle: ButtonStyle {
)
.foregroundColor(foregroundColor)
.background(
configuration.isPressed ? pressedBackgroundColor : background
isEnabled ?
(configuration.isPressed ? pressedBackgroundColor : background)
: disabledBackgroundColor
)
.cornerRadius(12)
.neumorphicButtonDesign(configuration.isPressed)
}
}
@ -34,7 +41,8 @@ private extension Button {
StandardButtonStyle(
foregroundColor: Asset.Colors.Text.button.color,
background: Asset.Colors.Buttons.createButton.color,
pressedBackgroundColor: Asset.Colors.Buttons.createButtonPressed.color
pressedBackgroundColor: Asset.Colors.Buttons.createButtonPressed.color,
disabledBackgroundColor: Asset.Colors.Buttons.createButtonDisabled.color
)
)
}

View File

@ -8,22 +8,44 @@
import SwiftUI
struct CircularFrame: View {
@Environment(\.colorScheme) var colorScheme
var body: some View {
GeometryReader { proxy in
let lineWidth = proxy.size.width * 0.05
let lineWidth = proxy.size.width * 0.06
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
.stroke(
LinearGradient(
colors: [
Asset.Colors.Onboarding.circularFrameGradientStart.color,
Asset.Colors.Onboarding.circularFrameGradientEnd.color
],
startPoint: colorScheme == .light ? .topLeading : .top,
endPoint: colorScheme == .light ? .bottomTrailing : .bottom
),
style: StrokeStyle(
lineWidth: lineWidth
)
)
// Update the offset to account for the 2 extra points
.offset(x: lineWidth / 2 - 1, y: lineWidth / 2 - 1)
.shadow(radius: 10)
.padding(colorScheme == .light ? 0 : 10)
if colorScheme == .dark {
Circle()
.stroke(
LinearGradient(
colors: [
Asset.Colors.Onboarding.circularFrameDarkOutlineGradientStart.color,
Asset.Colors.Onboarding.circularFrameDarkOutlineGradientEnd.color
],
startPoint: .top,
endPoint: .bottom
),
style: StrokeStyle(
lineWidth: lineWidth * 0.15
)
)
}
}
}
}
@ -114,7 +136,8 @@ struct CircularFramePreviewHelper: View {
struct CircularFrame_Previews: PreviewProvider {
static var previews: some View {
CircularFramePreviewHelper()
.preferredColorScheme(.light)
.preferredColorScheme(.dark)
.previewLayout(.device)
.applyScreenBackground()
}
}

View File

@ -26,6 +26,7 @@ struct CircularFrameBackgroundImages: Animatable, ViewModifier {
.opacity(imageIndex == viewStore.index ? 1 : 0)
.offset(x: imageIndex <= viewStore.index ? 0 : 25)
.mask(Circle())
.neumorphicDesign()
}
content
@ -43,6 +44,7 @@ struct CircularFrameBackgroundImage: Animatable, ViewModifier {
.resizable()
.aspectRatio(1.3, contentMode: .fill)
.mask(Circle())
.neumorphicDesign()
content
}
@ -66,18 +68,26 @@ struct CircularFrameBackground_Previews: PreviewProvider {
CircularFrame()
.backgroundImage(Asset.Assets.Backgrounds.callout0.image)
.frame(width: 300, height: 300)
.applyScreenBackground()
.neumorphicDesign()
CircularFrame()
.backgroundImage(Asset.Assets.Backgrounds.callout1.image)
.frame(width: 300, height: 300)
.applyScreenBackground()
.neumorphicDesign()
CircularFrame()
.backgroundImage(Asset.Assets.Backgrounds.callout2.image)
.frame(width: 300, height: 300)
.applyScreenBackground()
.neumorphicDesign()
CircularFrame()
.backgroundImage(Asset.Assets.Backgrounds.callout3.image)
.frame(width: 300, height: 300)
.applyScreenBackground()
.neumorphicDesign()
}
.preferredColorScheme(.light)
.previewLayout(.fixed(width: size + 50, height: size + 50))

View File

@ -77,6 +77,7 @@ struct BadgesOverlay: Animatable, ViewModifier {
y: proxy.size.height * 0.15
)
.opacity(badgeIndex == viewStore.index ? 1 : 0)
.shadow(color: Asset.Colors.Onboarding.badgeShadow.color, radius: 10, x: 0, y: 0)
}
}
@ -114,6 +115,7 @@ struct BadgeOverlay: Animatable, ViewModifier {
)
.transition(.scale(scale: 2))
.transition(.opacity)
.shadow(color: Asset.Colors.Onboarding.badgeShadow.color, radius: 10, x: 0, y: 0)
Spacer()
}
}

View File

@ -118,11 +118,11 @@ struct ButtonGuide: View {
.primaryButtonStyle
.frame(height: buttonHeight)
// TODO: Pressed Primary Button
// Pressed Primary Button
Button(action: {}) {
Text("Pressed Primary Button")
}
.primaryButtonStyle
.primaryButtonPressedStyle
.frame(height: buttonHeight)
// Disabled Primary Button
@ -140,14 +140,14 @@ struct ButtonGuide: View {
.activeButtonStyle
.frame(height: buttonHeight)
// TODO: Pressed Active Button
// Pressed Active Button
Button(action: {}) {
Text("Pressed Active Button")
}
.activeButtonStyle
.activeButtonPressedStyle
.frame(height: buttonHeight)
// TODO: Disabled Active Button
// Disabled Active Button
Button(action: {}) {
Text("Disabled Active Button")
}
@ -189,3 +189,31 @@ struct DesignGuide_Previews: PreviewProvider {
.previewLayout(.fixed(width: 1086, height: 1080))
}
}
// MARK: - Pressed Simulated
extension Button {
var primaryButtonPressedStyle: some View {
buttonStyle(
StandardButtonStyle(
foregroundColor: Asset.Colors.Text.button.color,
background: Asset.Colors.Buttons.primaryButtonPressed.color,
pressedBackgroundColor: Asset.Colors.Buttons.primaryButtonPressed.color,
disabledBackgroundColor: Asset.Colors.Buttons.primaryButtonDisabled.color
)
)
}
var activeButtonPressedStyle: some View {
buttonStyle(
StandardButtonStyle(
foregroundColor: Asset.Colors.Text.activeButtonText.color,
background: Asset.Colors.Buttons.activeButtonPressed.color,
pressedBackgroundColor: Asset.Colors.Buttons.activeButtonPressed.color,
disabledBackgroundColor: Asset.Colors.Buttons.activeButtonDisabled.color
)
)
}
}

View File

@ -0,0 +1,23 @@
//
// SecantButtonStyles.swift
// secant-testnet
//
// Created by Lukáš Korba on 02/22/22.
//
import SwiftUI
extension Button {
func titleText() -> some View {
self.modifier(TitleTextStyle())
}
private struct TitleTextStyle: ViewModifier {
func body(content: Content) -> some View {
content
.foregroundColor(Asset.Colors.Text.heading.color)
.font(.custom(FontFamily.Rubik.regular.name, size: 15))
.shadow(color: Asset.Colors.Text.captionTextShadow.color, radius: 1, x: 0, y: 1)
}
}
}

View File

@ -21,6 +21,10 @@ extension Text {
self.modifier(TitleTextStyle())
}
func synopsisText() -> some View {
self.modifier(SynopsisStyle())
}
/// Body text style. Used for content. Roboto-Regular 18pt
private struct BodyTextStyle: ViewModifier {
func body(content: Content) -> some View {
@ -30,11 +34,20 @@ extension Text {
}
}
/// Used for additional information, explanations, context (usually paragraphs)
private struct SynopsisStyle: ViewModifier {
func body(content: Content) -> some View {
content
.foregroundColor(Asset.Colors.Text.heading.color)
.font(.custom(FontFamily.Rubik.regular.name, size: 16))
}
}
private struct TitleTextStyle: ViewModifier {
func body(content: Content) -> some View {
content
.foregroundColor(Asset.Colors.Text.heading.color)
.font(.custom(FontFamily.Rubik.regular.name, size: 33))
.font(.custom(FontFamily.Rubik.regular.name, size: 33, relativeTo: .callout))
.shadow(color: Asset.Colors.Text.captionTextShadow.color, radius: 1, x: 0, y: 1)
}
}

View File

@ -15,8 +15,8 @@ struct OnboardingProgressStyle: ProgressViewStyle {
Asset.Colors.ProgressIndicator.gradientLeft.color,
Asset.Colors.ProgressIndicator.gradientRight.color
],
startPoint: UnitPoint(x: 0.00, y: 0.00),
endPoint: UnitPoint(x: 1.00, y: 0.00)
startPoint: .leading,
endPoint: .trailing
)
func makeBody(configuration: Configuration) -> some View {
@ -25,7 +25,9 @@ struct OnboardingProgressStyle: ProgressViewStyle {
return VStack {
HStack {
configuration.label
.foregroundColor(Asset.Colors.ProgressIndicator.negativeSpace.color)
.foregroundColor(Asset.Colors.Text.heading.color)
.font(.custom(FontFamily.Rubik.regular.name, size: 16))
.opacity(0.3)
Spacer()
}