mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 19:44:05 +00:00
Fix the AuthenticationStartScreen with large Dynamic Type sizes. (#5191)
* Allow AuthenticationStartLogo to be scaled and fix dark mode when not on a gradient. * Fix the layout of AuthenticationStartScreen with large Dynamic Type sizes.
This commit is contained in:
+123
-31
@@ -10,80 +10,132 @@ import SwiftUI
|
||||
|
||||
/// The app's logo styled to fit on various launch pages.
|
||||
struct AuthenticationStartLogo: View {
|
||||
/// Set to specify a custom size for the Logo, otherwise the default size of 158pt will be used.
|
||||
var size: CGFloat?
|
||||
/// Set to `true` to skip the brand chrome.
|
||||
let hideBrandChrome: Bool
|
||||
/// Set to `true` when using on top of `Asset.Images.launchBackground`.
|
||||
let isOnGradient: Bool
|
||||
|
||||
private let appLogoImage = Image(asset: Asset.Images.appLogo)
|
||||
|
||||
struct SizeMetrics {
|
||||
let scale: CGFloat
|
||||
let imageSize: CGFloat
|
||||
}
|
||||
|
||||
private var sizeMetrics: SizeMetrics? {
|
||||
size.map { customSize in
|
||||
let scale = customSize / 158
|
||||
return SizeMetrics(scale: scale,
|
||||
imageSize: hideBrandChrome ? customSize : 110 * scale)
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
if let sizeMetrics {
|
||||
appLogoImage
|
||||
.resizable()
|
||||
.frame(width: sizeMetrics.imageSize, height: sizeMetrics.imageSize)
|
||||
.modifier(AuthenticationBrandLogoModifier(scale: sizeMetrics.scale,
|
||||
hideBrandChrome: hideBrandChrome,
|
||||
isOnGradient: isOnGradient))
|
||||
} else {
|
||||
appLogoImage
|
||||
.modifier(AuthenticationBrandLogoModifier(scale: 1,
|
||||
hideBrandChrome: hideBrandChrome,
|
||||
isOnGradient: isOnGradient))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies the brand chrome styling (rounded card with shadows and border) to any image,
|
||||
/// as seen on the authentication start screen.
|
||||
private struct AuthenticationBrandLogoModifier: ViewModifier {
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
|
||||
/// Set to `true` when using on top of `Asset.Images.launchBackground`
|
||||
/// Scale factor relative to the original 158pt design.
|
||||
let scale: CGFloat
|
||||
/// Set to `true` to skip the brand chrome.
|
||||
let hideBrandChrome: Bool
|
||||
/// Set to `true` when using on top of `Asset.Images.launchBackground`.
|
||||
let isOnGradient: Bool
|
||||
|
||||
/// Extra padding needed to avoid cropping the shadows.
|
||||
private let extra: CGFloat = 64
|
||||
/// The shape that the logo is composed on top of.
|
||||
private let outerShape = RoundedRectangle(cornerRadius: 44)
|
||||
private let outerShapeShadowColor = Color(red: 0.11, green: 0.11, blue: 0.13)
|
||||
private var isLight: Bool {
|
||||
colorScheme == .light
|
||||
}
|
||||
|
||||
/// Extra padding needed to avoid cropping the shadows.
|
||||
private var extra: CGFloat {
|
||||
64 * scale
|
||||
}
|
||||
|
||||
/// The shape that the logo is composed on top of.
|
||||
private var outerShape: RoundedRectangle {
|
||||
RoundedRectangle(cornerRadius: 44 * scale)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
func body(content: Content) -> some View {
|
||||
if hideBrandChrome {
|
||||
Image(asset: Asset.Images.appLogo)
|
||||
content
|
||||
} else {
|
||||
brandLogo
|
||||
styledContent(content)
|
||||
}
|
||||
}
|
||||
|
||||
private var brandLogo: some View {
|
||||
Image(asset: Asset.Images.appLogo)
|
||||
private func styledContent(_ content: Content) -> some View {
|
||||
content
|
||||
.background {
|
||||
Circle()
|
||||
.inset(by: 1)
|
||||
.shadow(color: .black.opacity(!isLight ? 0.3 : 0.4),
|
||||
radius: 12.57143,
|
||||
y: 6.28571)
|
||||
.inset(by: 1 * scale)
|
||||
.shadow(color: .black.opacity(!isLight && isOnGradient ? 0.3 : 0.4),
|
||||
radius: 12.57143 * scale,
|
||||
y: 6.28571 * scale)
|
||||
|
||||
Circle()
|
||||
.inset(by: 1)
|
||||
.inset(by: 1 * scale)
|
||||
.shadow(color: .black.opacity(0.5),
|
||||
radius: 12.57143,
|
||||
y: 6.28571)
|
||||
radius: 12.57143 * scale,
|
||||
y: 6.28571 * scale)
|
||||
.blendMode(.overlay)
|
||||
}
|
||||
.padding(24)
|
||||
.padding(24 * scale)
|
||||
.background {
|
||||
Color.white
|
||||
.opacity(isLight ? 0.23 : 0.05)
|
||||
.opacity(isLight ? 0.23 : isOnGradient ? 0.05 : 0.13)
|
||||
}
|
||||
.clipShape(outerShape)
|
||||
.overlay {
|
||||
outerShape
|
||||
.inset(by: 0.25)
|
||||
.stroke(.white.opacity(isLight ? 1 : 0.9), lineWidth: 0.5)
|
||||
.inset(by: 0.25 * scale)
|
||||
.stroke(.white.opacity(isLight ? 1 : isOnGradient ? 0.9 : 0.25), lineWidth: 0.5 * scale)
|
||||
.blendMode(isLight ? .normal : .overlay)
|
||||
}
|
||||
.padding(extra)
|
||||
.background {
|
||||
ZStack {
|
||||
if !isLight {
|
||||
if !isLight, isOnGradient {
|
||||
outerShape
|
||||
.inset(by: 1)
|
||||
.inset(by: 1 * scale)
|
||||
.padding(extra)
|
||||
.shadow(color: .black.opacity(0.5),
|
||||
radius: 32.91666,
|
||||
y: 1.05333)
|
||||
radius: 32.91666 * scale,
|
||||
y: 1.05333 * scale)
|
||||
} else {
|
||||
outerShape
|
||||
.inset(by: 1)
|
||||
.inset(by: 1 * scale)
|
||||
.padding(extra)
|
||||
.shadow(color: outerShapeShadowColor.opacity(isLight ? 0.23 : 0.08),
|
||||
radius: 16,
|
||||
y: 8)
|
||||
radius: 16 * scale,
|
||||
y: 8 * scale)
|
||||
|
||||
outerShape
|
||||
.inset(by: 1)
|
||||
.inset(by: 1 * scale)
|
||||
.padding(extra)
|
||||
.shadow(color: outerShapeShadowColor.opacity(0.5),
|
||||
radius: 16,
|
||||
y: 8)
|
||||
radius: 16 * scale,
|
||||
y: 8 * scale)
|
||||
.blendMode(.overlay)
|
||||
}
|
||||
}
|
||||
@@ -98,3 +150,43 @@ struct AuthenticationStartLogo: View {
|
||||
.accessibilityHidden(true)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
VStack(spacing: 0) {
|
||||
HStack(spacing: 0) {
|
||||
AuthenticationStartLogo(hideBrandChrome: false, isOnGradient: false)
|
||||
.padding()
|
||||
AuthenticationStartLogo(hideBrandChrome: false, isOnGradient: true)
|
||||
.padding()
|
||||
.background {
|
||||
AuthenticationStartScreenBackgroundImage().offset(y: 70)
|
||||
}
|
||||
.clipped()
|
||||
}
|
||||
.background(.compound.bgCanvasDefault)
|
||||
|
||||
HStack(spacing: 0) {
|
||||
AuthenticationStartLogo(hideBrandChrome: false, isOnGradient: false)
|
||||
.padding()
|
||||
AuthenticationStartLogo(hideBrandChrome: false, isOnGradient: true)
|
||||
.padding()
|
||||
.background {
|
||||
AuthenticationStartScreenBackgroundImage().offset(y: 70)
|
||||
}
|
||||
.clipped()
|
||||
}
|
||||
.background(.compound.bgCanvasDefault)
|
||||
.colorScheme(.dark)
|
||||
|
||||
HStack(spacing: 0) {
|
||||
AuthenticationStartLogo(size: 54, hideBrandChrome: false, isOnGradient: false)
|
||||
.padding()
|
||||
.background(.compound.bgCanvasDefault)
|
||||
AuthenticationStartLogo(size: 54, hideBrandChrome: false, isOnGradient: false)
|
||||
.padding()
|
||||
.background(.compound.bgCanvasDefault)
|
||||
.colorScheme(.dark)
|
||||
}
|
||||
.padding(.top)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user