Age
This commit is contained in:
parent
39c515d982
commit
703e89d3c4
Binary file not shown.
@ -67,5 +67,53 @@
|
|||||||
landmarkType = "3">
|
landmarkType = "3">
|
||||||
</BreakpointContent>
|
</BreakpointContent>
|
||||||
</BreakpointProxy>
|
</BreakpointProxy>
|
||||||
|
<BreakpointProxy
|
||||||
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
|
<BreakpointContent
|
||||||
|
shouldBeEnabled = "No"
|
||||||
|
ignoreCount = "0"
|
||||||
|
continueAfterRunningActions = "No"
|
||||||
|
filePath = "OTRS-Watch/Extension/Date.swift"
|
||||||
|
timestampString = "504176238.441032"
|
||||||
|
startingColumnNumber = "9223372036854775807"
|
||||||
|
endingColumnNumber = "9223372036854775807"
|
||||||
|
startingLineNumber = "60"
|
||||||
|
endingLineNumber = "60"
|
||||||
|
landmarkName = "Date"
|
||||||
|
landmarkType = "4">
|
||||||
|
</BreakpointContent>
|
||||||
|
</BreakpointProxy>
|
||||||
|
<BreakpointProxy
|
||||||
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
|
<BreakpointContent
|
||||||
|
shouldBeEnabled = "No"
|
||||||
|
ignoreCount = "0"
|
||||||
|
continueAfterRunningActions = "No"
|
||||||
|
filePath = "OTRS-Watch/Extension/Date.swift"
|
||||||
|
timestampString = "504176552.499262"
|
||||||
|
startingColumnNumber = "9223372036854775807"
|
||||||
|
endingColumnNumber = "9223372036854775807"
|
||||||
|
startingLineNumber = "80"
|
||||||
|
endingLineNumber = "80"
|
||||||
|
landmarkName = "Date"
|
||||||
|
landmarkType = "4">
|
||||||
|
</BreakpointContent>
|
||||||
|
</BreakpointProxy>
|
||||||
|
<BreakpointProxy
|
||||||
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
|
<BreakpointContent
|
||||||
|
shouldBeEnabled = "No"
|
||||||
|
ignoreCount = "0"
|
||||||
|
continueAfterRunningActions = "No"
|
||||||
|
filePath = "OTRS-Watch/Extension/Date.swift"
|
||||||
|
timestampString = "504177295.908973"
|
||||||
|
startingColumnNumber = "9223372036854775807"
|
||||||
|
endingColumnNumber = "9223372036854775807"
|
||||||
|
startingLineNumber = "129"
|
||||||
|
endingLineNumber = "129"
|
||||||
|
landmarkName = "stringFromFormat(_:withValue:)"
|
||||||
|
landmarkType = "7">
|
||||||
|
</BreakpointContent>
|
||||||
|
</BreakpointProxy>
|
||||||
</Breakpoints>
|
</Breakpoints>
|
||||||
</Bucket>
|
</Bucket>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="15G1108" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="15G1212" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="macosx"/>
|
<deployment identifier="macosx"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
|
||||||
@ -734,8 +734,8 @@
|
|||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||||
<tableColumns>
|
<tableColumns>
|
||||||
<tableColumn width="116" minWidth="40" maxWidth="1000" id="KZ0-pD-Gxd">
|
<tableColumn width="118" minWidth="40" maxWidth="1000" id="KZ0-pD-Gxd">
|
||||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Erstellt am">
|
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Erstellt">
|
||||||
<font key="font" metaFont="smallSystem"/>
|
<font key="font" metaFont="smallSystem"/>
|
||||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||||
@ -748,11 +748,11 @@
|
|||||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||||
<prototypeCellViews>
|
<prototypeCellViews>
|
||||||
<tableCellView identifier="OTRSTicketCreated" id="2Z7-ua-4Vs">
|
<tableCellView identifier="OTRSTicketCreated" id="2Z7-ua-4Vs">
|
||||||
<rect key="frame" x="1" y="1" width="116" height="17"/>
|
<rect key="frame" x="1" y="1" width="118" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="npm-YV-jB4">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="npm-YV-jB4">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="116" height="17"/>
|
<rect key="frame" x="0.0" y="0.0" width="118" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="Exg-AG-gCr">
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="Exg-AG-gCr">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
@ -781,7 +781,7 @@
|
|||||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||||
<prototypeCellViews>
|
<prototypeCellViews>
|
||||||
<tableCellView identifier="OTRSTicketOwner" id="o7U-fI-1MY">
|
<tableCellView identifier="OTRSTicketOwner" id="o7U-fI-1MY">
|
||||||
<rect key="frame" x="120" y="1" width="64" height="17"/>
|
<rect key="frame" x="122" y="1" width="64" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="HV9-Un-Dyf">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="HV9-Un-Dyf">
|
||||||
@ -814,7 +814,7 @@
|
|||||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||||
<prototypeCellViews>
|
<prototypeCellViews>
|
||||||
<tableCellView identifier="OTRSTicketDetails" id="52t-AD-QAD">
|
<tableCellView identifier="OTRSTicketDetails" id="52t-AD-QAD">
|
||||||
<rect key="frame" x="187" y="1" width="505" height="17"/>
|
<rect key="frame" x="189" y="1" width="505" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3SI-Bc-aJ1">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3SI-Bc-aJ1">
|
||||||
|
|||||||
@ -45,4 +45,36 @@ struct Constants {
|
|||||||
static let SETTINGS = 1
|
static let SETTINGS = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DATE_TIME {
|
||||||
|
struct DE {
|
||||||
|
static let X_YEARS_AGO = "Vor %d Jahren"
|
||||||
|
static let X_MONTH_AGO = "Vor %d Monaten"
|
||||||
|
static let X_WEEKS_AGO = "Vor %d Wochen"
|
||||||
|
static let X_DAYS_AGO = "Vor %d Tagen"
|
||||||
|
static let X_HOURS_AGO = "Vor %d Stunden"
|
||||||
|
static let X_MINUTES_AGO = "Vor %d Minuten"
|
||||||
|
static let X_SECONDS_AGO = "Vor %d Sekunden"
|
||||||
|
|
||||||
|
static let ONE_YEAR_AGO = "Vor 1 Jahr"
|
||||||
|
static let ONE_MONTH_AGO = "Vor 1 Monat"
|
||||||
|
static let ONE_WEEK_AGO = "Vor 1 Woche"
|
||||||
|
static let ONE_DAY_AGO = "Vor 1 Tag"
|
||||||
|
static let ONE_MINUTE_AGO = "Vor einer Minute"
|
||||||
|
|
||||||
|
static let AN_HOUR_AGO = "Vor einer Stunde"
|
||||||
|
static let JUST_NOW = "Gerade eben"
|
||||||
|
static let LAST_YEAR = "Letztes Jahr"
|
||||||
|
static let LAST_MONTH = "Letzten Monat"
|
||||||
|
static let LAST_WEEK = "Letzte Woche"
|
||||||
|
static let YESTERDAY = "Gestern"
|
||||||
|
|
||||||
|
static let THIS_MORNING = "Heute Morgen"
|
||||||
|
static let THIS_AFTERNOON = "Heute Nachmittag"
|
||||||
|
static let THIS_WEEK = "Diese Woche"
|
||||||
|
static let THIS_MONTH = "Diesen Monat"
|
||||||
|
static let THIS_YEAR = "Dieses Jahr"
|
||||||
|
static let TODAY = "Heute"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,10 +8,150 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extension Date {
|
extension Date {
|
||||||
func toString() -> String {
|
func toString() -> String {
|
||||||
let dateFormatter = DateFormatter()
|
let dateFormatter = DateFormatter()
|
||||||
dateFormatter.dateFormat = "dd.MM.yyyy hh:mm"
|
dateFormatter.dateFormat = "dd.MM.yyyy"
|
||||||
return dateFormatter.string(from: self)
|
return dateFormatter.string(from: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// shows 1 or two letter abbreviation for units.
|
||||||
|
// does not include 'ago' text ... just {value}{unit-abbreviation}
|
||||||
|
// does not include interim summary options such as 'Just now'
|
||||||
|
/*public var timeAgoSimple: String {
|
||||||
|
let components = self.dateComponents()
|
||||||
|
|
||||||
|
if components.year! > 0 {
|
||||||
|
return stringFromFormat("%%d%@yr", withValue: components.year!)
|
||||||
|
}
|
||||||
|
|
||||||
|
if components.month! > 0 {
|
||||||
|
return stringFromFormat("%%d%@mo", withValue: components.month!)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: localize for other calanders
|
||||||
|
if components.day! >= 7 {
|
||||||
|
let value = components.day!/7
|
||||||
|
return stringFromFormat("%%d%@w", withValue: value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if components.day! > 0 {
|
||||||
|
return stringFromFormat("%%d%@d", withValue: components.day!)
|
||||||
|
}
|
||||||
|
|
||||||
|
if components.hour! > 0 {
|
||||||
|
return stringFromFormat("%%d%@h", withValue: components.hour!)
|
||||||
|
}
|
||||||
|
|
||||||
|
if components.minute! > 0 {
|
||||||
|
return stringFromFormat("%%d%@m", withValue: components.minute!)
|
||||||
|
}
|
||||||
|
|
||||||
|
if components.second! > 0 {
|
||||||
|
return stringFromFormat("%%d%@s", withValue: components.second! )
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public var timeAgo: String {
|
||||||
|
let components = self.dateComponents()
|
||||||
|
|
||||||
|
if components.year! > 0 {
|
||||||
|
if components.year! < 2 {
|
||||||
|
return Constants.DATE_TIME.DE.LAST_YEAR
|
||||||
|
} else {
|
||||||
|
return stringFromFormat(Constants.DATE_TIME.DE.X_YEARS_AGO, withValue: components.year!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if components.month! > 0 {
|
||||||
|
if components.month! < 2 {
|
||||||
|
return Constants.DATE_TIME.DE.LAST_MONTH
|
||||||
|
} else {
|
||||||
|
return stringFromFormat(Constants.DATE_TIME.DE.X_MONTH_AGO, withValue: components.month!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if components.day! >= 7 {
|
||||||
|
let week = components.day!/7
|
||||||
|
if week < 2 {
|
||||||
|
return Constants.DATE_TIME.DE.LAST_WEEK
|
||||||
|
} else {
|
||||||
|
return stringFromFormat(Constants.DATE_TIME.DE.X_WEEKS_AGO, withValue: week)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if components.day! > 0 {
|
||||||
|
if components.day! < 2 {
|
||||||
|
return Constants.DATE_TIME.DE.YESTERDAY
|
||||||
|
} else {
|
||||||
|
return stringFromFormat(Constants.DATE_TIME.DE.X_DAYS_AGO, withValue: components.day!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if components.hour! > 0 {
|
||||||
|
if components.hour! < 2 {
|
||||||
|
return Constants.DATE_TIME.DE.AN_HOUR_AGO
|
||||||
|
} else {
|
||||||
|
return stringFromFormat(Constants.DATE_TIME.DE.X_HOURS_AGO, withValue: components.hour!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if components.minute! > 0 {
|
||||||
|
if components.minute! < 2 {
|
||||||
|
return Constants.DATE_TIME.DE.ONE_MINUTE_AGO
|
||||||
|
} else {
|
||||||
|
return stringFromFormat(Constants.DATE_TIME.DE.X_MINUTES_AGO, withValue: components.minute!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if components.second! > 0 {
|
||||||
|
if components.second! < 5 {
|
||||||
|
return Constants.DATE_TIME.DE.JUST_NOW
|
||||||
|
} else {
|
||||||
|
return stringFromFormat(Constants.DATE_TIME.DE.X_SECONDS_AGO, withValue: components.second!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func dateComponents() -> DateComponents {
|
||||||
|
let calander = Calendar.current
|
||||||
|
return (calander as NSCalendar).components([.second, .minute, .hour, .day, .month, .year], from: self, to: Date(), options: [])
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func stringFromFormat(_ format: String, withValue value: Int) -> String {
|
||||||
|
let localeFormat = String(format: format, getLocaleFormatUnderscoresWithValue(Double(value)))
|
||||||
|
return String(format: format, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func getLocaleFormatUnderscoresWithValue(_ value: Double) -> String {
|
||||||
|
guard let localeCode = Locale.preferredLanguages.first else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Russian (ru) and Ukrainian (uk)
|
||||||
|
if localeCode.hasPrefix("ru") || localeCode.hasPrefix("uk") {
|
||||||
|
let XY = Int(floor(value)) % 100
|
||||||
|
let Y = Int(floor(value)) % 10
|
||||||
|
|
||||||
|
if Y == 0 || Y > 4 || (XY > 10 && XY < 15) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if Y > 1 && Y < 5 && (XY < 10 || XY > 20) {
|
||||||
|
return "_"
|
||||||
|
}
|
||||||
|
|
||||||
|
if Y == 1 && XY != 11 {
|
||||||
|
return "__"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ extension ViewController: NSTableViewDataSource, NSTableViewDelegate {
|
|||||||
if tableColumn == self.ticketTableView.tableColumns[0] {
|
if tableColumn == self.ticketTableView.tableColumns[0] {
|
||||||
cellIdentifier = CellIdentifiers.OTRSTicketNumber
|
cellIdentifier = CellIdentifiers.OTRSTicketNumber
|
||||||
image = nil
|
image = nil
|
||||||
text = item.created.toString()
|
text = item.created.timeAgo
|
||||||
} else if tableColumn == self.ticketTableView.tableColumns[1] {
|
} else if tableColumn == self.ticketTableView.tableColumns[1] {
|
||||||
cellIdentifier = CellIdentifiers.OTRSTicketDetails
|
cellIdentifier = CellIdentifiers.OTRSTicketDetails
|
||||||
image = nil
|
image = nil
|
||||||
|
|||||||
@ -75,6 +75,13 @@ extension Ticket {
|
|||||||
throw SerializationError.missing("Created")
|
throw SerializationError.missing("Created")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extract created, e.g. 2016-11-24 11:30:11
|
||||||
|
|
||||||
|
guard let createdUnixJSON = source["CreateTimeUnix"] as? String else {
|
||||||
|
throw SerializationError.missing("CreateTimeUnix")
|
||||||
|
}
|
||||||
|
let epochTime: TimeInterval = Double.init(createdUnixJSON)!
|
||||||
|
|
||||||
// extract changed, e.g. 2016-11-24 13:33:01
|
// extract changed, e.g. 2016-11-24 13:33:01
|
||||||
guard let changedJSON = source["Changed"] as? String else {
|
guard let changedJSON = source["Changed"] as? String else {
|
||||||
throw SerializationError.missing("Changed")
|
throw SerializationError.missing("Changed")
|
||||||
@ -91,14 +98,11 @@ extension Ticket {
|
|||||||
self.queue = queue_
|
self.queue = queue_
|
||||||
self.queueID = queueID_
|
self.queueID = queueID_
|
||||||
self.state = state_
|
self.state = state_
|
||||||
if let created:Date = dateFormatter.date(from: createdJSON) {
|
self.created = Date(timeIntervalSince1970: epochTime)
|
||||||
self.created = created
|
|
||||||
} else {
|
|
||||||
self.created = Date.init()
|
|
||||||
}
|
|
||||||
if let changed:Date = dateFormatter.date(from: changedJSON) {
|
if let changed:Date = dateFormatter.date(from: changedJSON) {
|
||||||
self.changed = changed
|
self.changed = changed
|
||||||
} else {
|
} else {
|
||||||
|
print("Error creating date instance from \(createdJSON)")
|
||||||
self.changed = Date.init()
|
self.changed = Date.init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user