diff --git a/submodules/DatePickerNode/Sources/DatePickerNode.swift b/submodules/DatePickerNode/Sources/DatePickerNode.swift index a65721bace..331134181d 100644 --- a/submodules/DatePickerNode/Sources/DatePickerNode.swift +++ b/submodules/DatePickerNode/Sources/DatePickerNode.swift @@ -322,6 +322,7 @@ public final class DatePickerNode: ASDisplayNode { self.updateState(updatedState, animated: false) self.pickerNode.minimumDate = newValue + self.timePickerNode.minimumDate = newValue if let size = self.validLayout { let _ = self.updateLayout(size: size, transition: .immediate) @@ -342,6 +343,7 @@ public final class DatePickerNode: ASDisplayNode { self.updateState(updatedState, animated: false) self.pickerNode.maximumDate = newValue + self.timePickerNode.maximumDate = newValue if let size = self.validLayout { let _ = self.updateLayout(size: size, transition: .immediate) @@ -396,6 +398,9 @@ public final class DatePickerNode: ASDisplayNode { self.pickerNode.minimumDate = self.state.minDate self.pickerNode.maximumDate = self.state.maxDate + self.timePickerNode.minimumDate = self.state.minDate + self.timePickerNode.maximumDate = self.state.maxDate + self.monthButtonNode = HighlightTrackingButtonNode() self.monthTextNode = ImmediateTextNode() self.monthArrowNode = ASImageNode() @@ -921,9 +926,7 @@ private class TimeInputView: UIView, UIKeyInput { var textUpdated: ((String) -> Void)? override func becomeFirstResponder() -> Bool { - if self.isFirstResponder { - self.didReset = false - } + self.didReset = false let result = super.becomeFirstResponder() self.focusUpdated?(true) return result @@ -937,7 +940,7 @@ private class TimeInputView: UIView, UIKeyInput { var length: Int = 4 - private var didReset = false + var didReset = false private let nonDigits = CharacterSet.decimalDigits.inverted func insertText(_ text: String) { if text.rangeOfCharacter(from: nonDigits) != nil { @@ -1024,6 +1027,12 @@ private class TimeInputNode: ASDisplayNode { view.textUpdated = self.textUpdated } } + + func reset() { + if let view = self.view as? TimeInputView { + view.didReset = false + } + } } private final class TimePickerNode: ASDisplayNode { @@ -1064,8 +1073,9 @@ private final class TimePickerNode: ASDisplayNode { } } } - var minDate: Date? - var maxDate: Date? + + var minimumDate: Date? + var maximumDate: Date? var valueChanged: ((Date) -> Void)? @@ -1205,23 +1215,7 @@ private final class TimePickerNode: ASDisplayNode { } } self.hoursNode.selected = { [weak self] index in - guard let strongSelf = self else { - return - } - switch dateTimeFormat.timeFormat { - case .military: - let hour = index - if let date = strongSelf.date { - var components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date) - components.hour = hour - if let newDate = calendar.date(from: components) { - strongSelf.date = newDate - strongSelf.valueChanged?(newDate) - } - } - case .regular: - break - } + self?.updateTime() } self.minutesNode.count = { @@ -1248,29 +1242,59 @@ private final class TimePickerNode: ASDisplayNode { } } } - self.minutesNode.selected = { [weak self] index in - guard let strongSelf = self else { - return - } - switch dateTimeFormat.timeFormat { - case .military: - let minute = index - if let date = strongSelf.date { - var components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date) - components.minute = minute - if let newDate = calendar.date(from: components) { - strongSelf.date = newDate - strongSelf.valueChanged?(newDate) - } - } - case .regular: - break - } + self.minutesNode.selected = { [weak self] _ in + self?.updateTime() } self.update() } + private func updateTime() { + switch self.dateTimeFormat.timeFormat { + case .military: + let hour = self.hoursNode.currentSelectedIndex + let minute = self.minutesNode.currentSelectedIndex + + let date = self.date ?? Date() + + var components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date) + components.hour = hour + components.minute = minute + if var newDate = calendar.date(from: components) { + if let minDate = self.minimumDate, newDate <= minDate { + if let nextDate = calendar.date(byAdding: .day, value: 1, to: newDate) { + newDate = nextDate + } + } + self.date = newDate + self.valueChanged?(newDate) + } + + case .regular: + let hour = self.hoursNode.currentSelectedIndex + let minute = self.minutesNode.currentSelectedIndex + + let date = self.date ?? Date() + + var components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date) + if self.amPMSelectorNode.selectedIndex == 0 { + components.hour = hour >= 12 ? hour - 12 : hour + } else if self.amPMSelectorNode.selectedIndex == 1 { + components.hour = hour < 12 ? hour + 12 : hour + } + components.minute = minute + if var newDate = calendar.date(from: components) { + if let minDate = self.minimumDate, newDate <= minDate { + if let nextDate = calendar.date(byAdding: .day, value: 1, to: newDate) { + newDate = nextDate + } + } + self.date = newDate + self.valueChanged?(newDate) + } + } + } + override func didLoad() { super.didLoad() @@ -1355,6 +1379,23 @@ private final class TimePickerNode: ASDisplayNode { private var selection: Selection { didSet { + self.typing = false + self.inputNode.reset() + switch self.selection { + case .none: + break + case .hours: + self.inputNode.text = self.hoursNode.titleAt?(self.hoursNode.currentSelectedIndex) ?? "" + self.inputNode.length = 2 + case .minutes: + self.inputNode.text = self.minutesNode.titleAt?(self.minutesNode.currentSelectedIndex) ?? "" + self.inputNode.length = 2 + case .all: + let hours = self.minutesNode.titleAt?(self.hoursNode.currentSelectedIndex) ?? "" + let minutes = self.minutesNode.titleAt?(self.minutesNode.currentSelectedIndex) ?? "" + self.inputNode.text = "\(hours)\(minutes)" + self.inputNode.length = 4 + } self.update() } } @@ -1417,8 +1458,6 @@ private final class TimePickerNode: ASDisplayNode { self.hoursNode.isHidden = false self.minutesNode.isHidden = false } - - self.inputNode.length = 2 case .minutes: colonColor = self.theme.textColor self.colonNode.alpha = 0.35 @@ -1446,8 +1485,6 @@ private final class TimePickerNode: ASDisplayNode { self.hoursNode.isHidden = false self.minutesNode.isHidden = false } - - self.inputNode.length = 2 case .all: colonColor = self.theme.accentColor self.colonNode.alpha = 1.0 @@ -1475,8 +1512,6 @@ private final class TimePickerNode: ASDisplayNode { self.hoursNode.isHidden = false self.minutesNode.isHidden = false } - - self.inputNode.length = 4 } if let size = self.validLayout { diff --git a/submodules/DatePickerNode/Sources/TapeNode.swift b/submodules/DatePickerNode/Sources/TapeNode.swift index d72a7e074c..a1ad195d49 100644 --- a/submodules/DatePickerNode/Sources/TapeNode.swift +++ b/submodules/DatePickerNode/Sources/TapeNode.swift @@ -63,7 +63,9 @@ open class TapeNode: ASDisplayNode { return UITableView() }() - private var infinityRowsMultiplier: Int = 1 + private var infinityRowsMultiplier: Int { + return generateInfinityRowsMultiplier() + } var currentSelectedRow: Int? var currentSelectedIndex: Int { @@ -86,8 +88,6 @@ open class TapeNode: ASDisplayNode { } fileprivate func setup() { - self.infinityRowsMultiplier = self.generateInfinityRowsMultiplier() - if #available(iOS 11.0, *) { self.tableView.contentInsetAdjustmentBehavior = .never } @@ -162,23 +162,41 @@ open class TapeNode: ASDisplayNode { if self.currentSelectedIndex == self.indexForRow(row) { return } - var finalRow = row + var finalRow = row if row <= self.numberOfRows { - let middleMultiplier = (self.infinityRowsMultiplier / 2) + let middleMultiplier = self.infinityRowsMultiplier / 2 let middleIndex = self.numberOfRows * middleMultiplier finalRow = middleIndex - (self.numberOfRows - finalRow) } - self.currentSelectedRow = finalRow + if let currentSelectedRow = self.currentSelectedRow { self.tableView.setContentOffset(CGPoint(x: 0.0, y: CGFloat(currentSelectedRow) * self.rowHeight), animated: animated) } } + func selectMiddleRow() { + var finalRow = self.currentSelectedIndex + let middleMultiplier = self.infinityRowsMultiplier / 2 + let middleIndex = self.numberOfRows * middleMultiplier + finalRow = middleIndex - (self.numberOfRows - finalRow) + + self.currentSelectedRow = finalRow + + if let currentSelectedRow = self.currentSelectedRow { + self.tableView.setContentOffset(CGPoint(x: 0.0, y: CGFloat(currentSelectedRow) * self.rowHeight), animated: false) + } + } + open func reloadPickerView() { self.tableView.reloadData() } + + private func hapticTap() { + self.hapticFeedback.impact(.light) + AudioServicesPlaySystemSound(1157) + } } extension TapeNode: UITableViewDataSource { @@ -248,15 +266,18 @@ extension TapeNode: UIScrollViewDelegate { if !decelerate { self.isScrolling = false self.isScrollingUpdated?(false) + + self.selectMiddleRow() } } public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { self.isScrolling = false self.isScrollingUpdated?(false) + + self.selectMiddleRow() } - public func scrollViewDidScroll(_ scrollView: UIScrollView) { let partialRow = Float(scrollView.contentOffset.y / self.rowHeight) let roundedRow = Int(lroundf(partialRow)) @@ -264,8 +285,7 @@ extension TapeNode: UIScrollViewDelegate { if self.previousRoundedRow != roundedRow && self.isScrolling { self.previousRoundedRow = roundedRow - self.hapticFeedback.impact() - AudioServicesPlaySystemSound(1157) + self.hapticTap() } } }