mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Time Picker Improvements
This commit is contained in:
parent
fa645bba66
commit
532dda0388
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user