diff --git a/Clocker/Clocker/en.lproj/Panel.xib b/Clocker/Clocker/en.lproj/Panel.xib index b9fc6f4..791dfae 100755 --- a/Clocker/Clocker/en.lproj/Panel.xib +++ b/Clocker/Clocker/en.lproj/Panel.xib @@ -49,10 +49,10 @@ - + - + @@ -262,7 +262,7 @@ - + @@ -336,7 +336,7 @@ - + @@ -413,7 +413,7 @@ - + @@ -462,7 +462,7 @@ - + @@ -507,9 +507,9 @@ - + - + diff --git a/Clocker/ClockerUITests/PanelTests.swift b/Clocker/ClockerUITests/PanelTests.swift index 501a586..ad42cbb 100644 --- a/Clocker/ClockerUITests/PanelTests.swift +++ b/Clocker/ClockerUITests/PanelTests.swift @@ -115,4 +115,13 @@ class PanelTests: XCTestCase { XCTAssert(app.popovers.count > 0) } + + // Ensure that once main panel is closed, the time in the menubar doesn't stop and stays up-to-date + func testTimeIsUpToDate() { + // Ensure that we have seconds selected for the timezone format + // Open Panel; before closing panel note the time + // Close Panel; + // Start timer; + // Check time increments or is not equal for all those five seconds? + } } diff --git a/Clocker/Overall App/Themer.swift b/Clocker/Overall App/Themer.swift index 6fa75e4..e141317 100644 --- a/Clocker/Overall App/Themer.swift +++ b/Clocker/Overall App/Themer.swift @@ -187,8 +187,8 @@ extension Themer { return themeIndex == .light - ? NSImage(named: NSImage.Name("Settings"))! - : NSImage(named: NSImage.Name("Settings-White"))! + ? NSImage(named: NSImage.Name("Settings"))! + : NSImage(named: NSImage.Name("Settings-White"))! } func pinImage() -> NSImage { diff --git a/Clocker/Panel/PanelController.swift b/Clocker/Panel/PanelController.swift index 944084f..866d480 100644 --- a/Clocker/Panel/PanelController.swift +++ b/Clocker/Panel/PanelController.swift @@ -95,8 +95,8 @@ class PanelController: ParentPanelController { // Reset future slider value to zero futureSlider.integerValue = 0 sliderDatePicker.dateValue = Date() - modernSliderLabel.stringValue = modernSliderDataSource[modernSliderDataSource.count / 2] - let indexPaths: Set = Set([IndexPath(item: modernSliderDataSource.count / 2, section: 0)]) + closestQuarterTimeRepresentation = setModernLabel() + let indexPaths: Set = Set([IndexPath(item: modernSlider.numberOfItems(inSection: 0) / 2, section: 0)]) modernSlider.scrollToItems(at: indexPaths, scrollPosition: .centeredHorizontally) setTimezoneDatasourceSlider(sliderValue: 0) diff --git a/Clocker/Panel/ParentPanelController+ModernSlider.swift b/Clocker/Panel/ParentPanelController+ModernSlider.swift index 0e5400c..c1fcbbb 100644 --- a/Clocker/Panel/ParentPanelController+ModernSlider.swift +++ b/Clocker/Panel/ParentPanelController+ModernSlider.swift @@ -5,13 +5,12 @@ import Foundation extension ParentPanelController: NSCollectionViewDataSource, NSCollectionViewDelegate { func collectionView(_: NSCollectionView, numberOfItemsInSection _: Int) -> Int { - return modernSliderDataSource.count + return (96 * PanelConstants.modernSliderDaySupport * 2) + 1 } func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { let item = collectionView.makeItem(withIdentifier: HourMarkerViewItem.reuseIdentifier, for: indexPath) as! HourMarkerViewItem - let dataSoureValue = modernSliderDataSource[indexPath.item] - item.setup(with: indexPath.item, value: dataSoureValue) + item.setup(with: indexPath.item) return item } } @@ -22,10 +21,56 @@ extension ParentPanelController { let changedOrigin = contentView.documentVisibleRect.origin let newPoint = NSPoint(x: changedOrigin.x + contentView.frame.width / 2, y: changedOrigin.y) let indexPath = modernSlider.indexPathForItem(at: newPoint) - if let correctIndexPath = indexPath?.item { - modernSliderLabel.stringValue = modernSliderDataSource[correctIndexPath] -// setTimezoneDatasourceSlider(sliderValue: item.indexTag * 15) -// mainTableView.reloadData() + if let correctIndexPath = indexPath?.item, currentCenterIndexPath != correctIndexPath { + currentCenterIndexPath = correctIndexPath + let minutesToAdd = setDefaultDateLabel(correctIndexPath) + setTimezoneDatasourceSlider(sliderValue: minutesToAdd) + mainTableView.reloadData() + } + } + + @objc func scrollViewWillStartLiveScroll(_: NSNotification) { + modernSliderIsScrolling = true + } + + @objc func scrollViewDidEndLiveScroll(_: NSNotification) { + modernSliderIsScrolling = false + } + + @discardableResult + public func setModernLabel(_ shouldUpdate: Bool = false) -> Date { + let defaultParameters = minuteFromCalendar() + let hourQuarterDate = Calendar.current.nextDate(after: defaultParameters.0, + matching: DateComponents(minute: defaultParameters.1), + matchingPolicy: .strict, + repeatedTimePolicy: .first, + direction: .forward)! + + if shouldUpdate { + modernSliderLabel.stringValue = timezoneFormattedStringRepresentation(hourQuarterDate) + } else { + modernSliderLabel.stringValue = CLEmptyString + } + + return hourQuarterDate + } + + public func setDefaultDateLabel(_ index: Int) -> Int { + let totalCount = (96 * PanelConstants.modernSliderDaySupport * 2) + 1 + let centerPoint = Int(ceil(Double(totalCount / 2))) + if index > (centerPoint + 1) { + let remainder = (index % (centerPoint + 1)) + let nextDate = Calendar.current.date(byAdding: .minute, value: remainder * 15, to: closestQuarterTimeRepresentation ?? Date())! + modernSliderLabel.stringValue = timezoneFormattedStringRepresentation(nextDate) + return nextDate.minutes(from: Date()) + 1 + } else if index <= centerPoint { + let remainder = centerPoint - index + 1 + let previousDate = Calendar.current.date(byAdding: .minute, value: -1 * remainder * 15, to: closestQuarterTimeRepresentation ?? Date())! + modernSliderLabel.stringValue = timezoneFormattedStringRepresentation(previousDate) + return previousDate.minutes(from: Date()) + } else { + setModernLabel(true) + return 0 } } @@ -45,31 +90,6 @@ extension ParentPanelController { return (currentDate, minute) } - public func forward15Minutes() -> [String] { - let defaultParameters = minuteFromCalendar() - var hourQuarterDate = Calendar.current.nextDate(after: defaultParameters.0, matching: DateComponents(minute: defaultParameters.1), matchingPolicy: .strict, repeatedTimePolicy: .first, direction: .forward)! - - var hourQuarters = [String]() - hourQuarters.append(timezoneFormattedStringRepresentation(hourQuarterDate)) - for _ in 1 ... 288 { - hourQuarterDate = Calendar.current.date(byAdding: .minute, value: 15, to: hourQuarterDate)! - hourQuarters.append(timezoneFormattedStringRepresentation(hourQuarterDate)) - } - return hourQuarters - } - - public func backward15Minutes() -> [String] { - let defaultParameters = minuteFromCalendar() - var hourQuarterDate = Calendar.current.nextDate(after: defaultParameters.0, matching: DateComponents(minute: defaultParameters.1), matchingPolicy: .strict, repeatedTimePolicy: .first, direction: .backward)! - var hourQuarters = [String]() - for _ in 1 ... 288 { - hourQuarterDate = Calendar.current.date(byAdding: .minute, value: -15, to: hourQuarterDate)! - hourQuarters.append(timezoneFormattedStringRepresentation(hourQuarterDate)) - } - - return hourQuarters - } - private func timezoneFormattedStringRepresentation(_ date: Date) -> String { let dateFormatter = DateFormatterManager.dateFormatterWithFormat(with: .none, format: "MMM d HH:mm", diff --git a/Clocker/Panel/ParentPanelController.swift b/Clocker/Panel/ParentPanelController.swift index 19a1c2f..72accbc 100644 --- a/Clocker/Panel/ParentPanelController.swift +++ b/Clocker/Panel/ParentPanelController.swift @@ -11,6 +11,7 @@ struct PanelConstants { static let noThanksTitle = "No, thanks" static let yesWithQuestionMark = "Yes?" static let yesWithExclamation = "Yes!" + static let modernSliderDaySupport = 7 } class ParentPanelController: NSWindowController { @@ -86,7 +87,9 @@ class ParentPanelController: NSWindowController { @IBOutlet var roundedDateView: NSView! // Modern Slider - public var modernSliderDataSource: [String] = [] + public var currentCenterIndexPath: Int = -1 + public var closestQuarterTimeRepresentation: Date? + public var modernSliderIsScrolling: Bool = false @IBOutlet var modernSlider: NSCollectionView! @IBOutlet var modernSliderLabel: NSTextField! @IBOutlet var modernContainerView: NSView! @@ -198,20 +201,23 @@ class ParentPanelController: NSWindowController { } if modernSlider != nil { - var backwards = backward15Minutes() - backwards.reverse() - let forwards = forward15Minutes() - modernSliderDataSource = backwards + forwards - modernSlider.enclosingScrollView?.scrollerInsets = NSEdgeInsets(top: 0, left: 0, bottom: 100, right: 0) modernSlider.delegate = self modernSlider.postsBoundsChangedNotifications = true + NotificationCenter.default.addObserver(self, + selector: #selector(scrollViewWillStartLiveScroll(_:)), + name: NSScrollView.willStartLiveScrollNotification, + object: modernSlider.enclosingScrollView) + NotificationCenter.default.addObserver(self, + selector: #selector(scrollViewDidEndLiveScroll(_:)), + name: NSScrollView.didEndLiveScrollNotification, + object: modernSlider.enclosingScrollView) NotificationCenter.default.addObserver(self, selector: #selector(collectionViewDidScroll(_:)), name: NSView.boundsDidChangeNotification, object: modernSlider.superview) - modernSliderLabel.stringValue = modernSliderDataSource[modernSliderDataSource.count / 2] - let indexPaths: Set = Set([IndexPath(item: modernSliderDataSource.count / 2, section: 0)]) + closestQuarterTimeRepresentation = setModernLabel() + let indexPaths: Set = Set([IndexPath(item: modernSlider.numberOfItems(inSection: 0) / 2, section: 0)]) modernSlider.scrollToItems(at: indexPaths, scrollPosition: .centeredHorizontally) } @@ -595,7 +601,7 @@ class ParentPanelController: NSWindowController { if let futureSliderCell = futureSlider.cell as? CustomSliderCell, futureSliderCell.tracking == true { return } - if modernSlider.isHidden == false { + if modernSlider.isHidden == false, modernSliderIsScrolling { return } let dataOperation = TimezoneDataOperations(with: model) @@ -615,6 +621,7 @@ class ParentPanelController: NSWindowController { } cellView.layout(with: model) updateDatePicker() + setModernLabel() } } } diff --git a/Clocker/Panel/UI/HourMarkerViewItem.swift b/Clocker/Panel/UI/HourMarkerViewItem.swift index 931a17d..a3fd643 100644 --- a/Clocker/Panel/UI/HourMarkerViewItem.swift +++ b/Clocker/Panel/UI/HourMarkerViewItem.swift @@ -4,11 +4,8 @@ import Cocoa class HourMarkerViewItem: NSCollectionViewItem { static let reuseIdentifier = NSUserInterfaceItemIdentifier("HourMarkerViewItem") - public var timeRepresentation: String = "-1" - - func setup(with index: Int, value: String) { - timeRepresentation = value + func setup(with index: Int) { for constraint in view.constraints where constraint.identifier == "constrainFromTop" { if index % 4 == 0 { constraint.constant = 0 diff --git a/Clocker/Preferences/General/SearchDataSource.swift b/Clocker/Preferences/General/SearchDataSource.swift index 5885f19..256c94b 100644 --- a/Clocker/Preferences/General/SearchDataSource.swift +++ b/Clocker/Preferences/General/SearchDataSource.swift @@ -66,6 +66,9 @@ class SearchDataSource: NSObject { let datasource = searchField.stringValue.isEmpty ? timezoneArray : timezoneFilteredArray return datasource[row % datasource.count] case .city: + if filteredArray.count == 0 { + return nil + } let timezoneData = filteredArray[row % filteredArray.count] return timezoneData }