mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
Various Improvements
This commit is contained in:
@@ -13,8 +13,9 @@ public final class DatePickerTheme: Equatable {
|
||||
public let disabledColor: UIColor
|
||||
public let selectionColor: UIColor
|
||||
public let selectionTextColor: UIColor
|
||||
public let separatorColor: UIColor
|
||||
|
||||
public init(backgroundColor: UIColor, textColor: UIColor, secondaryTextColor: UIColor, accentColor: UIColor, disabledColor: UIColor, selectionColor: UIColor, selectionTextColor: UIColor) {
|
||||
public init(backgroundColor: UIColor, textColor: UIColor, secondaryTextColor: UIColor, accentColor: UIColor, disabledColor: UIColor, selectionColor: UIColor, selectionTextColor: UIColor, separatorColor: UIColor) {
|
||||
self.backgroundColor = backgroundColor
|
||||
self.textColor = textColor
|
||||
self.secondaryTextColor = secondaryTextColor
|
||||
@@ -22,6 +23,7 @@ public final class DatePickerTheme: Equatable {
|
||||
self.disabledColor = disabledColor
|
||||
self.selectionColor = selectionColor
|
||||
self.selectionTextColor = selectionTextColor
|
||||
self.separatorColor = separatorColor
|
||||
}
|
||||
|
||||
public static func ==(lhs: DatePickerTheme, rhs: DatePickerTheme) -> Bool {
|
||||
@@ -43,13 +45,16 @@ public final class DatePickerTheme: Equatable {
|
||||
if lhs.selectionTextColor != rhs.selectionTextColor {
|
||||
return false
|
||||
}
|
||||
if lhs.separatorColor != rhs.separatorColor {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public extension DatePickerTheme {
|
||||
convenience init(theme: PresentationTheme) {
|
||||
self.init(backgroundColor: theme.list.itemBlocksBackgroundColor, textColor: theme.list.itemPrimaryTextColor, secondaryTextColor: theme.list.itemSecondaryTextColor, accentColor: theme.list.itemAccentColor, disabledColor: theme.list.itemDisabledTextColor, selectionColor: theme.list.itemCheckColors.fillColor, selectionTextColor: theme.list.itemCheckColors.foregroundColor)
|
||||
self.init(backgroundColor: theme.list.itemBlocksBackgroundColor, textColor: theme.list.itemPrimaryTextColor, secondaryTextColor: theme.list.itemSecondaryTextColor, accentColor: theme.list.itemAccentColor, disabledColor: theme.list.itemDisabledTextColor, selectionColor: theme.list.itemCheckColors.fillColor, selectionTextColor: theme.list.itemCheckColors.foregroundColor, separatorColor: theme.list.itemBlocksSeparatorColor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +109,12 @@ private func generateNavigationArrowImage(color: UIColor, mirror: Bool) -> UIIma
|
||||
})
|
||||
}
|
||||
|
||||
private func yearRange(for state: DatePickerNode.State) -> Range<Int> {
|
||||
let minYear = calendar.component(.year, from: state.minDate)
|
||||
let maxYear = calendar.component(.year, from: state.maxDate)
|
||||
return minYear ..< maxYear + 1
|
||||
}
|
||||
|
||||
public final class DatePickerNode: ASDisplayNode {
|
||||
class MonthNode: ASDisplayNode {
|
||||
private let month: Date
|
||||
@@ -117,29 +128,9 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
var maximumDate: Date? {
|
||||
didSet {
|
||||
if let size = self.validSize {
|
||||
self.updateLayout(size: size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var minimumDate: Date? {
|
||||
didSet {
|
||||
if let size = self.validSize {
|
||||
self.updateLayout(size: size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var date: Date? {
|
||||
didSet {
|
||||
if let size = self.validSize {
|
||||
self.updateLayout(size: size)
|
||||
}
|
||||
}
|
||||
}
|
||||
var maximumDate: Date?
|
||||
var minimumDate: Date?
|
||||
var date: Date?
|
||||
|
||||
private var validSize: CGSize?
|
||||
|
||||
@@ -267,6 +258,7 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
|
||||
private let timeTitleNode: ImmediateTextNode
|
||||
private let timeFieldNode: ASImageNode
|
||||
private let timeSeparatorNode: ASDisplayNode
|
||||
|
||||
private let dayNodes: [ImmediateTextNode]
|
||||
private var currentIndex = 0
|
||||
@@ -290,6 +282,8 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
|
||||
private var validLayout: CGSize?
|
||||
|
||||
public var valueUpdated: ((Date) -> Void)?
|
||||
|
||||
public var maximumDate: Date {
|
||||
get {
|
||||
return self.state.maxDate
|
||||
@@ -348,10 +342,15 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
self.state = State(minDate: telegramReleaseDate, maxDate: upperLimitDate, date: Date(), displayingMonthSelection: false, selectedMonth: monthForDate(Date()))
|
||||
|
||||
self.timeTitleNode = ImmediateTextNode()
|
||||
self.timeTitleNode.attributedText = NSAttributedString(string: "Time", font: Font.regular(17.0), textColor: theme.textColor)
|
||||
|
||||
self.timeFieldNode = ASImageNode()
|
||||
self.timeFieldNode.displaysAsynchronously = false
|
||||
self.timeFieldNode.displayWithoutProcessing = true
|
||||
|
||||
self.timeSeparatorNode = ASDisplayNode()
|
||||
self.timeSeparatorNode.backgroundColor = theme.separatorColor
|
||||
|
||||
self.dayNodes = (0..<7).map { _ in ImmediateTextNode() }
|
||||
|
||||
self.contentNode = ASDisplayNode()
|
||||
@@ -361,8 +360,9 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
self.pickerBackgroundNode.backgroundColor = theme.backgroundColor
|
||||
self.pickerBackgroundNode.isUserInteractionEnabled = false
|
||||
|
||||
self.pickerNode = MonthPickerNode(theme: theme, strings: strings, date: self.state.date, yearRange: 2013 ..< 2038, valueChanged: { date in
|
||||
|
||||
var monthChangedImpl: ((Date) -> Void)?
|
||||
self.pickerNode = MonthPickerNode(theme: theme, strings: strings, date: self.state.date, yearRange: yearRange(for: self.state), valueChanged: { date in
|
||||
monthChangedImpl?(date)
|
||||
})
|
||||
|
||||
self.monthButtonNode = HighlightTrackingButtonNode()
|
||||
@@ -380,9 +380,13 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
|
||||
self.clipsToBounds = true
|
||||
self.backgroundColor = theme.backgroundColor
|
||||
|
||||
self.addSubnode(self.contentNode)
|
||||
|
||||
self.addSubnode(self.timeTitleNode)
|
||||
self.addSubnode(self.timeFieldNode)
|
||||
self.addSubnode(self.timeSeparatorNode)
|
||||
|
||||
self.addSubnode(self.contentNode)
|
||||
|
||||
self.dayNodes.forEach { self.addSubnode($0) }
|
||||
|
||||
self.addSubnode(self.previousButtonNode)
|
||||
@@ -420,6 +424,15 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
|
||||
self.previousButtonNode.addTarget(self, action: #selector(self.previousButtonPressed), forControlEvents: .touchUpInside)
|
||||
self.nextButtonNode.addTarget(self, action: #selector(self.nextButtonPressed), forControlEvents: .touchUpInside)
|
||||
|
||||
monthChangedImpl = { [weak self] date in
|
||||
if let strongSelf = self {
|
||||
let updatedState = State(minDate: strongSelf.state.minDate, maxDate: strongSelf.state.maxDate, date: date, displayingMonthSelection: strongSelf.state.displayingMonthSelection, selectedMonth: monthForDate(date))
|
||||
strongSelf.updateState(updatedState, animated: false)
|
||||
|
||||
strongSelf.valueUpdated?(date)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public func didLoad() {
|
||||
@@ -436,6 +449,7 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
self.state = state
|
||||
|
||||
if previousState.minDate != state.minDate || previousState.maxDate != state.maxDate {
|
||||
self.pickerNode.yearRange = yearRange(for: state)
|
||||
self.setupItems()
|
||||
} else if previousState.selectedMonth != state.selectedMonth {
|
||||
for i in 0 ..< self.months.count {
|
||||
@@ -445,6 +459,7 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.pickerNode.date = self.state.date
|
||||
|
||||
if let size = self.validLayout {
|
||||
self.updateLayout(size: size, transition: animated ? .animated(duration: 0.3, curve: .spring) : .immediate)
|
||||
@@ -455,9 +470,7 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
let startMonth = monthForDate(self.state.minDate)
|
||||
let endMonth = monthForDate(self.state.maxDate)
|
||||
let selectedMonth = monthForDate(self.state.selectedMonth)
|
||||
|
||||
let calendar = Calendar.current
|
||||
|
||||
|
||||
var currentIndex = 0
|
||||
|
||||
var months: [Date] = [startMonth]
|
||||
@@ -524,7 +537,7 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
}
|
||||
self.transitionFraction = transitionFraction
|
||||
if let size = self.validLayout {
|
||||
let topInset: CGFloat = 78.0
|
||||
let topInset: CGFloat = 78.0 + 44.0
|
||||
let containerSize = CGSize(width: size.width, height: size.height - topInset)
|
||||
self.updateItems(size: containerSize, transition: .animated(duration: 0.3, curve: .spring))
|
||||
}
|
||||
@@ -565,10 +578,13 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
var wasAdded = false
|
||||
if let current = self.monthNodes[self.months[i]] {
|
||||
itemNode = current
|
||||
current.minimumDate = self.state.minDate
|
||||
current.maximumDate = self.state.maxDate
|
||||
current.date = self.state.date
|
||||
current.updateLayout(size: size)
|
||||
} else {
|
||||
wasAdded = true
|
||||
let addedItemNode = MonthNode(theme: self.theme, month: self.months[i], minimumDate: self.minimumDate, maximumDate: self.maximumDate, date: self.date)
|
||||
let addedItemNode = MonthNode(theme: self.theme, month: self.months[i], minimumDate: self.state.minDate, maximumDate: self.state.maxDate, date: self.state.date)
|
||||
itemNode = addedItemNode
|
||||
self.monthNodes[self.months[i]] = addedItemNode
|
||||
self.contentNode.addSubnode(addedItemNode)
|
||||
@@ -604,18 +620,29 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = size
|
||||
|
||||
let topInset: CGFloat = 78.0
|
||||
let timeHeight: CGFloat = 44.0
|
||||
let topInset: CGFloat = 78.0 + timeHeight
|
||||
let sideInset: CGFloat = 16.0
|
||||
|
||||
let month = monthForDate(self.state.selectedMonth)
|
||||
let components = calendar.dateComponents([.month, .year], from: month)
|
||||
|
||||
let timeTitleSize = self.timeTitleNode.updateLayout(size)
|
||||
self.timeTitleNode.frame = CGRect(origin: CGPoint(x: 16.0, y: 11.0), size: timeTitleSize)
|
||||
self.timeSeparatorNode.frame = CGRect(x: 16.0, y: timeHeight, width: size.width - 16.0, height: UIScreenPixel)
|
||||
|
||||
self.monthTextNode.attributedText = NSAttributedString(string: stringForMonth(strings: self.strings, month: components.month.flatMap { Int32($0) - 1 } ?? 0, ofYear: components.year.flatMap { Int32($0) - 1900 } ?? 100), font: controlFont, textColor: theme.textColor)
|
||||
let monthSize = self.monthTextNode.updateLayout(size)
|
||||
|
||||
let monthTextFrame = CGRect(x: sideInset, y: 10.0, width: monthSize.width, height: monthSize.height)
|
||||
let monthTextFrame = CGRect(x: sideInset, y: 11.0 + timeHeight, width: monthSize.width, height: monthSize.height)
|
||||
self.monthTextNode.frame = monthTextFrame
|
||||
self.monthArrowNode.frame = CGRect(x: monthTextFrame.maxX + 10.0, y: monthTextFrame.minY + 4.0, width: 7.0, height: 12.0)
|
||||
|
||||
let monthArrowFrame = CGRect(x: monthTextFrame.maxX + 10.0, y: monthTextFrame.minY + 4.0, width: 7.0, height: 12.0)
|
||||
self.monthArrowNode.position = monthArrowFrame.center
|
||||
self.monthArrowNode.bounds = CGRect(origin: CGPoint(), size: monthArrowFrame.size)
|
||||
|
||||
transition.updateTransformRotation(node: self.monthArrowNode, angle: self.state.displayingMonthSelection ? CGFloat.pi / 2.0 : 0.0)
|
||||
|
||||
self.monthButtonNode.frame = monthTextFrame.inset(by: UIEdgeInsets(top: -6.0, left: -6.0, bottom: -6.0, right: -30.0))
|
||||
|
||||
self.previousButtonNode.frame = CGRect(x: size.width - sideInset - 54.0, y: monthTextFrame.minY + 1.0, width: 10.0, height: 17.0)
|
||||
@@ -629,7 +656,7 @@ public final class DatePickerNode: ASDisplayNode {
|
||||
dayNode.attributedText = NSAttributedString(string: shortStringForDayOfWeek(strings: self.strings, day: Int32(i)).uppercased(), font: dayFont, textColor: theme.secondaryTextColor)
|
||||
|
||||
let textSize = dayNode.updateLayout(size)
|
||||
let cellFrame = CGRect(x: daysSideInset + CGFloat(i) * cellSize, y: 40.0, width: cellSize, height: cellSize)
|
||||
let cellFrame = CGRect(x: daysSideInset + CGFloat(i) * cellSize, y: topInset - 38.0, width: cellSize, height: cellSize)
|
||||
let textFrame = CGRect(origin: CGPoint(x: cellFrame.minX + floor((cellFrame.width - textSize.width) / 2.0), y: cellFrame.minY + floor((cellFrame.height - textSize.height) / 2.0)), size: textSize)
|
||||
|
||||
dayNode.frame = textFrame
|
||||
@@ -679,10 +706,10 @@ private final class MonthPickerNode: ASDisplayNode, UIPickerViewDelegate, UIPick
|
||||
private let theme: DatePickerTheme
|
||||
private let strings: PresentationStrings
|
||||
|
||||
private var date: Date
|
||||
private var yearRange: Range<Int> {
|
||||
var date: Date
|
||||
var yearRange: Range<Int> {
|
||||
didSet {
|
||||
self.pickerView.reloadAllComponents()
|
||||
self.reload()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -706,9 +733,16 @@ private final class MonthPickerNode: ASDisplayNode, UIPickerViewDelegate, UIPick
|
||||
self.pickerView.dataSource = self
|
||||
self.view.addSubview(self.pickerView)
|
||||
|
||||
self.reload()
|
||||
}
|
||||
|
||||
private func reload() {
|
||||
self.pickerView.reloadAllComponents()
|
||||
|
||||
// self.pickerView.selectRow(index, inComponent: 0, animated: false)
|
||||
|
||||
let month = calendar.component(.month, from: date)
|
||||
let year = calendar.component(.year, from: date)
|
||||
self.pickerView.selectRow(month - 1, inComponent: 0, animated: false)
|
||||
self.pickerView.selectRow(year - yearRange.startIndex, inComponent: 1, animated: false)
|
||||
}
|
||||
|
||||
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
||||
@@ -742,7 +776,23 @@ private final class MonthPickerNode: ASDisplayNode, UIPickerViewDelegate, UIPick
|
||||
}
|
||||
|
||||
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
|
||||
// self.valueChanged(timeoutValues[row])
|
||||
let month = pickerView.selectedRow(inComponent: 0) + 1
|
||||
let year = self.yearRange.startIndex + pickerView.selectedRow(inComponent: 1)
|
||||
|
||||
var components = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: self.date)
|
||||
let day = components.day ?? 1
|
||||
components.day = 1
|
||||
components.month = month
|
||||
components.year = year
|
||||
|
||||
let tempDate = calendar.date(from: components)!
|
||||
let numberOfDays = calendar.range(of: .day, in: .month, for: tempDate)!.count
|
||||
components.day = min(day, numberOfDays)
|
||||
|
||||
let date = calendar.date(from: components)!
|
||||
self.date = date
|
||||
|
||||
self.valueChanged(date)
|
||||
}
|
||||
|
||||
override func layout() {
|
||||
|
||||
Reference in New Issue
Block a user