mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 01:10:09 +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.updateState(updatedState, animated: false)
|
||||||
|
|
||||||
self.pickerNode.minimumDate = newValue
|
self.pickerNode.minimumDate = newValue
|
||||||
|
self.timePickerNode.minimumDate = newValue
|
||||||
|
|
||||||
if let size = self.validLayout {
|
if let size = self.validLayout {
|
||||||
let _ = self.updateLayout(size: size, transition: .immediate)
|
let _ = self.updateLayout(size: size, transition: .immediate)
|
||||||
@ -342,6 +343,7 @@ public final class DatePickerNode: ASDisplayNode {
|
|||||||
self.updateState(updatedState, animated: false)
|
self.updateState(updatedState, animated: false)
|
||||||
|
|
||||||
self.pickerNode.maximumDate = newValue
|
self.pickerNode.maximumDate = newValue
|
||||||
|
self.timePickerNode.maximumDate = newValue
|
||||||
|
|
||||||
if let size = self.validLayout {
|
if let size = self.validLayout {
|
||||||
let _ = self.updateLayout(size: size, transition: .immediate)
|
let _ = self.updateLayout(size: size, transition: .immediate)
|
||||||
@ -396,6 +398,9 @@ public final class DatePickerNode: ASDisplayNode {
|
|||||||
self.pickerNode.minimumDate = self.state.minDate
|
self.pickerNode.minimumDate = self.state.minDate
|
||||||
self.pickerNode.maximumDate = self.state.maxDate
|
self.pickerNode.maximumDate = self.state.maxDate
|
||||||
|
|
||||||
|
self.timePickerNode.minimumDate = self.state.minDate
|
||||||
|
self.timePickerNode.maximumDate = self.state.maxDate
|
||||||
|
|
||||||
self.monthButtonNode = HighlightTrackingButtonNode()
|
self.monthButtonNode = HighlightTrackingButtonNode()
|
||||||
self.monthTextNode = ImmediateTextNode()
|
self.monthTextNode = ImmediateTextNode()
|
||||||
self.monthArrowNode = ASImageNode()
|
self.monthArrowNode = ASImageNode()
|
||||||
@ -921,9 +926,7 @@ private class TimeInputView: UIView, UIKeyInput {
|
|||||||
var textUpdated: ((String) -> Void)?
|
var textUpdated: ((String) -> Void)?
|
||||||
|
|
||||||
override func becomeFirstResponder() -> Bool {
|
override func becomeFirstResponder() -> Bool {
|
||||||
if self.isFirstResponder {
|
self.didReset = false
|
||||||
self.didReset = false
|
|
||||||
}
|
|
||||||
let result = super.becomeFirstResponder()
|
let result = super.becomeFirstResponder()
|
||||||
self.focusUpdated?(true)
|
self.focusUpdated?(true)
|
||||||
return result
|
return result
|
||||||
@ -937,7 +940,7 @@ private class TimeInputView: UIView, UIKeyInput {
|
|||||||
|
|
||||||
var length: Int = 4
|
var length: Int = 4
|
||||||
|
|
||||||
private var didReset = false
|
var didReset = false
|
||||||
private let nonDigits = CharacterSet.decimalDigits.inverted
|
private let nonDigits = CharacterSet.decimalDigits.inverted
|
||||||
func insertText(_ text: String) {
|
func insertText(_ text: String) {
|
||||||
if text.rangeOfCharacter(from: nonDigits) != nil {
|
if text.rangeOfCharacter(from: nonDigits) != nil {
|
||||||
@ -1024,6 +1027,12 @@ private class TimeInputNode: ASDisplayNode {
|
|||||||
view.textUpdated = self.textUpdated
|
view.textUpdated = self.textUpdated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func reset() {
|
||||||
|
if let view = self.view as? TimeInputView {
|
||||||
|
view.didReset = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class TimePickerNode: ASDisplayNode {
|
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)?
|
var valueChanged: ((Date) -> Void)?
|
||||||
|
|
||||||
@ -1205,23 +1215,7 @@ private final class TimePickerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.hoursNode.selected = { [weak self] index in
|
self.hoursNode.selected = { [weak self] index in
|
||||||
guard let strongSelf = self else {
|
self?.updateTime()
|
||||||
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.minutesNode.count = {
|
self.minutesNode.count = {
|
||||||
@ -1248,29 +1242,59 @@ private final class TimePickerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.minutesNode.selected = { [weak self] index in
|
self.minutesNode.selected = { [weak self] _ in
|
||||||
guard let strongSelf = self else {
|
self?.updateTime()
|
||||||
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.update()
|
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() {
|
override func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
@ -1355,6 +1379,23 @@ private final class TimePickerNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var selection: Selection {
|
private var selection: Selection {
|
||||||
didSet {
|
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()
|
self.update()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1417,8 +1458,6 @@ private final class TimePickerNode: ASDisplayNode {
|
|||||||
self.hoursNode.isHidden = false
|
self.hoursNode.isHidden = false
|
||||||
self.minutesNode.isHidden = false
|
self.minutesNode.isHidden = false
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inputNode.length = 2
|
|
||||||
case .minutes:
|
case .minutes:
|
||||||
colonColor = self.theme.textColor
|
colonColor = self.theme.textColor
|
||||||
self.colonNode.alpha = 0.35
|
self.colonNode.alpha = 0.35
|
||||||
@ -1446,8 +1485,6 @@ private final class TimePickerNode: ASDisplayNode {
|
|||||||
self.hoursNode.isHidden = false
|
self.hoursNode.isHidden = false
|
||||||
self.minutesNode.isHidden = false
|
self.minutesNode.isHidden = false
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inputNode.length = 2
|
|
||||||
case .all:
|
case .all:
|
||||||
colonColor = self.theme.accentColor
|
colonColor = self.theme.accentColor
|
||||||
self.colonNode.alpha = 1.0
|
self.colonNode.alpha = 1.0
|
||||||
@ -1475,8 +1512,6 @@ private final class TimePickerNode: ASDisplayNode {
|
|||||||
self.hoursNode.isHidden = false
|
self.hoursNode.isHidden = false
|
||||||
self.minutesNode.isHidden = false
|
self.minutesNode.isHidden = false
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inputNode.length = 4
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let size = self.validLayout {
|
if let size = self.validLayout {
|
||||||
|
|||||||
@ -63,7 +63,9 @@ open class TapeNode: ASDisplayNode {
|
|||||||
return UITableView()
|
return UITableView()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private var infinityRowsMultiplier: Int = 1
|
private var infinityRowsMultiplier: Int {
|
||||||
|
return generateInfinityRowsMultiplier()
|
||||||
|
}
|
||||||
|
|
||||||
var currentSelectedRow: Int?
|
var currentSelectedRow: Int?
|
||||||
var currentSelectedIndex: Int {
|
var currentSelectedIndex: Int {
|
||||||
@ -86,8 +88,6 @@ open class TapeNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func setup() {
|
fileprivate func setup() {
|
||||||
self.infinityRowsMultiplier = self.generateInfinityRowsMultiplier()
|
|
||||||
|
|
||||||
if #available(iOS 11.0, *) {
|
if #available(iOS 11.0, *) {
|
||||||
self.tableView.contentInsetAdjustmentBehavior = .never
|
self.tableView.contentInsetAdjustmentBehavior = .never
|
||||||
}
|
}
|
||||||
@ -162,23 +162,41 @@ open class TapeNode: ASDisplayNode {
|
|||||||
if self.currentSelectedIndex == self.indexForRow(row) {
|
if self.currentSelectedIndex == self.indexForRow(row) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var finalRow = row
|
|
||||||
|
|
||||||
|
var finalRow = row
|
||||||
if row <= self.numberOfRows {
|
if row <= self.numberOfRows {
|
||||||
let middleMultiplier = (self.infinityRowsMultiplier / 2)
|
let middleMultiplier = self.infinityRowsMultiplier / 2
|
||||||
let middleIndex = self.numberOfRows * middleMultiplier
|
let middleIndex = self.numberOfRows * middleMultiplier
|
||||||
finalRow = middleIndex - (self.numberOfRows - finalRow)
|
finalRow = middleIndex - (self.numberOfRows - finalRow)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.currentSelectedRow = finalRow
|
self.currentSelectedRow = finalRow
|
||||||
|
|
||||||
if let currentSelectedRow = self.currentSelectedRow {
|
if let currentSelectedRow = self.currentSelectedRow {
|
||||||
self.tableView.setContentOffset(CGPoint(x: 0.0, y: CGFloat(currentSelectedRow) * self.rowHeight), animated: animated)
|
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() {
|
open func reloadPickerView() {
|
||||||
self.tableView.reloadData()
|
self.tableView.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func hapticTap() {
|
||||||
|
self.hapticFeedback.impact(.light)
|
||||||
|
AudioServicesPlaySystemSound(1157)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TapeNode: UITableViewDataSource {
|
extension TapeNode: UITableViewDataSource {
|
||||||
@ -248,15 +266,18 @@ extension TapeNode: UIScrollViewDelegate {
|
|||||||
if !decelerate {
|
if !decelerate {
|
||||||
self.isScrolling = false
|
self.isScrolling = false
|
||||||
self.isScrollingUpdated?(false)
|
self.isScrollingUpdated?(false)
|
||||||
|
|
||||||
|
self.selectMiddleRow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
||||||
self.isScrolling = false
|
self.isScrolling = false
|
||||||
self.isScrollingUpdated?(false)
|
self.isScrollingUpdated?(false)
|
||||||
|
|
||||||
|
self.selectMiddleRow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||||
let partialRow = Float(scrollView.contentOffset.y / self.rowHeight)
|
let partialRow = Float(scrollView.contentOffset.y / self.rowHeight)
|
||||||
let roundedRow = Int(lroundf(partialRow))
|
let roundedRow = Int(lroundf(partialRow))
|
||||||
@ -264,8 +285,7 @@ extension TapeNode: UIScrollViewDelegate {
|
|||||||
if self.previousRoundedRow != roundedRow && self.isScrolling {
|
if self.previousRoundedRow != roundedRow && self.isScrolling {
|
||||||
self.previousRoundedRow = roundedRow
|
self.previousRoundedRow = roundedRow
|
||||||
|
|
||||||
self.hapticFeedback.impact()
|
self.hapticTap()
|
||||||
AudioServicesPlaySystemSound(1157)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user