diff --git a/CHANGES.rst b/CHANGES.rst index cac04f6a2..679b2f8f0 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,10 +5,10 @@ Changes to be released in next version * 🙌 Improvements - * + * DesignKit: Add Fonts (#4356). 🐛 Bugfix - * + * SSO: Handle login callback URL with HTML entities (#4129). ⚠️ API Changes * diff --git a/DesignKit/Extensions/UIFont.swift b/DesignKit/Extensions/UIFont.swift new file mode 100644 index 000000000..7804c8066 --- /dev/null +++ b/DesignKit/Extensions/UIFont.swift @@ -0,0 +1,55 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import UIKit + +public extension UIFont { + + // MARK: - Convenient methods + + /// Update current font with a SymbolicTraits + func vc_withTraits(_ traits: UIFontDescriptor.SymbolicTraits) -> UIFont { + guard let descriptor = fontDescriptor.withSymbolicTraits(traits) else { + return self + } + return UIFont(descriptor: descriptor, size: 0) // Size 0 means keep the size as it is + } + + /// Update current font with a given Weight + func vc_withWeight(weight: Weight) -> UIFont { + // Add the font weight to the descriptor + let weightedFontDescriptor = fontDescriptor.addingAttributes([ + UIFontDescriptor.AttributeName.traits: [ + UIFontDescriptor.TraitKey.weight: weight + ] + ]) + return UIFont(descriptor: weightedFontDescriptor, size: 0) + } + + // MARK: - Shortcuts + + var vc_bold: UIFont { + return self.vc_withTraits(.traitBold) + } + + var vc_semiBold: UIFont { + return self.vc_withWeight(weight: .semibold) + } + + var vc_italic: UIFont { + return self.vc_withTraits(.traitItalic) + } +} diff --git a/DesignKit/Source/Fonts.swift b/DesignKit/Source/Fonts.swift new file mode 100644 index 000000000..1cce963ed --- /dev/null +++ b/DesignKit/Source/Fonts.swift @@ -0,0 +1,83 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import UIKit + +/// Describe fonts used in the application. +/// Font names are based on Element typograhy https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=1362%3A0 which is based on Apple font text styles (UIFont.TextStyle): https://developer.apple.com/documentation/uikit/uifonttextstyle +/// Create a custom TextStyle enum (like DesignKit.Fonts.TextStyle) is also a possiblity +@objc public protocol Fonts { + + /// The font for large titles. + var largeTitle: UIFont { get } + + /// `largeTitle` with a Bold weight. + var largeTitleB: UIFont { get } + + /// The font for first-level hierarchical headings. + var title1: UIFont { get } + + /// `title1` with a Bold weight. + var title1B: UIFont { get } + + /// The font for second-level hierarchical headings. + var title2: UIFont { get } + + /// `title2` with a Bold weight. + var title2B: UIFont { get } + + /// The font for third-level hierarchical headings. + var title3: UIFont { get } + + /// `title3` with a Semi Bold weight. + var title3SB: UIFont { get } + + /// The font for headings. + var headline: UIFont { get } + + /// The font for subheadings. + var subheadline: UIFont { get } + + /// The font for body text. + var body: UIFont { get } + + /// `body` with a Semi Bold weight. + var bodySB: UIFont { get } + + /// The font for callouts. + var callout: UIFont { get } + + /// `callout` with a Semi Bold weight. + var calloutSB: UIFont { get } + + /// The font for footnotes. + var footnote: UIFont { get } + + /// `footnote` with a Semi Bold weight. + var footnoteSB: UIFont { get } + + /// The font for standard captions. + var caption1: UIFont { get } + + /// `caption1` with a Semi Bold weight. + var caption1SB: UIFont { get } + + /// The font for alternate captions. + var caption2: UIFont { get } + + /// `caption2` with a Semi Bold weight. + var caption2SB: UIFont { get } +} diff --git a/DesignKit/Source/ThemeV2.swift b/DesignKit/Source/ThemeV2.swift index 48f310992..785639861 100644 --- a/DesignKit/Source/ThemeV2.swift +++ b/DesignKit/Source/ThemeV2.swift @@ -23,6 +23,9 @@ import UIKit /// Colors object var colors: Colors { get } + /// Fonts object + var fonts: Fonts { get } + /// may contain more design components in future, like icons, audio files etc. } diff --git a/DesignKit/Variants/Dark/DarkColors.swift b/DesignKit/Variants/Colors/Dark/DarkColors.swift similarity index 100% rename from DesignKit/Variants/Dark/DarkColors.swift rename to DesignKit/Variants/Colors/Dark/DarkColors.swift diff --git a/DesignKit/Variants/Light/LightColors.swift b/DesignKit/Variants/Colors/Light/LightColors.swift similarity index 100% rename from DesignKit/Variants/Light/LightColors.swift rename to DesignKit/Variants/Colors/Light/LightColors.swift diff --git a/DesignKit/Variants/Fonts/ElementFonts.swift b/DesignKit/Variants/Fonts/ElementFonts.swift new file mode 100644 index 000000000..6612d3dc1 --- /dev/null +++ b/DesignKit/Variants/Fonts/ElementFonts.swift @@ -0,0 +1,119 @@ +// +// Copyright 2021 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import UIKit + +/// Fonts at https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=1362%3A0 +@objcMembers +public class ElementFonts { + + // MARK: - Setup + + public init() { + } + + // MARK: - Private + + /// Returns an instance of the font associated with the text style and scaled appropriately for the content size category defined in the trait collection. + /// Keep this method private method at the moment and create a DesignKit.Fonts.TextStyle if needed. + fileprivate func font(forTextStyle textStyle: UIFont.TextStyle, compatibleWith traitCollection: UITraitCollection? = nil) -> UIFont { + return UIFont.preferredFont(forTextStyle: textStyle, compatibleWith: traitCollection) + } +} + +// MARK: - Fonts protocol +extension ElementFonts: Fonts { + + public var largeTitle: UIFont { + return self.font(forTextStyle: .largeTitle) + } + + public var largeTitleB: UIFont { + return self.largeTitle.vc_bold + } + + public var title1: UIFont { + return self.font(forTextStyle: .title1) + } + + public var title1B: UIFont { + return self.title1.vc_bold + } + + public var title2: UIFont { + return self.font(forTextStyle: .title2) + } + + public var title2B: UIFont { + return self.title2.vc_bold + } + + public var title3: UIFont { + return self.font(forTextStyle: .title3) + } + + public var title3SB: UIFont { + return self.title3.vc_semiBold + } + + public var headline: UIFont { + return self.font(forTextStyle: .headline) + } + + public var subheadline: UIFont { + return self.font(forTextStyle: .subheadline) + } + + public var body: UIFont { + return self.font(forTextStyle: .body) + } + + public var bodySB: UIFont { + return self.body.vc_semiBold + } + + public var callout: UIFont { + return self.font(forTextStyle: .callout) + } + + public var calloutSB: UIFont { + return self.callout.vc_semiBold + } + + public var footnote: UIFont { + return self.font(forTextStyle: .footnote) + } + + public var footnoteSB: UIFont { + return self.footnote.vc_semiBold + } + + public var caption1: UIFont { + return self.font(forTextStyle: .caption1) + } + + public var caption1SB: UIFont { + return self.caption1.vc_semiBold + } + + public var caption2: UIFont { + return self.font(forTextStyle: .caption2) + } + + public var caption2SB: UIFont { + return self.caption2.vc_semiBold + } +} diff --git a/Riot/Managers/Theme/Themes/DarkTheme.swift b/Riot/Managers/Theme/Themes/DarkTheme.swift index a3bc39557..7ce49c214 100644 --- a/Riot/Managers/Theme/Themes/DarkTheme.swift +++ b/Riot/Managers/Theme/Themes/DarkTheme.swift @@ -146,4 +146,8 @@ class DarkTheme: NSObject, Theme { lazy var colors: Colors = { return DarkColors() }() + + lazy var fonts: Fonts = { + return ElementFonts() + }() } diff --git a/Riot/Managers/Theme/Themes/DefaultTheme.swift b/Riot/Managers/Theme/Themes/DefaultTheme.swift index 7f6ae77b1..770f33a90 100644 --- a/Riot/Managers/Theme/Themes/DefaultTheme.swift +++ b/Riot/Managers/Theme/Themes/DefaultTheme.swift @@ -153,4 +153,8 @@ class DefaultTheme: NSObject, Theme { lazy var colors: Colors = { return LightColors() }() + + lazy var fonts: Fonts = { + return ElementFonts() + }() } diff --git a/Riot/Modules/Authentication/AuthenticationViewController.m b/Riot/Modules/Authentication/AuthenticationViewController.m index b7a64071f..d56c7511e 100644 --- a/Riot/Modules/Authentication/AuthenticationViewController.m +++ b/Riot/Modules/Authentication/AuthenticationViewController.m @@ -83,6 +83,8 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; @property (nonatomic, getter = isFirstViewAppearing) BOOL firstViewAppearing; +@property (nonatomic, strong) MXKErrorAlertPresentation *errorPresenter; + @end @implementation AuthenticationViewController @@ -118,6 +120,7 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; _firstViewAppearing = YES; self.crossSigningService = [CrossSigningService new]; + self.errorPresenter = [MXKErrorAlertPresentation new]; } - (void)viewDidLoad @@ -1817,6 +1820,7 @@ static const CGFloat kAuthInputContainerViewMinHeightConstraintConstant = 150.0; - (void)ssoAuthenticationPresenter:(SSOAuthenticationPresenter *)presenter authenticationDidFailWithError:(NSError *)error { [self dismissSSOAuthenticationPresenter]; + [self.errorPresenter presentErrorFromViewController:self forError:error animated:YES handler:nil]; } - (void)ssoAuthenticationPresenter:(SSOAuthenticationPresenter *)presenter authenticationSucceededWithToken:(NSString *)token diff --git a/Riot/Modules/Authentication/SSO/SSOAuthenticationService.swift b/Riot/Modules/Authentication/SSO/SSOAuthenticationService.swift index 314a984a1..d00094b85 100644 --- a/Riot/Modules/Authentication/SSO/SSOAuthenticationService.swift +++ b/Riot/Modules/Authentication/SSO/SSOAuthenticationService.swift @@ -70,7 +70,9 @@ final class SSOAuthenticationService: NSObject { } func loginToken(from url: URL) -> String? { - guard let components = URLComponents(string: url.absoluteString) else { + // If needed convert URL string from HTML entities into correct character representations using UTF8 (like '&' with '&') + guard let sanitizedStringURL = url.absoluteString.replacingHTMLEntities(), + let components = URLComponents(string: sanitizedStringURL) else { return nil } return components.vc_getQueryItemValue(for: SSOURLConstants.Parameters.callbackLoginToken) diff --git a/Riot/Modules/SideMenu/SideMenuViewController.swift b/Riot/Modules/SideMenu/SideMenuViewController.swift index 0851ec8df..57f98b059 100644 --- a/Riot/Modules/SideMenu/SideMenuViewController.swift +++ b/Riot/Modules/SideMenu/SideMenuViewController.swift @@ -107,6 +107,7 @@ final class SideMenuViewController: UIViewController { self.userAvatarView.update(theme: theme) self.userDisplayNameLabel.textColor = theme.textPrimaryColor + self.userDisplayNameLabel.font = theme.fonts.title3SB self.userIdLabel.textColor = theme.textSecondaryColor for sideMenuActionView in self.sideMenuActionViews { diff --git a/Riot/SupportingFiles/Riot-Bridging-Header.h b/Riot/SupportingFiles/Riot-Bridging-Header.h index 3292be7d4..b4d4b8e00 100644 --- a/Riot/SupportingFiles/Riot-Bridging-Header.h +++ b/Riot/SupportingFiles/Riot-Bridging-Header.h @@ -4,6 +4,7 @@ @import MatrixSDK; @import MatrixKit; +@import DTCoreText; #import "WebViewViewController.h" #import "RiotSplitViewController.h"