Merged PR 210708: MSDateTimePicker Presentation API with DateTime support
Introduces a new `MSDateTimePicker` class to manage and handle presenting multiple Date or Time related pickers and coordinating between them. Includes a refactor of `MSDatePicker` into `MSDatePickerController`, leaving one Controller class for each type of picker. Also includes some miscellaneous SwiftLint update fixes. ![Screen Shot 2018-12-07 at 4.27.44 PM.png](https://onedrive.visualstudio.com/4dcbf0bc-c3cd-49c8-a7c3-ec1924691d9b/_apis/git/repositories/93ac71ee-b53a-4fc6-a8c4-d46a80d4ca39/pullRequests/210708/attachments/Screen%20Shot%202018-12-07%20at%204.27.44%20PM.png) ![Screen Shot 2018-12-07 at 4.27.48 PM.png](https://onedrive.visualstudio.com/4dcbf0bc-c3cd-49c8-a7c3-ec1924691d9b/_apis/git/repositories/93ac71ee-b53a-4fc6-a8c4-d46a80d4ca39/pullRequests/210708/attachments/Screen%20Shot%202018-12-07%20at%204.27.48%20PM.png) Related work items: #665501
This commit is contained in:
Родитель
522ae9c053
Коммит
198f12b1cb
|
@ -50,9 +50,6 @@ whitelist_rules:
|
|||
# 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
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import UIKit
|
|||
let demos: [(title: String, controllerClass: UIViewController.Type)] = [
|
||||
("MSAvatarView", MSAvatarViewDemoController.self),
|
||||
("MSBadgeView", MSBadgeViewDemoController.self),
|
||||
("MSDatePicker", MSDatePickerDemoController.self),
|
||||
("MSDateTimePicker", MSDateTimePickerDemoController.self),
|
||||
("MSDrawerController", MSDrawerDemoController.self),
|
||||
("MSLabel", MSLabelDemoController.self),
|
||||
("MSPersonaListView", MSPersonaListViewDemoController.self),
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
//
|
||||
// Copyright © 2018 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
|
||||
import OfficeUIFabric
|
||||
import UIKit
|
||||
|
||||
class MSDatePickerDemoController: DemoController {
|
||||
private var dateLabel: MSLabel?
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
dateLabel = MSLabel(style: .headline, colorStyle: .primary)
|
||||
dateLabel?.text = "No date selected"
|
||||
container.addArrangedSubview(dateLabel!)
|
||||
container.addArrangedSubview(createButton(title: "Show date picker", action: #selector(presentDatePicker)))
|
||||
}
|
||||
|
||||
@objc func presentDatePicker() {
|
||||
let datePicker = MSDatePicker(initialDate: Date())
|
||||
datePicker.delegate = self
|
||||
datePicker.present(from: self)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MSDatePickerDemoController: MSDatePickerDelegate
|
||||
|
||||
extension MSDatePickerDemoController: MSDatePickerDelegate {
|
||||
func datePicker(_ datePicker: MSDatePicker, didPickDate date: Date) {
|
||||
dateLabel?.text = String.dateString(from: date, compactness: .longDaynameDayMonthYear)
|
||||
dismiss(animated: true)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Copyright © 2018 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
|
||||
import OfficeUIFabric
|
||||
import UIKit
|
||||
|
||||
class MSDateTimePickerDemoController: DemoController {
|
||||
private let dateLabel = MSLabel(style: .headline, colorStyle: .primary)
|
||||
private let dateTimePicker = MSDateTimePicker()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
dateTimePicker.delegate = self
|
||||
dateLabel.text = "No date selected"
|
||||
container.addArrangedSubview(dateLabel)
|
||||
container.addArrangedSubview(createButton(title: "Show date picker", action: #selector(presentDatePicker)))
|
||||
container.addArrangedSubview(createButton(title: "Show date time picker", action: #selector(presentDateTimePicker)))
|
||||
}
|
||||
|
||||
@objc func presentDatePicker() {
|
||||
dateTimePicker.present(from: self, with: .date)
|
||||
}
|
||||
|
||||
@objc func presentDateTimePicker() {
|
||||
dateTimePicker.present(from: self, with: .dateTime)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MSDateTimePickerDemoController: MSDatePickerDelegate
|
||||
|
||||
extension MSDateTimePickerDemoController: MSDateTimePickerDelegate {
|
||||
func dateTimePicker(_ dateTimePicker: MSDateTimePicker, didPickDate date: Date) {
|
||||
var compactness = MSDateStringCompactness.longDaynameDayMonthYear
|
||||
if dateTimePicker.mode == .dateTime {
|
||||
compactness = .longDaynameDayMonthHoursColumnsMinutes
|
||||
}
|
||||
dateLabel.text = String.dateString(from: date, compactness: compactness)
|
||||
dateTimePicker.dismiss()
|
||||
}
|
||||
}
|
|
@ -55,13 +55,12 @@
|
|||
FD256C5B2183B90B00EC9588 /* MSDatePickerSelectionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD256C5A2183B90B00EC9588 /* MSDatePickerSelectionManager.swift */; };
|
||||
FD36F1A9216C0A6900CECBC6 /* MSCardPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDA1AF9221487225001AE720 /* MSCardPresentationController.swift */; };
|
||||
FD4F2A1B2148937100C437D6 /* MSPageCardPresenterController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD4F2A1A2148937100C437D6 /* MSPageCardPresenterController.swift */; };
|
||||
FD4F2A1E214ADBCF00C437D6 /* MSDatePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD4F2A1D214ADBCF00C437D6 /* MSDatePicker.swift */; };
|
||||
FD4F2A20214AE20400C437D6 /* MSDatePickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD4F2A1F214AE20400C437D6 /* MSDatePickerController.swift */; };
|
||||
FD56FD92219123FE0023C7EA /* MSDateTimePickerViewComponentTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9758082191118E00B67319 /* MSDateTimePickerViewComponentTableView.swift */; };
|
||||
FD56FD94219128BF0023C7EA /* MSDateTimePickerViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9758072191118E00B67319 /* MSDateTimePickerViewDataSource.swift */; };
|
||||
FD56FD95219131430023C7EA /* MSDateTimePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9758062191118D00B67319 /* MSDateTimePickerView.swift */; };
|
||||
FD56FD962192754B0023C7EA /* MSDateTimePickerViewComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9758092191118E00B67319 /* MSDateTimePickerViewComponent.swift */; };
|
||||
FD56FD9A2194E50D0023C7EA /* MSDateTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5ADBF32190CDC80005A9AF /* MSDateTimePicker.swift */; };
|
||||
FD56FD9A2194E50D0023C7EA /* MSDateTimePickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5ADBF32190CDC80005A9AF /* MSDateTimePickerController.swift */; };
|
||||
FD599D0221348439008845EE /* MSCalendarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD599D0121348439008845EE /* MSCalendarView.swift */; };
|
||||
FD599D062134A682008845EE /* AccessibleViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD599D052134A682008845EE /* AccessibleViewDelegate.swift */; };
|
||||
FD599D082134AB0E008845EE /* MSCalendarViewWeekdayHeadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD599D072134AB0E008845EE /* MSCalendarViewWeekdayHeadingView.swift */; };
|
||||
|
@ -77,6 +76,7 @@
|
|||
FD777529219E3F6C00033D58 /* MSDayOfMonth.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD777528219E3F6C00033D58 /* MSDayOfMonth.swift */; };
|
||||
FD77752B219E455A00033D58 /* MSAccessibilityContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD77752A219E455A00033D58 /* MSAccessibilityContainerView.swift */; };
|
||||
FD77752D219E62E100033D58 /* MSDateTimePickerViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD77752C219E62E100033D58 /* MSDateTimePickerViewLayout.swift */; };
|
||||
FD77753021A490BA00033D58 /* MSDateTimePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD77752F21A490BA00033D58 /* MSDateTimePicker.swift */; };
|
||||
FD97580F2191118E00B67319 /* MSDateTimePickerViewComponentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD97580A2191118E00B67319 /* MSDateTimePickerViewComponentCell.swift */; };
|
||||
FD9A5C872179464F00D224D9 /* DateComponents+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9A5C862179464F00D224D9 /* DateComponents+Extensions.swift */; };
|
||||
FDA1AF8C21484625001AE720 /* MSBlurringView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDA1AF8B21484625001AE720 /* MSBlurringView.swift */; };
|
||||
|
@ -152,14 +152,13 @@
|
|||
FD0D29D52151A3D700E8655E /* MSCardPresenterNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSCardPresenterNavigationController.swift; sourceTree = "<group>"; };
|
||||
FD256C5A2183B90B00EC9588 /* MSDatePickerSelectionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSDatePickerSelectionManager.swift; sourceTree = "<group>"; };
|
||||
FD4F2A1A2148937100C437D6 /* MSPageCardPresenterController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSPageCardPresenterController.swift; sourceTree = "<group>"; };
|
||||
FD4F2A1D214ADBCF00C437D6 /* MSDatePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSDatePicker.swift; sourceTree = "<group>"; };
|
||||
FD4F2A1F214AE20400C437D6 /* MSDatePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSDatePickerController.swift; sourceTree = "<group>"; };
|
||||
FD599D0121348439008845EE /* MSCalendarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSCalendarView.swift; sourceTree = "<group>"; };
|
||||
FD599D052134A682008845EE /* AccessibleViewDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccessibleViewDelegate.swift; sourceTree = "<group>"; };
|
||||
FD599D072134AB0E008845EE /* MSCalendarViewWeekdayHeadingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSCalendarViewWeekdayHeadingView.swift; sourceTree = "<group>"; };
|
||||
FD599D092134AB15008845EE /* MSCalendarViewLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSCalendarViewLayout.swift; sourceTree = "<group>"; };
|
||||
FD599D0B2134AB1E008845EE /* MSCalendarViewDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSCalendarViewDataSource.swift; sourceTree = "<group>"; };
|
||||
FD5ADBF32190CDC80005A9AF /* MSDateTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSDateTimePicker.swift; sourceTree = "<group>"; };
|
||||
FD5ADBF32190CDC80005A9AF /* MSDateTimePickerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSDateTimePickerController.swift; sourceTree = "<group>"; };
|
||||
FD5BBE3A214B2F44008964B4 /* Date+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extensions.swift"; sourceTree = "<group>"; };
|
||||
FD5BBE3E214C68F8008964B4 /* UINavigationBar+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationBar+Extensions.swift"; sourceTree = "<group>"; };
|
||||
FD5BBE40214C6AF3008964B4 /* MSTwoLinesTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSTwoLinesTitleView.swift; sourceTree = "<group>"; };
|
||||
|
@ -169,6 +168,7 @@
|
|||
FD777528219E3F6C00033D58 /* MSDayOfMonth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSDayOfMonth.swift; sourceTree = "<group>"; };
|
||||
FD77752A219E455A00033D58 /* MSAccessibilityContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSAccessibilityContainerView.swift; sourceTree = "<group>"; };
|
||||
FD77752C219E62E100033D58 /* MSDateTimePickerViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSDateTimePickerViewLayout.swift; sourceTree = "<group>"; };
|
||||
FD77752F21A490BA00033D58 /* MSDateTimePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSDateTimePicker.swift; sourceTree = "<group>"; };
|
||||
FD9758062191118D00B67319 /* MSDateTimePickerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSDateTimePickerView.swift; sourceTree = "<group>"; };
|
||||
FD9758072191118E00B67319 /* MSDateTimePickerViewDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSDateTimePickerViewDataSource.swift; sourceTree = "<group>"; };
|
||||
FD9758082191118E00B67319 /* MSDateTimePickerViewComponentTableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSDateTimePickerViewComponentTableView.swift; sourceTree = "<group>"; };
|
||||
|
@ -399,7 +399,6 @@
|
|||
FD4F2A1C214ADBBF00C437D6 /* Date Picker */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FD4F2A1D214ADBCF00C437D6 /* MSDatePicker.swift */,
|
||||
FD4F2A1F214AE20400C437D6 /* MSDatePickerController.swift */,
|
||||
FD256C5A2183B90B00EC9588 /* MSDatePickerSelectionManager.swift */,
|
||||
);
|
||||
|
@ -411,6 +410,7 @@
|
|||
children = (
|
||||
FD4F2A1C214ADBBF00C437D6 /* Date Picker */,
|
||||
FD5C8C2A2190C3470063562C /* Date Time Picker */,
|
||||
FD77752F21A490BA00033D58 /* MSDateTimePicker.swift */,
|
||||
);
|
||||
path = "Date Time Pickers";
|
||||
sourceTree = "<group>";
|
||||
|
@ -418,7 +418,7 @@
|
|||
FD5C8C2A2190C3470063562C /* Date Time Picker */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FD5ADBF32190CDC80005A9AF /* MSDateTimePicker.swift */,
|
||||
FD5ADBF32190CDC80005A9AF /* MSDateTimePickerController.swift */,
|
||||
FD97580521910FE800B67319 /* Views */,
|
||||
);
|
||||
path = "Date Time Picker";
|
||||
|
@ -640,7 +640,6 @@
|
|||
A5B87B04211E22B70038C37C /* MSDimmingView.swift in Sources */,
|
||||
A5961F9F218A256B00E2A506 /* MSPopupMenuItem.swift in Sources */,
|
||||
B4E782C321793AB200A7DFCE /* MSActivityIndicatorCell.swift in Sources */,
|
||||
FD4F2A1E214ADBCF00C437D6 /* MSDatePicker.swift in Sources */,
|
||||
FD599D0A2134AB15008845EE /* MSCalendarViewLayout.swift in Sources */,
|
||||
FDD454EE21405B390006E84E /* MSDotView.swift in Sources */,
|
||||
FD256C5B2183B90B00EC9588 /* MSDatePickerSelectionManager.swift in Sources */,
|
||||
|
@ -657,10 +656,11 @@
|
|||
FD5BBE43214C73CE008964B4 /* MSEasyTapButton.swift in Sources */,
|
||||
FD77752B219E455A00033D58 /* MSAccessibilityContainerView.swift in Sources */,
|
||||
FDF41ED92141A02200EC527C /* MSCalendarConfiguration.swift in Sources */,
|
||||
FD77753021A490BA00033D58 /* MSDateTimePicker.swift in Sources */,
|
||||
FD7254E92147059D002F4069 /* Calendar+Extensions.swift in Sources */,
|
||||
A559BB7E212B6D100055E107 /* String+Extension.swift in Sources */,
|
||||
A5961FA5218A260500E2A506 /* MSPopupMenuSectionHeaderView.swift in Sources */,
|
||||
FD56FD9A2194E50D0023C7EA /* MSDateTimePicker.swift in Sources */,
|
||||
FD56FD9A2194E50D0023C7EA /* MSDateTimePickerController.swift in Sources */,
|
||||
B46D3F9D215985AC0029772C /* MSPersonaListView.swift in Sources */,
|
||||
A5DCA76421224026005F4CB7 /* MSSeparator.swift in Sources */,
|
||||
FD599D062134A682008845EE /* AccessibleViewDelegate.swift in Sources */,
|
||||
|
|
|
@ -28,8 +28,6 @@ class MSCalendarViewWeekdayHeadingView: UIView {
|
|||
private var firstWeekday: Int?
|
||||
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]()
|
||||
|
||||
init(headerStyle: MSDatePickerHeaderStyle) {
|
||||
|
|
|
@ -1,203 +0,0 @@
|
|||
//
|
||||
// Copyright © 2018 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: MSDatePickerHeaderStyle
|
||||
|
||||
@objc public enum MSDatePickerHeaderStyle: Int {
|
||||
case light
|
||||
case dark
|
||||
}
|
||||
|
||||
// MARK: - MSDatePickerDelegate
|
||||
|
||||
/// Allows a class to be notified when a user confirms their selected date
|
||||
public protocol MSDatePickerDelegate: class {
|
||||
func datePicker(_ datePicker: MSDatePicker, didPickDate date: Date)
|
||||
}
|
||||
|
||||
// MARK: - MSDatePicker
|
||||
|
||||
/// A view controller that can present itself modally to display a calendar used for picking a date, with a navigation bar with title.
|
||||
open class MSDatePicker: UIViewController {
|
||||
private struct Constants {
|
||||
// TODO: Make title button width dynamic
|
||||
static let titleButtonWidth: CGFloat = 160
|
||||
static let preloadAvailabilityDaysOffset: Int = 30
|
||||
}
|
||||
|
||||
/// The currently selected whole date. Automatically changes to start of day when set.
|
||||
open var date: Date {
|
||||
get {
|
||||
return contentController.startDate
|
||||
}
|
||||
set {
|
||||
let startDate = newValue.startOfDay
|
||||
contentController.setup(startDate: startDate, endDate: startDate.adding(hours: 23, minutes: 59))
|
||||
updateNavigationBar()
|
||||
}
|
||||
}
|
||||
|
||||
public weak var delegate: MSDatePickerDelegate?
|
||||
|
||||
private var titleView: MSTwoLinesTitleView!
|
||||
private let subtitle: String?
|
||||
private var contentController: MSDatePickerController!
|
||||
|
||||
// TODO: Add availability back in? - contactAvailabilitySummaryDataSource: ContactAvailabilitySummaryDataSource?,
|
||||
|
||||
/// Creates and sets up a calendar-style date picker, with a specified date shown first.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - initialDate: A date object on the day chosen to be selected.
|
||||
/// - overrideSubtitle: An optional string describing an optional subtitle for this date picker.
|
||||
public init(initialDate: Date, subtitle: String? = nil) {
|
||||
self.subtitle = subtitle
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
let selectedDate = initialDate.startOfDay
|
||||
initContentController(startDate: selectedDate, endDate: selectedDate.adding(hours: 23, minutes: 59), selectionMode: .start)
|
||||
initTitleView()
|
||||
}
|
||||
|
||||
public required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
/// Presents this date picker over the selected view controller, using a card modal style.
|
||||
///
|
||||
/// - Parameter presentingViewController: The view controller the date picker will be presented on top of
|
||||
public func present(from presentingViewController: UIViewController) {
|
||||
if UIAccessibilityIsVoiceOverRunning() {
|
||||
let dateTimePicker = MSDateTimePicker(date: date, showsTime: false)
|
||||
dateTimePicker.delegate = self
|
||||
dateTimePicker.present(from: presentingViewController)
|
||||
}
|
||||
|
||||
let navController = MSCardPresenterNavigationController(rootViewController: self)
|
||||
let pageCardPresenterVC = MSPageCardPresenterController(viewControllers: [navController], startingIndex: 0)
|
||||
|
||||
pageCardPresenterVC.onDismiss = {
|
||||
presentingViewController.dismiss(animated: true)
|
||||
}
|
||||
|
||||
presentingViewController.present(pageCardPresenterVC, animated: true)
|
||||
}
|
||||
|
||||
open override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
addChildController(contentController)
|
||||
initNavigationBar()
|
||||
}
|
||||
|
||||
open override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
|
||||
updateTitleFrame()
|
||||
|
||||
contentController.view.frame = view.bounds
|
||||
}
|
||||
|
||||
open override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
// Hide default bottom border of navigation bar
|
||||
navigationController?.navigationBar.hideBottomBorder()
|
||||
}
|
||||
|
||||
// MARK: Create components
|
||||
|
||||
private func initTitleView() {
|
||||
titleView = MSTwoLinesTitleView()
|
||||
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTitleButtonTapped))
|
||||
titleView.addGestureRecognizer(tapRecognizer)
|
||||
|
||||
updateNavigationBar()
|
||||
}
|
||||
|
||||
private func initContentController(startDate: Date, endDate: Date, selectionMode: MSDatePickerSelectionManager.SelectionMode) {
|
||||
contentController = MSDatePickerController(
|
||||
startDate: startDate,
|
||||
endDate: endDate,
|
||||
selectionMode: selectionMode
|
||||
)
|
||||
contentController.delegate = self
|
||||
}
|
||||
|
||||
// MARK: Add components to hierarchy
|
||||
|
||||
private func initNavigationBar() {
|
||||
if let image = UIImage.staticImageNamed("checkmark-blue-25x25"),
|
||||
let landscapeImage = UIImage.staticImageNamed("checkmark-blue-thin-20x20") {
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(image: image, landscapeImagePhone: landscapeImage, style: .plain, target: self, action: #selector(handleDidTapDone))
|
||||
}
|
||||
if let image = UIImage.staticImageNamed("back-25x25") {
|
||||
navigationItem.leftBarButtonItem = UIBarButtonItem(image: image, style: .plain, target: self, action: #selector(handleDidTapBack))
|
||||
navigationItem.leftBarButtonItem?.tintColor = MSColors.buttonImage
|
||||
}
|
||||
navigationItem.titleView = titleView
|
||||
}
|
||||
|
||||
// MARK: Update components
|
||||
|
||||
private func updateNavigationBar() {
|
||||
let title = String.dateString(from: contentController.focusDate, compactness: .shortDaynameShortMonthnameDay)
|
||||
titleView.setup(title: title, subtitle: subtitle)
|
||||
updateTitleFrame()
|
||||
}
|
||||
|
||||
private func updateTitleFrame() {
|
||||
// Title
|
||||
if let navigationController = navigationController {
|
||||
titleView.frame = CGRect(
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
width: Constants.titleButtonWidth,
|
||||
height: navigationController.navigationBar.height
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Handlers
|
||||
|
||||
@objc private func handleTitleButtonTapped() {
|
||||
contentController.scrollToStartDate(animated: true)
|
||||
}
|
||||
|
||||
@objc private func handleDidTapDone() {
|
||||
delegate?.datePicker(self, didPickDate: date)
|
||||
}
|
||||
|
||||
@objc private func handleDidTapBack() {
|
||||
parent?.dismiss(animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MSDatePicker: MSDatePickerControllerDelegate
|
||||
|
||||
extension MSDatePicker: MSDatePickerControllerDelegate {
|
||||
func datePickerController(_ datePickerController: MSDatePickerController, didSelectDate: Date) {
|
||||
updateNavigationBar()
|
||||
// TODO: Add delegate call for notifying date did change
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MSDatePicker: MSDateTimePickerDelegate
|
||||
|
||||
extension MSDatePicker: MSDateTimePickerDelegate {
|
||||
func dateTimePicker(_ dateTimePicker: MSDateTimePicker, didPickDate date: Date) {
|
||||
delegate?.datePicker(self, didPickDate: date)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MSDatePicker: MSCardPresentable
|
||||
|
||||
extension MSDatePicker: MSCardPresentable {
|
||||
public func idealSize() -> CGSize {
|
||||
return contentController.idealSize()
|
||||
}
|
||||
}
|
|
@ -4,10 +4,11 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
// MARK: MSDatePickerControllerDelegate
|
||||
// MARK: MSDatePickerHeaderStyle
|
||||
|
||||
protocol MSDatePickerControllerDelegate: class {
|
||||
func datePickerController(_ datePickerController: MSDatePickerController, didSelectDate date: Date)
|
||||
@objc enum MSDatePickerHeaderStyle: Int {
|
||||
case light
|
||||
case dark
|
||||
}
|
||||
|
||||
// MARK: - MSDatePickerController
|
||||
|
@ -16,10 +17,25 @@ protocol MSDatePickerControllerDelegate: class {
|
|||
* Represents a date picker, that enables the user to scroll through years vertically week by week.
|
||||
* The user can select a date or a range of dates.
|
||||
*/
|
||||
|
||||
class MSDatePickerController: UIViewController {
|
||||
class MSDatePickerController: UIViewController, DateTimePicker {
|
||||
private struct Constants {
|
||||
static let idealWidth: CGFloat = 343
|
||||
// TODO: Make title button width dynamic
|
||||
static let titleButtonWidth: CGFloat = 160
|
||||
static let preloadAvailabilityDaysOffset: Int = 30
|
||||
}
|
||||
|
||||
// Temporary date property for single date selection and DateTimePicker conformance. Will remove when MSDateSelectable is refactored to include start and end date.
|
||||
/// The currently selected whole date. Automatically changes to start of day when set.
|
||||
var date: Date {
|
||||
get {
|
||||
return startDate
|
||||
}
|
||||
set {
|
||||
let startDate = newValue.startOfDay
|
||||
setup(startDate: startDate, endDate: startDate.adding(hours: 23, minutes: 59))
|
||||
updateNavigationBar()
|
||||
}
|
||||
}
|
||||
|
||||
var firstWeekday: Int = Calendar.current.firstWeekday
|
||||
|
@ -27,8 +43,6 @@ class MSDatePickerController: UIViewController {
|
|||
var startDate: Date { return selectionManager.selectedDates.startDate }
|
||||
var endDate: Date { return selectionManager.selectedDates.endDate }
|
||||
|
||||
weak var delegate: MSDatePickerControllerDelegate?
|
||||
|
||||
var visibleDates: (startDate: Date, endDate: Date)? {
|
||||
let contentOffset = calendarView.collectionView.contentOffset
|
||||
return visibleDates(at: CGPoint(x: 0, y: contentOffset.y))
|
||||
|
@ -38,6 +52,11 @@ class MSDatePickerController: UIViewController {
|
|||
return selectionManager.selectionMode == .start ? startDate : endDate
|
||||
}
|
||||
|
||||
weak var delegate: DateTimePickerDelegate?
|
||||
|
||||
private var titleView: MSTwoLinesTitleView!
|
||||
private let subtitle: String?
|
||||
|
||||
private var monthOverlayIsShown: Bool = false
|
||||
private var reloadDataAfterOverlayIsNeeded: Bool = false
|
||||
|
||||
|
@ -45,20 +64,33 @@ class MSDatePickerController: UIViewController {
|
|||
private let calendarView = MSCalendarView()
|
||||
private var calendarViewDataSource: MSCalendarViewDataSource!
|
||||
|
||||
// TODO: Add availability back in? availabilityDataSource: MeetingCalendarDatePickerAvailabilityDataSource?
|
||||
init(startDate: Date, endDate: Date, selectionMode: MSDatePickerSelectionManager.SelectionMode) {
|
||||
// TODO: Add availability back in? - contactAvailabilitySummaryDataSource: ContactAvailabilitySummaryDataSource?,
|
||||
|
||||
/// Creates and sets up a calendar-style date picker, with a specified date shown first.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - startDate: A date object for the start day or day/time to be initially selected. Until range implemented, changes to start of day.
|
||||
/// - endDate: An optional date object for an end day or day/time to be initially selected. Until range implemented, ignored.
|
||||
/// - selectionMode: The side (start or end) of the current range to be selected on this picker.
|
||||
/// - subtitle: An optional string describing an optional subtitle for this date picker.
|
||||
init(startDate: Date, endDate: Date? = nil, selectionMode: MSDatePickerSelectionManager.SelectionMode = .start, subtitle: String? = nil) {
|
||||
self.subtitle = subtitle
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
calendarViewDataSource = MSCalendarViewDataSource(styleDataSource: self)
|
||||
|
||||
let startDate = startDate.startOfDay
|
||||
selectionManager = MSDatePickerSelectionManager(
|
||||
dataSource: calendarViewDataSource,
|
||||
startDate: startDate,
|
||||
endDate: endDate,
|
||||
endDate: startDate.adding(hours: 23, minutes: 59),
|
||||
selectionMode: selectionMode
|
||||
)
|
||||
|
||||
initTitleView()
|
||||
}
|
||||
|
||||
public required init?(coder aDecoder: NSCoder) {
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
|
@ -79,7 +111,7 @@ class MSDatePickerController: UIViewController {
|
|||
}
|
||||
}
|
||||
|
||||
public override func viewDidLoad() {
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
calendarView.weekdayHeadingView.setup(horizontalSizeClass: traitCollection.horizontalSizeClass, firstWeekday: firstWeekday)
|
||||
|
@ -99,27 +131,65 @@ class MSDatePickerController: UIViewController {
|
|||
calendarView.collectionViewLayout.delegate = self
|
||||
|
||||
view.addSubview(calendarView)
|
||||
|
||||
initNavigationBar()
|
||||
}
|
||||
|
||||
public override func viewWillAppear(_ animated: Bool) {
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
scrollToStartDate(animated: false)
|
||||
|
||||
// Hide default bottom border of navigation bar
|
||||
navigationController?.navigationBar.hideBottomBorder()
|
||||
}
|
||||
|
||||
public override func viewWillLayoutSubviews() {
|
||||
override func viewWillLayoutSubviews() {
|
||||
super.viewWillLayoutSubviews()
|
||||
|
||||
calendarView.frame = view.bounds
|
||||
}
|
||||
|
||||
func scrollToStartDate(animated: Bool) {
|
||||
private func initTitleView() {
|
||||
titleView = MSTwoLinesTitleView()
|
||||
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTitleButtonTapped))
|
||||
titleView.addGestureRecognizer(tapRecognizer)
|
||||
|
||||
updateNavigationBar()
|
||||
}
|
||||
|
||||
private func initNavigationBar() {
|
||||
if let image = UIImage.staticImageNamed("checkmark-blue-25x25"),
|
||||
let landscapeImage = UIImage.staticImageNamed("checkmark-blue-thin-20x20") {
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(image: image, landscapeImagePhone: landscapeImage, style: .plain, target: self, action: #selector(handleDidTapDone))
|
||||
}
|
||||
navigationItem.titleView = titleView
|
||||
}
|
||||
|
||||
private func updateNavigationBar() {
|
||||
let title = String.dateString(from: focusDate, compactness: .shortDaynameShortMonthnameDay)
|
||||
titleView.setup(title: title, subtitle: subtitle)
|
||||
updateTitleFrame()
|
||||
}
|
||||
|
||||
private func updateTitleFrame() {
|
||||
if let navigationController = navigationController {
|
||||
titleView.frame = CGRect(
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
width: Constants.titleButtonWidth,
|
||||
height: navigationController.navigationBar.height
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private func scrollToStartDate(animated: Bool) {
|
||||
let targetIndexPath = IndexPath(item: 0, section: max(selectionManager.startDateIndexPath.section - 1, 0))
|
||||
calendarView.collectionView.scrollToItem(at: targetIndexPath, at: [.top], animated: animated)
|
||||
// TODO: Notify of visible date?
|
||||
}
|
||||
|
||||
func setNeedsReloadAvailability() {
|
||||
private func setNeedsReloadAvailability() {
|
||||
reloadDataAfterOverlayIsNeeded = true
|
||||
reloadDataAfterOverlayHiddenIfNeeded()
|
||||
}
|
||||
|
@ -151,12 +221,22 @@ class MSDatePickerController: UIViewController {
|
|||
let endDate = calendarViewDataSource.dayEnd(forDayAt: endIndexPath)
|
||||
return (startDate: startDate, endDate: endDate)
|
||||
}
|
||||
|
||||
// MARK: Handlers
|
||||
|
||||
@objc private func handleTitleButtonTapped() {
|
||||
scrollToStartDate(animated: true)
|
||||
}
|
||||
|
||||
@objc private func handleDidTapDone() {
|
||||
delegate?.dateTimePicker(self, didPickDate: date)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MSDatePickerController: UICollectionViewDelegate
|
||||
|
||||
extension MSDatePickerController: UICollectionViewDelegate {
|
||||
public func collectionView(_ collectionView: UICollectionView, willDisplaySupplementaryView view: UICollectionReusableView, forElementKind elementKind: String, at indexPath: IndexPath) {
|
||||
func collectionView(_ collectionView: UICollectionView, willDisplaySupplementaryView view: UICollectionReusableView, forElementKind elementKind: String, at indexPath: IndexPath) {
|
||||
guard let monthBannerView = view as? MSCalendarViewMonthBannerView else {
|
||||
return
|
||||
}
|
||||
|
@ -164,7 +244,7 @@ extension MSDatePickerController: UICollectionViewDelegate {
|
|||
monthBannerView.setVisible(monthOverlayIsShown, animated: false)
|
||||
}
|
||||
|
||||
public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
|
||||
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
|
||||
guard let dayCell = cell as? MSCalendarViewDayCell else {
|
||||
return
|
||||
}
|
||||
|
@ -174,11 +254,11 @@ extension MSDatePickerController: UICollectionViewDelegate {
|
|||
updateSelectionOfVisibleCells()
|
||||
}
|
||||
|
||||
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
didTapItem(at: indexPath)
|
||||
}
|
||||
|
||||
public func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
|
||||
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
|
||||
didTapItem(at: indexPath)
|
||||
}
|
||||
|
||||
|
@ -188,7 +268,9 @@ extension MSDatePickerController: UICollectionViewDelegate {
|
|||
updateSelectionOfVisibleCells()
|
||||
|
||||
let (startDate, _) = selectionManager.selectedDates
|
||||
delegate?.datePickerController(self, didSelectDate: startDate)
|
||||
delegate?.dateTimePicker(self, didSelectDate: startDate)
|
||||
|
||||
updateNavigationBar()
|
||||
}
|
||||
|
||||
private func updateSelectionOfVisibleCells() {
|
||||
|
@ -248,7 +330,7 @@ extension MSDatePickerController: UIScrollViewDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
||||
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
||||
changeMonthOverlayVisibility(false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,28 +4,28 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
// MARK: MSDateTimePickerDelegate
|
||||
// MARK: MSDateTimePickerController
|
||||
|
||||
@objc protocol MSDateTimePickerDelegate: class {
|
||||
@objc func dateTimePicker(_ dateTimePicker: MSDateTimePicker, didPickDate date: Date)
|
||||
@objc optional func dateTimePicker(_ dateTimePicker: MSDateTimePicker, didSelectDate date: Date)
|
||||
}
|
||||
|
||||
// MARK: - MSDateTimePicker
|
||||
|
||||
class MSDateTimePicker: UIViewController {
|
||||
class MSDateTimePickerController: UIViewController, DateTimePicker {
|
||||
private struct Constants {
|
||||
static let idealRowCount: Int = 7
|
||||
static let idealWidth: CGFloat = 320
|
||||
static let titleButtonWidth: CGFloat = 160
|
||||
}
|
||||
|
||||
var mode: MSDateTimePickerViewMode { return dateTimePickerView.mode }
|
||||
|
||||
weak var delegate: MSDateTimePickerDelegate?
|
||||
var date: Date {
|
||||
didSet {
|
||||
dateTimePickerView.setDate(date, animated: false)
|
||||
updateNavigationBar()
|
||||
}
|
||||
}
|
||||
|
||||
private var date: Date
|
||||
weak var delegate: DateTimePickerDelegate?
|
||||
|
||||
private let dateTimePickerView: MSDateTimePickerView
|
||||
private let titleView = MSTwoLinesTitleView()
|
||||
|
||||
// TODO: Add availability back in? - contactAvailabilitySummaryDataSource: ContactAvailabilitySummaryDataSource?,
|
||||
init(date: Date, showsTime: Bool = true) {
|
||||
|
@ -38,32 +38,19 @@ class MSDateTimePicker: UIViewController {
|
|||
|
||||
dateTimePickerView.addTarget(self, action: #selector(handleDidSelectDate(_:)), for: .valueChanged)
|
||||
|
||||
initNavigationBar()
|
||||
updateNavigationBar()
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
/// Presents this date time picker over the selected view controller, using a card modal style.
|
||||
///
|
||||
/// - Parameter presentingViewController: The view controller the date picker will be presented on top of
|
||||
func present(from presentingViewController: UIViewController) {
|
||||
let navController = MSCardPresenterNavigationController(rootViewController: self)
|
||||
let pageCardPresenterVC = MSPageCardPresenterController(viewControllers: [navController], startingIndex: 0)
|
||||
|
||||
pageCardPresenterVC.onDismiss = {
|
||||
self.dismiss(accept: false)
|
||||
}
|
||||
|
||||
presentingViewController.present(pageCardPresenterVC, animated: true)
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.backgroundColor = MSColors.background
|
||||
|
||||
view.addSubview(dateTimePickerView)
|
||||
initNavigationBar()
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
|
@ -83,9 +70,23 @@ class MSDateTimePicker: UIViewController {
|
|||
let landscapeImage = UIImage.staticImageNamed("checkmark-blue-thin-20x20") {
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(image: image, landscapeImagePhone: landscapeImage, style: .plain, target: self, action: #selector(handleDidTapDone))
|
||||
}
|
||||
if let image = UIImage.staticImageNamed("back-25x25") {
|
||||
navigationItem.leftBarButtonItem = UIBarButtonItem(image: image, style: .plain, target: self, action: #selector(handleDidTapBack))
|
||||
navigationItem.leftBarButtonItem?.tintColor = MSColors.buttonImage
|
||||
navigationItem.titleView = titleView
|
||||
}
|
||||
|
||||
private func updateNavigationBar() {
|
||||
let title = String.dateString(from: date, compactness: .shortDaynameShortMonthnameDay)
|
||||
titleView.setup(title: title)
|
||||
updateTitleFrame()
|
||||
}
|
||||
|
||||
private func updateTitleFrame() {
|
||||
if let navigationController = navigationController {
|
||||
titleView.frame = CGRect(
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
width: Constants.titleButtonWidth,
|
||||
height: navigationController.navigationBar.height
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,21 +99,17 @@ class MSDateTimePicker: UIViewController {
|
|||
|
||||
@objc private func handleDidSelectDate(_ datePicker: MSDateTimePickerView) {
|
||||
date = datePicker.date
|
||||
delegate?.dateTimePicker?(self, didSelectDate: date)
|
||||
delegate?.dateTimePicker(self, didSelectDate: date)
|
||||
}
|
||||
|
||||
@objc private func handleDidTapDone(_ item: UIBarButtonItem) {
|
||||
dismiss(accept: true)
|
||||
}
|
||||
|
||||
@objc private func handleDidTapBack(_ item: UIBarButtonItem) {
|
||||
dismiss(accept: false)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MSDateTimePicker: MSCardPresentable
|
||||
// MARK: - MSDateTimePickerController: MSCardPresentable
|
||||
|
||||
extension MSDateTimePicker: MSCardPresentable {
|
||||
extension MSDateTimePickerController: MSCardPresentable {
|
||||
func idealSize() -> CGSize {
|
||||
let height = MSDateTimePickerViewLayout.height(forRowCount: Constants.idealRowCount)
|
||||
return CGSize(width: Constants.idealWidth, height: height)
|
|
@ -0,0 +1,117 @@
|
|||
//
|
||||
// Copyright © 2018 Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: MSDateTimePickerMode
|
||||
|
||||
@objc public enum MSDateTimePickerMode: Int {
|
||||
case date
|
||||
case dateTime
|
||||
}
|
||||
|
||||
// MARK: - MSDateTimePickerDelegate
|
||||
|
||||
@objc public protocol MSDateTimePickerDelegate: class {
|
||||
/// Allows a class to be notified when a user confirms their selected date
|
||||
func dateTimePicker(_ dateTimePicker: MSDateTimePicker, didPickDate date: Date)
|
||||
}
|
||||
|
||||
// MARK: - DateTimePicker
|
||||
|
||||
protocol DateTimePicker: class {
|
||||
var date: Date { get set }
|
||||
var delegate: DateTimePickerDelegate? { get set }
|
||||
}
|
||||
|
||||
// MARK: - DateTimePickerDelegate
|
||||
|
||||
protocol DateTimePickerDelegate: class {
|
||||
func dateTimePicker(_ dateTimePicker: DateTimePicker, didPickDate date: Date)
|
||||
func dateTimePicker(_ dateTimePicker: DateTimePicker, didSelectDate date: Date)
|
||||
}
|
||||
|
||||
// MARK: - MSDateTimePicker
|
||||
|
||||
/// Manages the presentation and coordination of different date and time pickers
|
||||
public class MSDateTimePicker: NSObject {
|
||||
public private(set) var mode: MSDateTimePickerMode?
|
||||
@objc public weak var delegate: MSDateTimePickerDelegate?
|
||||
|
||||
private var presentingController: UIViewController?
|
||||
private var presentedPickers: [DateTimePicker]?
|
||||
|
||||
/// Presents a picker or set of pickers from a `presentingController` depending on the mode selected. Also handles accessibility replacement presentation.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - presentingController: The view controller that is presenting these pickers
|
||||
/// - mode: Enum describing which mode of pickers should be presented
|
||||
/// - date: The initial date selected on the presented pickers
|
||||
@objc public func present(from presentingController: UIViewController, with mode: MSDateTimePickerMode, for date: Date = Date()) {
|
||||
self.presentingController = presentingController
|
||||
if UIAccessibilityIsVoiceOverRunning() {
|
||||
presentDateTimePickerForAccessibility(initialDate: date, showsTime: mode == .dateTime)
|
||||
return
|
||||
}
|
||||
self.mode = mode
|
||||
switch mode {
|
||||
case .date:
|
||||
presentDatePicker(initialDate: date)
|
||||
case .dateTime:
|
||||
presentDateTimePicker(initialDate: date)
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func dismiss() {
|
||||
presentingController?.dismiss(animated: true)
|
||||
mode = nil
|
||||
presentedPickers = nil
|
||||
presentingController = nil
|
||||
}
|
||||
|
||||
private func presentDatePicker(initialDate: Date) {
|
||||
let datePicker = MSDatePickerController(startDate: initialDate)
|
||||
present([datePicker])
|
||||
}
|
||||
|
||||
private func presentDateTimePicker(initialDate: Date) {
|
||||
let datePicker = MSDatePickerController(startDate: initialDate)
|
||||
let dateTimePicker = MSDateTimePickerController(date: initialDate, showsTime: true)
|
||||
present([datePicker, dateTimePicker])
|
||||
}
|
||||
|
||||
private func presentDateTimePickerForAccessibility(initialDate: Date, showsTime: Bool) {
|
||||
let dateTimePicker = MSDateTimePickerController(date: initialDate, showsTime: showsTime)
|
||||
present([dateTimePicker])
|
||||
}
|
||||
|
||||
private func present(_ pickers: [DateTimePicker]) {
|
||||
pickers.forEach { $0.delegate = self }
|
||||
presentedPickers = pickers
|
||||
|
||||
let viewControllers = pickers.map { MSCardPresenterNavigationController(rootViewController: $0 as! UIViewController) }
|
||||
let pageCardPresenter = MSPageCardPresenterController(viewControllers: viewControllers, startingIndex: 0)
|
||||
pageCardPresenter.onDismiss = {
|
||||
self.dismiss()
|
||||
}
|
||||
presentingController?.present(pageCardPresenter, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - MSDateTimePicker: DateTimePickerDelegate
|
||||
|
||||
extension MSDateTimePicker: DateTimePickerDelegate {
|
||||
func dateTimePicker(_ dateTimePicker: DateTimePicker, didPickDate date: Date) {
|
||||
delegate?.dateTimePicker(self, didPickDate: date)
|
||||
}
|
||||
|
||||
func dateTimePicker(_ dateTimePicker: DateTimePicker, didSelectDate date: Date) {
|
||||
guard let presentedPickers = presentedPickers else {
|
||||
return
|
||||
}
|
||||
for picker in presentedPickers where picker !== dateTimePicker {
|
||||
picker.date = date
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,8 +6,6 @@ import Foundation
|
|||
|
||||
public extension Calendar {
|
||||
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]()
|
||||
|
||||
static func sharedCalendarWithTimeZone(_ timeZone: TimeZone?) -> Calendar {
|
||||
|
|
Загрузка…
Ссылка в новой задаче