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:
Родитель
b21862b29b
Коммит
4646de3cb8
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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) { }
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче