Merged PR 197584: SwiftLint Integration

- Adds a config file for running SwiftLint with explicitly whitelisted rules.
- Adds a run script build phase to run SwiftLint every time we build the OfficeUIFabric framework.
- Fixes warnings that were showing from implementing these linting rules.

You can find a description of all rules on the [SwiftLint github repo](https://github.com/realm/SwiftLint/blob/master/Rules.md).
This commit is contained in:
Will Richman 2018-10-31 20:23:38 +00:00
Родитель b21862b29b
Коммит 4646de3cb8
30 изменённых файлов: 292 добавлений и 80 удалений

189
.swiftlint.yml Normal file
Просмотреть файл

@ -0,0 +1,189 @@
whitelist_rules:
# Delegate protocols should be class-only so they can be weakly referenced.
- class_delegate_protocol
# Closing brace with closing parenthesis should not have any whitespaces in the middle.
- closing_brace
# Closure end should have the same indentation as the line that started it.
- closure_end_indentation
# Colons should be next to the identifier when specifying a type and next to the key in dictionary literals.
- colon
# There should be no space before and one after any comma.
- comma
# Conditional statements should always return on the next line.
- conditional_returns_on_newline
# Prefer contains over first(where:) != nil
- contains_over_first_not_nil
# if, for, guard, switch, while, and catch statements shouldn't unnecessarily wrap their conditionals or arguments in parentheses.
- control_statement
# Discouraged direct initialization of types that can be harmful (UIDevice, Bundle, etc)
- discouraged_direct_init
# Prefer () -> over Void ->.
- empty_parameters
# When using trailing closures, empty parentheses should be avoided after the method call.
- empty_parentheses_with_trailing_closure
# Properties should have a type interface
- explicit_type_interface
# Prefer to use extension access modifiers.
- extension_access_modifier
# A fatalError call should have a message.
- fatal_error_message
# Header comments should be consistent with project patterns.
- file_header
# Identifier names should only contain alphanumeric characters and start with a lowercase character or should only contain capital letters.
- identifier_name
# Computed read-only properties and subscripts should avoid using the get keyword.
- implicit_getter
# If defer is at the end of its parent scope, it will be executed right where it is anyway.
- inert_defer
# Files should not contain leading whitespace.
- leading_whitespace
# Struct-scoped constants are preferred over legacy global constants.
- legacy_constant
# Swift constructors are preferred over legacy convenience functions.
- legacy_constructor
# MARK comment should be in valid format. e.g. '// MARK: ...' or '// MARK: - ...'
- mark
# Modifier order should be consistent.
- modifier_order
# Functions and methods parameters should be either on the same line, or one per line.
- multiline_parameters
# Trailing closure syntax should not be used when passing more than one closure argument.
- multiple_closures_with_trailing_closure
# Opening braces should be preceded by a single space and on the same line as the declaration.
- opening_brace
# Operators should be surrounded by a single whitespace when they are being used.
- operator_usage_whitespace
# Some overridden methods should always call super
- overridden_super_call
# Prefer private over fileprivate declarations.
- private_over_fileprivate
# When declaring properties in protocols, the order of accessors should be get set.
- protocol_property_accessors_order
# Prefer _ = foo() over let _ = foo() when discarding a result from a function.
- redundant_discardable_let
# Initializing an optional variable with nil is redundant.
- redundant_optional_initialization
# Property setter access level shouldn't be explicit if it's the same as the variable access level.
- redundant_set_access_control
# String enum values can be omitted when they are equal to the enumcase name.
- redundant_string_enum_value
# Properties, variables, and constants should not have redundant type annotation
- redundant_type_annotation
# Returning Void in a function declaration is redundant.
- redundant_void_return
# Return arrow and return type should be separated by a single space or on a separate line.
- return_arrow_whitespace
# Prefer shorthand operators (+=, -=, *=, /=) over doing the operation and assigning.
- shorthand_operator
# Else and catch should be on the same line, one space after the previous declaration.
- statement_position
# SwiftLint 'disable' commands are superfluous when the disabled rule would not have triggered a violation in the disabled region.
- superfluous_disable_command
# Case statements should vertically align with their enclosing switch statement, or indented if configured otherwise.
- switch_case_alignment
# Cases inside a switch should always be on a newline.
- switch_case_on_newline
# Shorthand syntactic sugar should be used, i.e. [Int] instead of Array.
- syntactic_sugar
# Trailing commas in arrays and dictionaries should be avoided/enforced.
- trailing_comma
# Files should have a single trailing newline.
- trailing_newline
# Lines should not have trailing semicolons.
- trailing_semicolon
# Lines should not have trailing whitespace.
- trailing_whitespace
# Type name should only contain alphanumeric characters, start with an uppercase character, and span between 3 and 40 characters in length.
- type_name
# Avoid using unneeded break statements.
- unneeded_break_in_switch
# Unused parameter in a closure should be replaced with _.
- unused_closure_parameter
# When the index or the item is not used, .enumerated() can be removed.
- unused_enumerated
# Prefer != nil over let _ =.
- unused_optional_binding
# Function parameters should be aligned vertically if they're in multiple lines in a declaration.
- vertical_parameter_alignment
# Limit vertical whitespace to a single empty line.
- vertical_whitespace
# Prefer -> Void over -> ().
- void_return
# Delegates should be weak to avoid reference cycles.
- weak_delegate
excluded: # paths to ignore during linting. Takes precedence over `included`.
- Pods
explicit_type_interface: # requires type annotation on everything but local variables and constants
excluded:
- local
allow_redundancy: true # Ignores rule if it would result in redundancy
file_header:
required_pattern: |
\/\/
\/\/ Copyright © \d{4} Microsoft Corporation\. All rights reserved\.
\/\/
identifier_name:
min_length: 1
max_length: 60
modifier_order:
preferred_modifier_order:
- acl
- setterACL
- override
- typeMethods

Просмотреть файл

@ -16,7 +16,7 @@ class DemoController: UIViewController {
} }
let container: UIStackView = createVerticalContainer() let container: UIStackView = createVerticalContainer()
let scrollingContainer: UIScrollView = UIScrollView(frame: .zero) let scrollingContainer = UIScrollView(frame: .zero)
func createButton(title: String, action: Selector) -> MSButton { func createButton(title: String, action: Selector) -> MSButton {
let button = MSButton() let button = MSButton()

Просмотреть файл

@ -27,7 +27,7 @@ class MSDrawerDemoController: DemoController {
} else if let barButtonItem = barButtonItem { } else if let barButtonItem = barButtonItem {
controller = MSDrawerController(barButtonItem: barButtonItem, presentationOrigin: presentationOrigin, presentationDirection: presentationDirection) controller = MSDrawerController(barButtonItem: barButtonItem, presentationOrigin: presentationOrigin, presentationDirection: presentationDirection)
} else { } else {
fatalError() fatalError("Presenting a drawer requires either a sourceView or a barButtonItem")
} }
controller.preferredContentSize = CGSize(width: controller.preferredWidth, height: 200) controller.preferredContentSize = CGSize(width: controller.preferredWidth, height: 200)

Просмотреть файл

@ -58,7 +58,7 @@ class MSPersonaListViewDemoController: DemoController {
// MARK: - MSPersonaListViewDemoController: MSPersonaListViewSearchDirectoryDelegate // MARK: - MSPersonaListViewDemoController: MSPersonaListViewSearchDirectoryDelegate
extension MSPersonaListViewDemoController: MSPersonaListViewSearchDirectoryDelegate { extension MSPersonaListViewDemoController: MSPersonaListViewSearchDirectoryDelegate {
func personaListSearchDirectory(_ personaListView: MSPersonaListView, completion: @escaping ((_ success: Bool) -> ())) { func personaListSearchDirectory(_ personaListView: MSPersonaListView, completion: @escaping ((_ success: Bool) -> Void)) {
// Delay added for 2 seconds to demo activity indicator // Delay added for 2 seconds to demo activity indicator
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
let personas: [MSPersona] = [ let personas: [MSPersona] = [

Просмотреть файл

@ -403,6 +403,7 @@
A5CEC14D20D980B20016922A /* Frameworks */, A5CEC14D20D980B20016922A /* Frameworks */,
A5CEC14E20D980B20016922A /* Headers */, A5CEC14E20D980B20016922A /* Headers */,
A5CEC14F20D980B20016922A /* Resources */, A5CEC14F20D980B20016922A /* Resources */,
FD256C59218392B800EC9588 /* ShellScript */,
); );
buildRules = ( buildRules = (
); );
@ -489,6 +490,22 @@
}; };
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
FD256C59218392B800EC9588 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
A5CEC14C20D980B20016922A /* Sources */ = { A5CEC14C20D980B20016922A /* Sources */ = {
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;

Просмотреть файл

@ -133,7 +133,7 @@ class MSCalendarView: UIView {
override var accessibilityHint: String? { get { return "Accessibility.Calendar.Hint".localized } set { } } override var accessibilityHint: String? { get { return "Accessibility.Calendar.Hint".localized } set { } }
override var accessibilityTraits: UIAccessibilityTraits { get { return UIAccessibilityTraitAdjustable|super.accessibilityTraits } set { } } override var accessibilityTraits: UIAccessibilityTraits { get { return UIAccessibilityTraitAdjustable | super.accessibilityTraits } set { } }
override var accessibilityValue: String? { override var accessibilityValue: String? {
get { return accessibleViewDelegate?.accessibilityValueForAccessibleView?(self) ?? super.accessibilityValue } get { return accessibleViewDelegate?.accessibilityValueForAccessibleView?(self) ?? super.accessibilityValue }

Просмотреть файл

@ -23,12 +23,12 @@ class MSCalendarViewLayout: UICollectionViewLayout {
// Higher Z indexes appear on top // Higher Z indexes appear on top
} }
static let preferredItemHeight = Constants.itemHeight static let preferredItemHeight: CGFloat = Constants.itemHeight
weak var delegate: MSCalendarViewLayoutDelegate? weak var delegate: MSCalendarViewLayoutDelegate?
private var numberOfSections: Int = 0 private var numberOfSections: Int = 0
private var itemSize = CGSize.zero private var itemSize: CGSize = .zero
override func prepare() { override func prepare() {
super.prepare() super.prepare()

Просмотреть файл

@ -28,6 +28,8 @@ class MSCalendarViewWeekdayHeadingView: UIView {
private var firstWeekday: Int? private var firstWeekday: Int?
private let headerStyle: MSDatePickerHeaderStyle private let headerStyle: MSDatePickerHeaderStyle
// TODO: Remove this exception when SwiftLint rule false positive is fixed
// swiftlint:disable:next explicit_type_interface
private var headingLabels = [UILabel]() private var headingLabels = [UILabel]()
init(headerStyle: MSDatePickerHeaderStyle) { init(headerStyle: MSDatePickerHeaderStyle) {

Просмотреть файл

@ -70,10 +70,10 @@ open class MSActivityIndicatorView: UIView {
private struct Constants { private struct Constants {
static let rotationAnimationDuration: TimeInterval = 0.7 static let rotationAnimationDuration: TimeInterval = 0.7
static let rotationAnimationKey = "rotationAnimation" static let rotationAnimationKey: String = "rotationAnimation"
} }
open var hidesWhenStopped = true open var hidesWhenStopped: Bool = true
open var color: UIColor = MSColors.activityIndicator { open var color: UIColor = MSColors.activityIndicator {
didSet { didSet {
setupLoaderLayer() setupLoaderLayer()
@ -85,7 +85,7 @@ open class MSActivityIndicatorView: UIView {
} }
} }
// Don't modify this directly. Instead, call `startAnimating` and `stopAnimating` // Don't modify this directly. Instead, call `startAnimating` and `stopAnimating`
@objc(isAnimating) public private(set) var isAnimating = false @objc(isAnimating) public private(set) var isAnimating: Bool = false
private var loaderLayer: CAShapeLayer = { private var loaderLayer: CAShapeLayer = {
let shapeLayer = CAShapeLayer() let shapeLayer = CAShapeLayer()

Просмотреть файл

@ -35,7 +35,7 @@ open class MSBlurringView: UIView {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override open func layoutSubviews() { open override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
blurVisualEffectView.frame = bounds blurVisualEffectView.frame = bounds

Просмотреть файл

@ -9,7 +9,7 @@ import UIKit
open class MSEasyTapButton: UIButton { open class MSEasyTapButton: UIButton {
open var minTapTargetSize = CGSize(width: 44.0, height: 44.0) open var minTapTargetSize = CGSize(width: 44.0, height: 44.0)
override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool { open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
let growX = max(0, (minTapTargetSize.width - bounds.size.width) / 2) let growX = max(0, (minTapTargetSize.width - bounds.size.width) / 2)
let growY = max(0, (minTapTargetSize.height - bounds.size.height) / 2) let growY = max(0, (minTapTargetSize.height - bounds.size.height) / 2)

Просмотреть файл

@ -105,7 +105,7 @@ open class MSTwoLinesTitleView: UIView {
return titleLabel return titleLabel
}() }()
private var titleButtonImageView: UIImageView = UIImageView() private var titleButtonImageView = UIImageView()
private var titleButtonStyle: MSTwoLinesTitleViewButtonStyle? private var titleButtonStyle: MSTwoLinesTitleViewButtonStyle?
private let subtitleButton = MSEasyTapButton() private let subtitleButton = MSEasyTapButton()
@ -127,7 +127,7 @@ open class MSTwoLinesTitleView: UIView {
applyStyle(style: style) applyStyle(style: style)
} }
override public init(frame: CGRect) { public override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
applyStyle(style: .dark) applyStyle(style: .dark)
@ -220,7 +220,7 @@ open class MSTwoLinesTitleView: UIView {
// MARK: Layout // MARK: Layout
override open func sizeThatFits(_ size: CGSize) -> CGSize { open override func sizeThatFits(_ size: CGSize) -> CGSize {
var titleSize = titleButtonLabel.sizeThatFits(size) var titleSize = titleButtonLabel.sizeThatFits(size)
if let titleButtonStyle = titleButtonStyle { if let titleButtonStyle = titleButtonStyle {
titleSize.width += 2 * (titleButtonStyle.width + titleButtonStyle.horizontalPadding) titleSize.width += 2 * (titleButtonStyle.width + titleButtonStyle.horizontalPadding)
@ -234,7 +234,7 @@ open class MSTwoLinesTitleView: UIView {
return CGSize(width: max(titleSize.width, subtitleSize.width), height: titleSize.height + subtitleSize.height) return CGSize(width: max(titleSize.width, subtitleSize.width), height: titleSize.height + subtitleSize.height)
} }
override open func layoutSubviews() { open override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
let isCompact = traitCollection.verticalSizeClass == .compact let isCompact = traitCollection.verticalSizeClass == .compact
@ -324,13 +324,13 @@ open class MSTwoLinesTitleView: UIView {
// MARK: Accessibility // MARK: Accessibility
override open var isAccessibilityElement: Bool { get { return false } set { } } open override var isAccessibilityElement: Bool { get { return false } set { } }
override open func accessibilityElementCount() -> Int { open override func accessibilityElementCount() -> Int {
return 2 return 2
} }
override open func accessibilityElement(at index: Int) -> Any? { open override func accessibilityElement(at index: Int) -> Any? {
if index == 0 { if index == 0 {
return titleButton return titleButton
} else if index == 1 { } else if index == 1 {
@ -339,7 +339,7 @@ open class MSTwoLinesTitleView: UIView {
return nil return nil
} }
override open func index(ofAccessibilityElement element: Any) -> Int { open override func index(ofAccessibilityElement element: Any) -> Int {
if let view = element as? UIView { if let view = element as? UIView {
return view == titleButton ? 0 : 1 return view == titleButton ? 0 : 1
} }

Просмотреть файл

@ -41,7 +41,7 @@ public struct MSColors {
// MARK: Avatar background colors // MARK: Avatar background colors
public static let avatarBackgroundColors = [ public static let avatarBackgroundColors: [UIColor] = [
#colorLiteral(red: 0, green: 0.4705882353, blue: 0.831372549, alpha: 1), // #0078D4 #colorLiteral(red: 0, green: 0.4705882353, blue: 0.831372549, alpha: 1), // #0078D4
#colorLiteral(red: 0.8196078431, green: 0.2039215686, blue: 0.2196078431, alpha: 1), // #D13438 #colorLiteral(red: 0.8196078431, green: 0.2039215686, blue: 0.2196078431, alpha: 1), // #D13438
#colorLiteral(red: 0.5333333333, green: 0.09019607843, blue: 0.5960784314, alpha: 1), // #881798 #colorLiteral(red: 0.5333333333, green: 0.09019607843, blue: 0.5960784314, alpha: 1), // #881798
@ -62,7 +62,7 @@ public struct MSColors {
#colorLiteral(red: 0.3607843137, green: 0.1803921569, blue: 0.568627451, alpha: 1), // #5C2E91 #colorLiteral(red: 0.3607843137, green: 0.1803921569, blue: 0.568627451, alpha: 1), // #5C2E91
#colorLiteral(red: 0.4117647059, green: 0.4745098039, blue: 0.4941176471, alpha: 1), // #69797E #colorLiteral(red: 0.4117647059, green: 0.4745098039, blue: 0.4941176471, alpha: 1), // #69797E
#colorLiteral(red: 0, green: 0.3568627451, blue: 0.4392156863, alpha: 1), // #005B70 #colorLiteral(red: 0, green: 0.3568627451, blue: 0.4392156863, alpha: 1), // #005B70
#colorLiteral(red: 0.5568627451, green: 0.337254902, blue: 0.1803921569, alpha: 1), // #8E562E #colorLiteral(red: 0.5568627451, green: 0.337254902, blue: 0.1803921569, alpha: 1) // #8E562E
] ]
// MARK: Semantic // MARK: Semantic

Просмотреть файл

@ -4,9 +4,9 @@
public struct MSFonts { public struct MSFonts {
/// Semibold 28pt /// Semibold 28pt
public static let title1: UIFont = UIFont.preferredFont(forTextStyle: .title1).withWeight(.semibold) public static let title1 = UIFont.preferredFont(forTextStyle: .title1).withWeight(.semibold)
/// Semibold 22pt /// Semibold 22pt
public static let title2: UIFont = UIFont.preferredFont(forTextStyle: .title2).withWeight(.semibold) public static let title2 = UIFont.preferredFont(forTextStyle: .title2).withWeight(.semibold)
/// Semibold 17pt /// Semibold 17pt
public static let headline: UIFont = .preferredFont(forTextStyle: .headline) public static let headline: UIFont = .preferredFont(forTextStyle: .headline)
/// Regular 17pt /// Regular 17pt

Просмотреть файл

@ -25,7 +25,7 @@ open class MSDatePicker: UIViewController {
private struct Constants { private struct Constants {
// TODO: Make title button width dynamic // TODO: Make title button width dynamic
static let titleButtonWidth: CGFloat = 160 static let titleButtonWidth: CGFloat = 160
static let preloadAvailabilityDaysOffset = 30 static let preloadAvailabilityDaysOffset: Int = 30
} }
/// The currently selected whole date. Automatically changes to start of day when set. /// The currently selected whole date. Automatically changes to start of day when set.
@ -63,7 +63,7 @@ open class MSDatePicker: UIViewController {
initTitleView() initTitleView()
} }
required public init?(coder aDecoder: NSCoder) { public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
@ -81,14 +81,14 @@ open class MSDatePicker: UIViewController {
presentingViewController.present(pageCardPresenterVC, animated: true) presentingViewController.present(pageCardPresenterVC, animated: true)
} }
override open func viewDidLoad() { open override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
addChildController(contentController) addChildController(contentController)
initNavigationBar() initNavigationBar()
} }
override open func viewDidLayoutSubviews() { open override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews() super.viewDidLayoutSubviews()
updateTitleFrame() updateTitleFrame()
@ -96,7 +96,7 @@ open class MSDatePicker: UIViewController {
contentController.view.frame = view.bounds contentController.view.frame = view.bounds
} }
override open func viewWillAppear(_ animated: Bool) { open override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
// Hide default bottom border of navigation bar // Hide default bottom border of navigation bar

Просмотреть файл

@ -58,7 +58,7 @@ class MSDatePickerController: UIViewController {
) )
} }
required public init?(coder aDecoder: NSCoder) { public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
@ -79,7 +79,7 @@ class MSDatePickerController: UIViewController {
} }
} }
override public func viewDidLoad() { public override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
calendarView.weekdayHeadingView.setup(horizontalSizeClass: traitCollection.horizontalSizeClass, firstWeekday: firstWeekday) calendarView.weekdayHeadingView.setup(horizontalSizeClass: traitCollection.horizontalSizeClass, firstWeekday: firstWeekday)
@ -101,13 +101,13 @@ class MSDatePickerController: UIViewController {
view.addSubview(calendarView) view.addSubview(calendarView)
} }
override public func viewWillAppear(_ animated: Bool) { public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
scrollToStartDate(animated: false) scrollToStartDate(animated: false)
} }
override public func viewWillLayoutSubviews() { public override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews() super.viewWillLayoutSubviews()
calendarView.frame = view.bounds calendarView.frame = view.bounds

Просмотреть файл

@ -55,8 +55,10 @@ class MSDatePickerSelectionManager {
private var selectedIndexPaths: (startIndexPath: IndexPath, endIndexPath: IndexPath) { private var selectedIndexPaths: (startIndexPath: IndexPath, endIndexPath: IndexPath) {
switch selectionState { switch selectionState {
case let .single(selectedIndexPath): return (selectedIndexPath, selectedIndexPath) case let .single(selectedIndexPath):
case let .range(startIndexPath, endIndexPath): return (startIndexPath, endIndexPath) return (selectedIndexPath, selectedIndexPath)
case let .range(startIndexPath, endIndexPath):
return (startIndexPath, endIndexPath)
} }
} }

Просмотреть файл

@ -5,7 +5,9 @@
import Foundation import Foundation
public extension Calendar { public extension Calendar {
private static let sharedAutoUpdatingCalendar = Calendar.autoupdatingCurrent private static let sharedAutoUpdatingCalendar: Calendar = .autoupdatingCurrent
// TODO: Remove this exception when SwiftLint rule false positive is fixed
// swiftlint:disable:next explicit_type_interface
private static var sharedTimeZoneCalendars = [Calendar]() private static var sharedTimeZoneCalendars = [Calendar]()
static func sharedCalendarWithTimeZone(_ timeZone: TimeZone?) -> Calendar { static func sharedCalendarWithTimeZone(_ timeZone: TimeZone?) -> Calendar {

Просмотреть файл

@ -20,7 +20,7 @@ public extension String {
// Discard name if first char is not a letter // Discard name if first char is not a letter
let isInitialLetter: Bool = initialLetter.count > 0 && CharacterSet.letters.contains(initialUnicodeScalar) let isInitialLetter: Bool = initialLetter.count > 0 && CharacterSet.letters.contains(initialUnicodeScalar)
if isInitialLetter && initials.count < 2 { if isInitialLetter && initials.count < 2 {
initials = initials + initialLetter initials += initialLetter
} }
} }
@ -239,5 +239,3 @@ public extension String {
return dateFormatter.string(from: date) return dateFormatter.string(from: date)
} }
} }

Просмотреть файл

@ -3,8 +3,8 @@
// //
public extension UIFontDescriptor { public extension UIFontDescriptor {
var traits: [UIFontDescriptor.TraitKey : Any]? { var traits: [UIFontDescriptor.TraitKey: Any]? {
return object(forKey: .traits) as? [UIFontDescriptor.TraitKey : Any] return object(forKey: .traits) as? [UIFontDescriptor.TraitKey: Any]
} }
var weight: UIFont.Weight { var weight: UIFont.Weight {
if let weight = traits?[.weight] as? NSNumber { if let weight = traits?[.weight] as? NSNumber {

Просмотреть файл

@ -123,17 +123,19 @@ open class MSAvatarView: UIView {
addSubview(imageView) addSubview(imageView)
} }
@objc public required init(coder aDecoder: NSCoder) { fatalError() } @objc public required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override open var intrinsicContentSize: CGSize { open override var intrinsicContentSize: CGSize {
return avatarSize.size return avatarSize.size
} }
override open func sizeThatFits(_ size: CGSize) -> CGSize { open override func sizeThatFits(_ size: CGSize) -> CGSize {
return avatarSize.size return avatarSize.size
} }
override open func layoutSubviews() { open override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
imageView.frame = bounds imageView.frame = bounds
@ -221,6 +223,6 @@ open class MSAvatarView: UIView {
// MARK: Accessibility // MARK: Accessibility
override open var accessibilityLabel: String? { get { return name ?? email } set {} } open override var accessibilityLabel: String? { get { return name ?? email } set {} }
override open var accessibilityTraits: UIAccessibilityTraits { get { return UIAccessibilityTraitImage } set {} } open override var accessibilityTraits: UIAccessibilityTraits { get { return UIAccessibilityTraitImage } set {} }
} }

Просмотреть файл

@ -16,7 +16,7 @@ open class MSPersonaCell: UITableViewCell {
} }
public static let defaultHeight: CGFloat = 60 public static let defaultHeight: CGFloat = 60
public static let identifier = "MSPersonaCell" public static let identifier: String = "MSPersonaCell"
public static var separatorLeftInset: CGFloat { public static var separatorLeftInset: CGFloat {
return Constants.avatarMarginLeft + Constants.avatarSize.size.width + Constants.avatarMarginRight return Constants.avatarMarginLeft + Constants.avatarSize.size.width + Constants.avatarMarginRight
} }
@ -36,7 +36,7 @@ open class MSPersonaCell: UITableViewCell {
return label return label
}() }()
@objc override public init(style: UITableViewCellStyle, reuseIdentifier: String?) { @objc public override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: .default, reuseIdentifier: reuseIdentifier) super.init(style: .default, reuseIdentifier: reuseIdentifier)
contentView.addSubview(avatarView) contentView.addSubview(avatarView)
@ -65,14 +65,14 @@ open class MSPersonaCell: UITableViewCell {
setNeedsLayout() setNeedsLayout()
} }
override open func prepareForReuse() { open override func prepareForReuse() {
super.prepareForReuse() super.prepareForReuse()
nameLabel.text = nil nameLabel.text = nil
subtitleLabel.text = nil subtitleLabel.text = nil
subtitleLabel.isHidden = true subtitleLabel.isHidden = true
} }
override open func layoutSubviews() { open override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
avatarView.left = Constants.avatarMarginLeft avatarView.left = Constants.avatarMarginLeft
@ -106,13 +106,13 @@ open class MSPersonaCell: UITableViewCell {
// setHighlighted and setSelected maintain the correct background color of avatar when the cell is highlighted or selected. // setHighlighted and setSelected maintain the correct background color of avatar when the cell is highlighted or selected.
// Without this avatar's background color will change to the cell's background color. // Without this avatar's background color will change to the cell's background color.
override open func setHighlighted(_ highlighted: Bool, animated: Bool) { open override func setHighlighted(_ highlighted: Bool, animated: Bool) {
let avatarBackgroundColor = avatarView.avatarBackgroundColor let avatarBackgroundColor = avatarView.avatarBackgroundColor
super.setHighlighted(highlighted, animated: animated) super.setHighlighted(highlighted, animated: animated)
avatarView.avatarBackgroundColor = avatarBackgroundColor avatarView.avatarBackgroundColor = avatarBackgroundColor
} }
override open func setSelected(_ selected: Bool, animated: Bool) { open override func setSelected(_ selected: Bool, animated: Bool) {
let avatarBackgroundColor = avatarView.avatarBackgroundColor let avatarBackgroundColor = avatarView.avatarBackgroundColor
super.setSelected(selected, animated: animated) super.setSelected(selected, animated: animated)
avatarView.avatarBackgroundColor = avatarBackgroundColor avatarView.avatarBackgroundColor = avatarBackgroundColor

Просмотреть файл

@ -14,7 +14,7 @@ import UIKit
// MARK: - MSPersonaListViewSearchDirectoryDelegate // MARK: - MSPersonaListViewSearchDirectoryDelegate
@objc public protocol MSPersonaListViewSearchDirectoryDelegate { @objc public protocol MSPersonaListViewSearchDirectoryDelegate {
func personaListSearchDirectory(_ personaListView: MSPersonaListView, completion: @escaping ((_ success: Bool) -> ())) func personaListSearchDirectory(_ personaListView: MSPersonaListView, completion: @escaping ((_ success: Bool) -> Void))
} }
// MARK: - MSPersonaListView // MARK: - MSPersonaListView

Просмотреть файл

@ -21,8 +21,8 @@ open class MSPageCardPresenterController: UIViewController {
static let pageControlVerticalMarginCompact: CGFloat = 5 static let pageControlVerticalMarginCompact: CGFloat = 5
} }
override open var modalPresentationStyle: UIModalPresentationStyle { get { return .custom } set { } } open override var modalPresentationStyle: UIModalPresentationStyle { get { return .custom } set { } }
override open var transitioningDelegate: UIViewControllerTransitioningDelegate? { get { return self } set { } } open override var transitioningDelegate: UIViewControllerTransitioningDelegate? { get { return self } set { } }
var onDismiss: (() -> Void)? var onDismiss: (() -> Void)?
var onSwitchToNewViewController: ((UIViewController, Int) -> Void)? var onSwitchToNewViewController: ((UIViewController, Int) -> Void)?
@ -65,11 +65,11 @@ open class MSPageCardPresenterController: UIViewController {
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
} }
required public init?(coder aDecoder: NSCoder) { public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override open func viewDidLoad() { open override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
scrollView.delegate = self scrollView.delegate = self
@ -96,7 +96,7 @@ open class MSPageCardPresenterController: UIViewController {
updateViewAccessibilityElements() updateViewAccessibilityElements()
} }
override open func viewWillAppear(_ animated: Bool) { open override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
if startingIndex > 0 { if startingIndex > 0 {
@ -105,7 +105,7 @@ open class MSPageCardPresenterController: UIViewController {
} }
} }
override open func viewWillLayoutSubviews() { open override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews() super.viewWillLayoutSubviews()
let positionRatio = scrollView.contentOffset.x / max(1, scrollView.contentSize.width) let positionRatio = scrollView.contentOffset.x / max(1, scrollView.contentSize.width)

Просмотреть файл

@ -13,7 +13,7 @@ import UIKit
*/ */
open class MSActionsCell: UITableViewCell { open class MSActionsCell: UITableViewCell {
public static let defaultHeight: CGFloat = 45 public static let defaultHeight: CGFloat = 45
public static let identifier = "MSActionsCell" public static let identifier: String = "MSActionsCell"
private struct Constants { private struct Constants {
static let actionTitleFont: UIFont = MSFonts.body static let actionTitleFont: UIFont = MSFonts.body
@ -62,7 +62,7 @@ open class MSActionsCell: UITableViewCell {
separator.isHidden = !hasAction separator.isHidden = !hasAction
} }
override open func layoutSubviews() { open override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
let actionCount: CGFloat = action2Button.isHidden ? 1 : 2 let actionCount: CGFloat = action2Button.isHidden ? 1 : 2
@ -78,15 +78,15 @@ open class MSActionsCell: UITableViewCell {
} }
} }
override open func prepareForReuse() { open override func prepareForReuse() {
super.prepareForReuse() super.prepareForReuse()
action1Button.removeTarget(nil, action: nil, for: .allEvents) action1Button.removeTarget(nil, action: nil, for: .allEvents)
action2Button.removeTarget(nil, action: nil, for: .allEvents) action2Button.removeTarget(nil, action: nil, for: .allEvents)
} }
override open func setHighlighted(_ highlighted: Bool, animated: Bool) { } open override func setHighlighted(_ highlighted: Bool, animated: Bool) { }
override open func setSelected(_ selected: Bool, animated: Bool) { } open override func setSelected(_ selected: Bool, animated: Bool) { }
private func actionTitleColor(isDestructive: Bool, isHighlighted: Bool) -> UIColor { private func actionTitleColor(isDestructive: Bool, isHighlighted: Bool) -> UIColor {
if isDestructive { if isDestructive {

Просмотреть файл

@ -7,7 +7,7 @@ import UIKit
// MARK: MSActivityIndicatorCell // MARK: MSActivityIndicatorCell
open class MSActivityIndicatorCell: UITableViewCell { open class MSActivityIndicatorCell: UITableViewCell {
public static let identifier = "MSActivityIndicatorCell" public static let identifier: String = "MSActivityIndicatorCell"
public static let defaultHeight: CGFloat = 45 public static let defaultHeight: CGFloat = 45
private let activityIndicatorView: MSActivityIndicatorView = { private let activityIndicatorView: MSActivityIndicatorView = {

Просмотреть файл

@ -7,11 +7,11 @@ import UIKit
// MARK: MSCenteredLabelCell // MARK: MSCenteredLabelCell
open class MSCenteredLabelCell: UITableViewCell { open class MSCenteredLabelCell: UITableViewCell {
public static let identifier = "MSCenteredLabelCell" public static let identifier: String = "MSCenteredLabelCell"
public static let defaultHeight: CGFloat = 45 public static let defaultHeight: CGFloat = 45
private struct Constants { private struct Constants {
static let labelFont = MSFonts.body static let labelFont: UIFont = MSFonts.body
static let paddingVerticalSmall: CGFloat = 5 static let paddingVerticalSmall: CGFloat = 5
} }
@ -24,7 +24,7 @@ open class MSCenteredLabelCell: UITableViewCell {
return label return label
}() }()
override public init(style: UITableViewCellStyle, reuseIdentifier: String?) { public override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier) super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(label) contentView.addSubview(label)
} }
@ -41,14 +41,14 @@ open class MSCenteredLabelCell: UITableViewCell {
setNeedsLayout() setNeedsLayout()
} }
override open func layoutSubviews() { open override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
let labelFittingSize = label.sizeThatFits(CGSize(width: contentView.width - layoutMargins.left - layoutMargins.right, height: CGFloat.greatestFiniteMagnitude)) let labelFittingSize = label.sizeThatFits(CGSize(width: contentView.width - layoutMargins.left - layoutMargins.right, height: CGFloat.greatestFiniteMagnitude))
label.frame.size = labelFittingSize label.frame.size = labelFittingSize
label.centerInSuperview() label.centerInSuperview()
} }
override open func setHighlighted(_ highlighted: Bool, animated: Bool) { } open override func setHighlighted(_ highlighted: Bool, animated: Bool) { }
override open func setSelected(_ selected: Bool, animated: Bool) { } open override func setSelected(_ selected: Bool, animated: Bool) { }
} }