functioning watch app

This commit is contained in:
Ryan Nystrom
2018-04-29 17:46:00 -04:00
parent b1c881cddb
commit b02c7cf0ad
140 changed files with 7380 additions and 3471 deletions

View File

@@ -10,6 +10,7 @@ import UIKit
import SnapKit
import IGListKit
import SDWebImage
import DateAgo
protocol IssueCommentDetailCellDelegate: class {
func didTapMore(cell: IssueCommentDetailCell, sender: UIView)
@@ -135,7 +136,7 @@ final class IssueCommentDetailCell: IssueCommentBaseCell, ListBindable {
editedLabel.text = "\(Constants.Strings.bullet) \(String(format: format, editedLogin))"
let detailFormat = NSLocalizedString("%@ edited this issue %@", comment: "")
editedLabel.detailText = String(format: detailFormat, arguments: [editedLogin, editedDate.agoString])
editedLabel.detailText = String(format: detailFormat, arguments: [editedLogin, editedDate.agoString(.long)])
} else {
editedLabel.isHidden = true
}

View File

@@ -8,6 +8,7 @@
import Foundation
import StyledText
import StringHelpers
extension NSRange {
var right: Int {

View File

@@ -7,6 +7,7 @@
//
import Foundation
import StringHelpers
private let regex: NSRegularExpression = {
let pattern = "(" + GithubEmojis.alias.map({ $0.key }).joined(separator: "|") + ")"

View File

@@ -7,6 +7,7 @@
//
import Foundation
import StringHelpers
private let regex = try! NSRegularExpression(pattern: "https?:\\/\\/.*github.com\\/(\\w*)\\/([^/]*?)\\/issues\\/([0-9]+)", options: [])
extension String {

View File

@@ -7,6 +7,7 @@
//
import Foundation
import StringHelpers
private let regex = try! NSRegularExpression(pattern: "<!--((.|\n|\r)*?)-->", options: [])
extension String {

View File

@@ -8,6 +8,7 @@
import UIKit
import StyledText
import StringHelpers
extension StyledTextBuilder {
func addCheckbox(checked: Bool, range: NSRange, viewerCanUpdate: Bool) {

View File

@@ -9,6 +9,7 @@
import Foundation
import IGListKit
import StyledText
import DateAgo
final class IssueLabeledModel: ListDiffable {
@@ -71,7 +72,7 @@ final class IssueLabeledModel: ListDiffable {
]
)))
.restore()
.add(text: " \(date.agoString)", attributes: [MarkdownAttribute.details: DateDetailsFormatter().string(from: date)])
.add(text: " \(date.agoString(.long))", attributes: [MarkdownAttribute.details: DateDetailsFormatter().string(from: date)])
self.string = StyledTextRenderer(
string: builder.build(),

View File

@@ -9,6 +9,7 @@
import Foundation
import IGListKit
import StyledText
import DateAgo
final class IssueMilestoneEventModel: ListDiffable {
@@ -62,7 +63,7 @@ final class IssueMilestoneEventModel: ListDiffable {
style: Styles.Text.secondaryBold.with(foreground: Styles.Colors.Gray.dark.color)
))
.restore()
.add(text: " \(date.agoString)", attributes: [MarkdownAttribute.details: DateDetailsFormatter().string(from: date)])
.add(text: " \(date.agoString(.long))", attributes: [MarkdownAttribute.details: DateDetailsFormatter().string(from: date)])
self.string = StyledTextRenderer(
string: builder.build(),

View File

@@ -9,6 +9,7 @@
import Foundation
import IGListKit
import StyledText
import DateAgo
final class IssueReferencedModel: ListDiffable {
@@ -64,7 +65,7 @@ final class IssueReferencedModel: ListDiffable {
.restore()
.add(text: NSLocalizedString(" referenced ", comment: ""))
.save()
.add(text: date.agoString, attributes: [MarkdownAttribute.details: DateDetailsFormatter().string(from: date)])
.add(text: date.agoString(.long), attributes: [MarkdownAttribute.details: DateDetailsFormatter().string(from: date)])
.restore()
.add(text: "\n")
.save()

View File

@@ -9,6 +9,8 @@
import Foundation
import IGListKit
import StyledText
import DateAgo
import StringHelpers
final class IssueReferencedCommitModel: ListDiffable {
@@ -57,7 +59,7 @@ final class IssueReferencedCommitModel: ListDiffable {
])
))
.restore()
.add(text: " \(date.agoString)", attributes: [MarkdownAttribute.details: DateDetailsFormatter().string(from: date)])
.add(text: " \(date.agoString(.long))", attributes: [MarkdownAttribute.details: DateDetailsFormatter().string(from: date)])
self.string = StyledTextRenderer(
string: builder.build(),

View File

@@ -9,6 +9,7 @@
import UIKit
import IGListKit
import StyledText
import DateAgo
final class IssueRequestModel: ListDiffable {
@@ -63,7 +64,7 @@ final class IssueRequestModel: ListDiffable {
.save()
.add(styledText: StyledText(text: " \(user)", style: Styles.Text.secondaryBold))
.restore()
.add(text: " \(date.agoString)", attributes: [MarkdownAttribute.details: DateDetailsFormatter().string(from: date)])
.add(text: " \(date.agoString(.long))", attributes: [MarkdownAttribute.details: DateDetailsFormatter().string(from: date)])
self.string = StyledTextRenderer(
string: builder.build(),

View File

@@ -8,6 +8,7 @@
import UIKit
import SnapKit
import StringHelpers
protocol IssueStatusEventCellDelegate: class {
func didTapActor(cell: IssueStatusEventCell)

View File

@@ -10,26 +10,6 @@ import UIKit
import GitHubAPI
extension String {
var notificationIdentifier: NotificationViewModel.Identifier? {
let split = components(separatedBy: "/")
guard split.count > 2,
let identifier = split.last
else { return nil }
let type = split[split.count - 2]
switch type {
case "commits":
return .hash(identifier)
case "releases":
return .release(identifier)
default:
return .number((identifier as NSString).integerValue)
}
}
}
func CreateViewModels(
containerWidth: CGFloat,
v3notifications: [V3Notification]) -> [NotificationViewModel] {
@@ -37,9 +17,16 @@ func CreateViewModels(
for notification in v3notifications {
guard let type = NotificationType(rawValue: notification.subject.type.rawValue),
let identifier = notification.subject.url?.absoluteString.notificationIdentifier
let identifier = notification.subject.identifier
else { continue }
let modelIdentifier: NotificationViewModel.Identifier
switch identifier {
case .hash(let h): modelIdentifier = .hash(h)
case .number(let n): modelIdentifier = .number(n)
case .release(let r): modelIdentifier = .release(r)
}
let model = NotificationViewModel(
id: notification.id,
title: notification.subject.title,
@@ -48,7 +35,7 @@ func CreateViewModels(
read: !notification.unread,
owner: notification.repository.owner.login,
repo: notification.repository.name,
identifier: identifier,
identifier: modelIdentifier,
containerWidth: containerWidth
)
viewModels.append(model)

View File

@@ -9,6 +9,7 @@
import Foundation
import IGListKit
import FlatCache
import DateAgo
final class NotificationViewModel: ListDiffable, Cachable {
@@ -62,7 +63,7 @@ final class NotificationViewModel: ListDiffable, Cachable {
self.identifier = identifier
self.state = state
self.commentCount = commentCount
self.agoString = date.agoString
self.agoString = date.agoString(.long)
}
convenience init(

View File

@@ -9,6 +9,7 @@
import UIKit
import SnapKit
import StyledText
import DateAgo
final class RepositorySummaryCell: SelectableCell {
@@ -96,7 +97,7 @@ final class RepositorySummaryCell: SelectableCell {
titleView.configure(renderer: model.title, width: contentView.bounds.width)
let format = NSLocalizedString("#%d opened %@ by %@", comment: "")
secondaryLabel.text = String(format: format, arguments: [model.number, model.created.agoString, model.author])
secondaryLabel.text = String(format: format, arguments: [model.number, model.created.agoString(.long), model.author])
let imageName: String
let tint: UIColor

View File

@@ -10,36 +10,19 @@ import Foundation
import Alamofire
import Apollo
import GitHubSession
import GitHubAPI
func newGithubClient(
userSession: GitHubUserSession? = nil
) -> GithubClient {
var additionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
// for apollo + github gql endpoint
// http://dev.apollodata.com/ios/initialization.html
if let token = userSession?.token, let authMethod = userSession?.authMethod {
let header = authMethod == .oauth ? "Bearer \(token)" : "token \(token)"
additionalHeaders["Authorization"] = header
}
let config = URLSessionConfiguration.default
config.httpAdditionalHeaders = additionalHeaders
config.timeoutIntervalForRequest = 15
// disable URL caching for the v3 API
config.requestCachePolicy = .reloadIgnoringLocalCacheData
config.urlCache = nil
let networker = Alamofire.SessionManager(configuration: config)
let gqlURL = URL(string: "https://api.github.com/graphql")!
let transport = HTTPNetworkTransport(url: gqlURL, configuration: config)
let apollo = ApolloClient(networkTransport: transport)
let networkingConfigs = userSession?.networkingConfigs
let config = ConfiguredNetworkers(
token: networkingConfigs?.token,
useOauth: networkingConfigs?.useOauth
)
return GithubClient(
apollo: apollo,
networker: networker,
apollo: config.apollo,
networker: config.alamofire,
userSession: userSession
)
}

View File

@@ -21,7 +21,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
private var showingLogin = false
private let flexController = FlexController()
private let sessionManager = GitHubSessionManager()
private var badgeNotifications: BadgeNotifications? = nil
private var badgeNotifications: BadgeNotifications?
private var watchAppSync: WatchAppUserSessionSync?
private lazy var rootNavigationManager: RootNavigationManager = {
return RootNavigationManager(
@@ -34,6 +35,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
sessionManager.addListener(listener: self)
let focusedSession = sessionManager.focusedUserSession
watchAppSync = WatchAppUserSessionSync(userSession: focusedSession)
watchAppSync?.start()
// initialize a webview at the start so webview startup later on isn't so slow
_ = UIWebView()
@@ -52,7 +57,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// setup root VCs
window?.backgroundColor = Styles.Colors.background
rootNavigationManager.resetRootViewController(userSession: sessionManager.focusedUserSession)
rootNavigationManager.resetRootViewController(userSession: focusedSession)
// use Alamofire status bar network activity helper
NetworkActivityIndicatorManager.shared.isEnabled = true
@@ -108,6 +113,7 @@ extension AppDelegate: GitHubSessionListener {
// configure 3d touch shortcut handling
func didFocus(manager: GitHubSessionManager, userSession: GitHubUserSession, dismiss: Bool) {
ShortcutHandler.configure(application: UIApplication.shared, sessionManager: sessionManager)
watchAppSync?.sync(userSession: userSession)
}
func didReceiveRedirect(manager: GitHubSessionManager, code: String) {}

View File

@@ -7,11 +7,12 @@
//
import UIKit
import DateAgo
extension ShowMoreDetailsLabel {
func setText(date: Date) {
text = date.agoString
text = date.agoString(.long)
detailText = DateDetailsFormatter().string(from: date)
}

View File

@@ -115,7 +115,6 @@
293189281F5391F700EF0911 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 293189271F5391F700EF0911 /* Result.swift */; };
2931892B1F5397E400EF0911 /* IssueMilestoneCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2931892A1F5397E400EF0911 /* IssueMilestoneCell.swift */; };
2931892F1F539C0E00EF0911 /* IssueMilestoneSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2931892E1F539C0E00EF0911 /* IssueMilestoneSectionController.swift */; };
2931EA471EF7734B00AEE0FF /* String+NSRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2931EA461EF7734B00AEE0FF /* String+NSRange.swift */; };
29351E9C2079106300FF8C17 /* String+GitHubEmoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29351E9B2079106300FF8C17 /* String+GitHubEmoji.swift */; };
29351E9E207917ED00FF8C17 /* IssueCommentTableModel+Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29351E9D207917ED00FF8C17 /* IssueCommentTableModel+Models.swift */; };
29351EA02079246400FF8C17 /* CodeBlockModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29351E9F2079246400FF8C17 /* CodeBlockModel.swift */; };
@@ -124,7 +123,6 @@
29351EA62079791800FF8C17 /* String+StripHTMLComments.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29351EA52079791800FF8C17 /* String+StripHTMLComments.swift */; };
293971891F904C82002FAC4B /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 293971881F904C82002FAC4B /* Toast.swift */; };
2939718B1F904D2A002FAC4B /* Toast+GitHawk.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2939718A1F904D2A002FAC4B /* Toast+GitHawk.swift */; };
293A45751F296B7E00DD1006 /* DateDisplayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 297AE84C1EC0D58A00B44A1F /* DateDisplayTests.swift */; };
293A45761F296B7E00DD1006 /* IssueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A476B11ED24D99005D0953 /* IssueTests.swift */; };
293A45771F296B7E00DD1006 /* ListKitTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29C2950D1EC7B43B00D46CD2 /* ListKitTestCase.swift */; };
293A45781F296B7E00DD1006 /* ListTestKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29C295091EC7AFA500D46CD2 /* ListTestKit.swift */; };
@@ -138,6 +136,10 @@
294002411FDD9E8400950167 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 294002401FDD9E8400950167 /* GoogleService-Info.plist */; };
29416BF91F1138B700D03E1A /* OauthLogin.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 29416BF81F1138B700D03E1A /* OauthLogin.storyboard */; };
29416BFB1F113D0A00D03E1A /* LoginSplashViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29416BFA1F113D0A00D03E1A /* LoginSplashViewController.swift */; };
2941E4D3209411D60046932D /* ExtensionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2941E4D2209411D60046932D /* ExtensionDelegate.swift */; };
2941E4D5209412700046932D /* RepoInboxController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2941E4D4209412700046932D /* RepoInboxController.swift */; };
2941E4D7209415340046932D /* InboxRowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2941E4D6209415340046932D /* InboxRowController.swift */; };
2941E4D9209416510046932D /* RepoInboxRowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2941E4D8209416510046932D /* RepoInboxRowController.swift */; };
294434E11FB1F2DA00050C06 /* BookmarkNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294434E01FB1F2DA00050C06 /* BookmarkNavigationController.swift */; };
294563E61EE4EE6F00DBCD35 /* IssueStatusModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294563E51EE4EE6F00DBCD35 /* IssueStatusModel.swift */; };
294563E81EE4EED200DBCD35 /* IssueStatusSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294563E71EE4EED200DBCD35 /* IssueStatusSectionController.swift */; };
@@ -148,6 +150,14 @@
29459A6F1FE61E0500034A04 /* MarkdownCheckboxModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29459A6E1FE61E0500034A04 /* MarkdownCheckboxModel.swift */; };
29459A711FE7153500034A04 /* LogEnvironmentInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29459A701FE7153500034A04 /* LogEnvironmentInformation.swift */; };
2946FA5120367FC100C37435 /* GithubClient+Merge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2946FA5020367FC100C37435 /* GithubClient+Merge.swift */; };
2949276020941857008B34EE /* EmptyRowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2949275F20941857008B34EE /* EmptyRowController.swift */; };
2949276220941865008B34EE /* SignInRowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2949276120941865008B34EE /* SignInRowController.swift */; };
2949276420941870008B34EE /* ReadAllRowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2949276320941870008B34EE /* ReadAllRowController.swift */; };
2949276A2094BB3B008B34EE /* ErrorRowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294927692094BB3B008B34EE /* ErrorRowController.swift */; };
2949276C2094BB82008B34EE /* NSObject+RowControllerIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2949276B2094BB82008B34EE /* NSObject+RowControllerIdentifier.swift */; };
2949276E2094BCA8008B34EE /* LoadingRowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2949276D2094BCA8008B34EE /* LoadingRowController.swift */; };
294927702094C088008B34EE /* V3Repository+HashableEquatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2949276F2094C088008B34EE /* V3Repository+HashableEquatable.swift */; };
294927C720966C98008B34EE /* InboxDataController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294927C620966C98008B34EE /* InboxDataController.swift */; };
2949674C1EF9716400B1CF1A /* IssueCommentHrModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2949674B1EF9716400B1CF1A /* IssueCommentHrModel.swift */; };
2949674E1EF9719300B1CF1A /* IssueCommentHrCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2949674D1EF9719300B1CF1A /* IssueCommentHrCell.swift */; };
294967511EFC1E9E00B1CF1A /* IssueCommentHtmlModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294967501EFC1E9E00B1CF1A /* IssueCommentHtmlModel.swift */; };
@@ -162,9 +172,7 @@
294EE4BD209006C0002C9CB1 /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 294EE4BB209006C0002C9CB1 /* Interface.storyboard */; };
294EE4BF209006C2002C9CB1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 294EE4BE209006C2002C9CB1 /* Assets.xcassets */; };
294EE4C6209006C2002C9CB1 /* FreetimeWatch Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 294EE4C5209006C2002C9CB1 /* FreetimeWatch Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
294EE4CB209006C2002C9CB1 /* InterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294EE4CA209006C2002C9CB1 /* InterfaceController.swift */; };
294EE4CD209006C2002C9CB1 /* ExtensionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294EE4CC209006C2002C9CB1 /* ExtensionDelegate.swift */; };
294EE4CF209006C2002C9CB1 /* ComplicationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294EE4CE209006C2002C9CB1 /* ComplicationController.swift */; };
294EE4CB209006C2002C9CB1 /* InboxController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294EE4CA209006C2002C9CB1 /* InboxController.swift */; };
294EE4D1209006C3002C9CB1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 294EE4D0209006C3002C9CB1 /* Assets.xcassets */; };
294EE4D5209006C3002C9CB1 /* FreetimeWatch.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 294EE4B9209006BF002C9CB1 /* FreetimeWatch.app */; };
2950AB1B2082E47200C6F19A /* AppSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2950AB1A2082E47200C6F19A /* AppSplitViewController.swift */; };
@@ -276,9 +284,7 @@
29A08FBD1F12EF7C00C5368E /* IssueReferencedCommitCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A08FBA1F12EF7C00C5368E /* IssueReferencedCommitCell.swift */; };
29A08FBE1F12EF7C00C5368E /* IssueReferencedCommitModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A08FBB1F12EF7C00C5368E /* IssueReferencedCommitModel.swift */; };
29A08FBF1F12EF7C00C5368E /* IssueReferencedCommitSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A08FBC1F12EF7C00C5368E /* IssueReferencedCommitSectionController.swift */; };
29A08FC11F12F08100C5368E /* String+HashDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A08FC01F12F08100C5368E /* String+HashDisplay.swift */; };
29A195021EC66B8B00C3E289 /* UIColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A195011EC66B8B00C3E289 /* UIColor+Hex.swift */; };
29A195041EC74C4800C3E289 /* Date+Display.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A195031EC74C4800C3E289 /* Date+Display.swift */; };
29A195071EC7601000C3E289 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 29A195061EC7601000C3E289 /* Localizable.stringsdict */; };
29A195081EC7602500C3E289 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 29A195061EC7601000C3E289 /* Localizable.stringsdict */; };
29A1950A1EC78B4800C3E289 /* NotificationType+Icon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A195091EC78B4800C3E289 /* NotificationType+Icon.swift */; };
@@ -603,7 +609,6 @@
293189271F5391F700EF0911 /* Result.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = "<group>"; };
2931892A1F5397E400EF0911 /* IssueMilestoneCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueMilestoneCell.swift; sourceTree = "<group>"; };
2931892E1F539C0E00EF0911 /* IssueMilestoneSectionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueMilestoneSectionController.swift; sourceTree = "<group>"; };
2931EA461EF7734B00AEE0FF /* String+NSRange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+NSRange.swift"; sourceTree = "<group>"; };
29351E9B2079106300FF8C17 /* String+GitHubEmoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+GitHubEmoji.swift"; sourceTree = "<group>"; };
29351E9D207917ED00FF8C17 /* IssueCommentTableModel+Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "IssueCommentTableModel+Models.swift"; sourceTree = "<group>"; };
29351E9F2079246400FF8C17 /* CodeBlockModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeBlockModel.swift; sourceTree = "<group>"; };
@@ -620,6 +625,10 @@
294002401FDD9E8400950167 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
29416BF81F1138B700D03E1A /* OauthLogin.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = OauthLogin.storyboard; sourceTree = "<group>"; };
29416BFA1F113D0A00D03E1A /* LoginSplashViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginSplashViewController.swift; sourceTree = "<group>"; };
2941E4D2209411D60046932D /* ExtensionDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionDelegate.swift; sourceTree = "<group>"; };
2941E4D4209412700046932D /* RepoInboxController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepoInboxController.swift; sourceTree = "<group>"; };
2941E4D6209415340046932D /* InboxRowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InboxRowController.swift; sourceTree = "<group>"; };
2941E4D8209416510046932D /* RepoInboxRowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepoInboxRowController.swift; sourceTree = "<group>"; };
294434E01FB1F2DA00050C06 /* BookmarkNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkNavigationController.swift; sourceTree = "<group>"; };
294563E51EE4EE6F00DBCD35 /* IssueStatusModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueStatusModel.swift; sourceTree = "<group>"; };
294563E71EE4EED200DBCD35 /* IssueStatusSectionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueStatusSectionController.swift; sourceTree = "<group>"; };
@@ -630,6 +639,16 @@
29459A6E1FE61E0500034A04 /* MarkdownCheckboxModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkdownCheckboxModel.swift; sourceTree = "<group>"; };
29459A701FE7153500034A04 /* LogEnvironmentInformation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogEnvironmentInformation.swift; sourceTree = "<group>"; };
2946FA5020367FC100C37435 /* GithubClient+Merge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GithubClient+Merge.swift"; sourceTree = "<group>"; };
2949275F20941857008B34EE /* EmptyRowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyRowController.swift; sourceTree = "<group>"; };
2949276120941865008B34EE /* SignInRowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInRowController.swift; sourceTree = "<group>"; };
2949276320941870008B34EE /* ReadAllRowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadAllRowController.swift; sourceTree = "<group>"; };
294927692094BB3B008B34EE /* ErrorRowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorRowController.swift; sourceTree = "<group>"; };
2949276B2094BB82008B34EE /* NSObject+RowControllerIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSObject+RowControllerIdentifier.swift"; sourceTree = "<group>"; };
2949276D2094BCA8008B34EE /* LoadingRowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingRowController.swift; sourceTree = "<group>"; };
2949276F2094C088008B34EE /* V3Repository+HashableEquatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "V3Repository+HashableEquatable.swift"; sourceTree = "<group>"; };
294927712094C5D3008B34EE /* FreetimeWatch.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FreetimeWatch.entitlements; sourceTree = "<group>"; };
294927722094C5DF008B34EE /* FreetimeWatch Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "FreetimeWatch Extension.entitlements"; sourceTree = "<group>"; };
294927C620966C98008B34EE /* InboxDataController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InboxDataController.swift; sourceTree = "<group>"; };
2949674B1EF9716400B1CF1A /* IssueCommentHrModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssueCommentHrModel.swift; sourceTree = "<group>"; };
2949674D1EF9719300B1CF1A /* IssueCommentHrCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssueCommentHrCell.swift; sourceTree = "<group>"; };
294967501EFC1E9E00B1CF1A /* IssueCommentHtmlModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IssueCommentHtmlModel.swift; sourceTree = "<group>"; };
@@ -646,9 +665,7 @@
294EE4BE209006C2002C9CB1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
294EE4C0209006C2002C9CB1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
294EE4C5209006C2002C9CB1 /* FreetimeWatch Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "FreetimeWatch Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
294EE4CA209006C2002C9CB1 /* InterfaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceController.swift; sourceTree = "<group>"; };
294EE4CC209006C2002C9CB1 /* ExtensionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionDelegate.swift; sourceTree = "<group>"; };
294EE4CE209006C2002C9CB1 /* ComplicationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplicationController.swift; sourceTree = "<group>"; };
294EE4CA209006C2002C9CB1 /* InboxController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InboxController.swift; sourceTree = "<group>"; };
294EE4D0209006C3002C9CB1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
294EE4D2209006C3002C9CB1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
2950AB1A2082E47200C6F19A /* AppSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSplitViewController.swift; sourceTree = "<group>"; };
@@ -705,7 +722,6 @@
297A6CE52027880C0027E03B /* MessageView+Styles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageView+Styles.swift"; sourceTree = "<group>"; };
297AE8341EC0D58A00B44A1F /* Freetime.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Freetime.app; sourceTree = BUILT_PRODUCTS_DIR; };
297AE8481EC0D58A00B44A1F /* FreetimeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FreetimeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
297AE84C1EC0D58A00B44A1F /* DateDisplayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateDisplayTests.swift; sourceTree = "<group>"; };
297AE84E1EC0D58A00B44A1F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
297AE8671EC0D5C200B44A1F /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
297AE8691EC0D5C200B44A1F /* UIViewController+Alerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Alerts.swift"; sourceTree = "<group>"; };
@@ -769,9 +785,7 @@
29A08FBA1F12EF7C00C5368E /* IssueReferencedCommitCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueReferencedCommitCell.swift; sourceTree = "<group>"; };
29A08FBB1F12EF7C00C5368E /* IssueReferencedCommitModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueReferencedCommitModel.swift; sourceTree = "<group>"; };
29A08FBC1F12EF7C00C5368E /* IssueReferencedCommitSectionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IssueReferencedCommitSectionController.swift; sourceTree = "<group>"; };
29A08FC01F12F08100C5368E /* String+HashDisplay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+HashDisplay.swift"; sourceTree = "<group>"; };
29A195011EC66B8B00C3E289 /* UIColor+Hex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Hex.swift"; sourceTree = "<group>"; };
29A195031EC74C4800C3E289 /* Date+Display.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+Display.swift"; sourceTree = "<group>"; };
29A195061EC7601000C3E289 /* Localizable.stringsdict */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.stringsdict; path = Localizable.stringsdict; sourceTree = "<group>"; };
29A195091EC78B4800C3E289 /* NotificationType+Icon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NotificationType+Icon.swift"; sourceTree = "<group>"; };
29A1950B1EC7901400C3E289 /* NotificationType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationType.swift; sourceTree = "<group>"; };
@@ -1318,9 +1332,10 @@
294EE4BA209006C0002C9CB1 /* FreetimeWatch */ = {
isa = PBXGroup;
children = (
294EE4BB209006C0002C9CB1 /* Interface.storyboard */,
294EE4BE209006C2002C9CB1 /* Assets.xcassets */,
294927712094C5D3008B34EE /* FreetimeWatch.entitlements */,
294EE4C0209006C2002C9CB1 /* Info.plist */,
294EE4BB209006C0002C9CB1 /* Interface.storyboard */,
);
path = FreetimeWatch;
sourceTree = "<group>";
@@ -1328,11 +1343,22 @@
294EE4C9209006C2002C9CB1 /* FreetimeWatch Extension */ = {
isa = PBXGroup;
children = (
294EE4CA209006C2002C9CB1 /* InterfaceController.swift */,
294EE4CC209006C2002C9CB1 /* ExtensionDelegate.swift */,
294EE4CE209006C2002C9CB1 /* ComplicationController.swift */,
294EE4D0209006C3002C9CB1 /* Assets.xcassets */,
2949275F20941857008B34EE /* EmptyRowController.swift */,
294927692094BB3B008B34EE /* ErrorRowController.swift */,
2941E4D2209411D60046932D /* ExtensionDelegate.swift */,
294927722094C5DF008B34EE /* FreetimeWatch Extension.entitlements */,
294EE4CA209006C2002C9CB1 /* InboxController.swift */,
294927C620966C98008B34EE /* InboxDataController.swift */,
2941E4D6209415340046932D /* InboxRowController.swift */,
294EE4D2209006C3002C9CB1 /* Info.plist */,
2949276D2094BCA8008B34EE /* LoadingRowController.swift */,
2949276B2094BB82008B34EE /* NSObject+RowControllerIdentifier.swift */,
2949276320941870008B34EE /* ReadAllRowController.swift */,
2941E4D4209412700046932D /* RepoInboxController.swift */,
2941E4D8209416510046932D /* RepoInboxRowController.swift */,
2949276120941865008B34EE /* SignInRowController.swift */,
2949276F2094C088008B34EE /* V3Repository+HashableEquatable.swift */,
);
path = "FreetimeWatch Extension";
sourceTree = "<group>";
@@ -1378,7 +1404,6 @@
29459A6E1FE61E0500034A04 /* MarkdownCheckboxModel.swift */,
29351EA320796BB800FF8C17 /* String+DetectShortlink.swift */,
29351E9B2079106300FF8C17 /* String+GitHubEmoji.swift */,
2931EA461EF7734B00AEE0FF /* String+NSRange.swift */,
29351EA12079663800FF8C17 /* String+Shortlink.swift */,
29351EA52079791800FF8C17 /* String+StripHTMLComments.swift */,
2965F36F2071508C003CC92F /* StyledTextBuilder+Checkbox.swift */,
@@ -1454,7 +1479,6 @@
isa = PBXGroup;
children = (
DCA5ED171FAEF3220072F074 /* Bookmark Tests */,
297AE84C1EC0D58A00B44A1F /* DateDisplayTests.swift */,
2981A8A61EFEBEF900E25EF1 /* EmojiTests.swift */,
2986B35D1FD462AA00E3CFC6 /* FilePathTests.swift */,
296B4E331F7C80B800C16887 /* GraphQLIDDecodeTests.swift */,
@@ -1558,9 +1582,9 @@
298BA08C1EC90A9000B01946 /* NSAttributedStringSizing.swift */,
292CD3D31F0DC12100D3D57B /* PhotoViewHandler.swift */,
2980033A1F51E82400BE90F4 /* Rating */,
65A3152A2044376D0074E3B6 /* Route.swift */,
293189271F5391F700EF0911 /* Result.swift */,
29316DC21ECC981D007CAE3F /* RootNavigationManager.swift */,
65A3152A2044376D0074E3B6 /* Route.swift */,
294A3D751FB29843000E81A4 /* ScrollViewKeyboardAdjuster.swift */,
9870B9021FC73EE70009719C /* Secrets.swift */,
3E79A2FE1F8A7DA700E1126B /* ShortcutHandler.swift */,
@@ -1615,7 +1639,6 @@
29DA1E871F5E2B8A0050C64B /* ClearAllHeaderCell.swift */,
29B94E661FCB2D4600715D7E /* CodeView.swift */,
29C167661ECA005500439D62 /* Constants.swift */,
29A195031EC74C4800C3E289 /* Date+Display.swift */,
29A4768D1ED07A23005D0953 /* DateDetailsFormatter.swift */,
291929601F3FD2960012067B /* DiffString.swift */,
D8C2AEF41F9AA94600A95945 /* DotListView.swift */,
@@ -1641,7 +1664,6 @@
29C2950F1EC7B7FF00D46CD2 /* ShowMoreDetailsLabel.swift */,
295840701EE9F4D3007723C6 /* ShowMoreDetailsLabel+Date.swift */,
2971722C1F069E96005E43AC /* SpinnerCell.swift */,
29A08FC01F12F08100C5368E /* String+HashDisplay.swift */,
291929621F3FF0DA0012067B /* StyledTableCell.swift */,
299F63E7205F09900015D901 /* StyledTextRenderer+ListDiffable.swift */,
299F63D9205DD86E0015D901 /* StyledTextViewCell.swift */,
@@ -2136,11 +2158,21 @@
CreatedOnToolsVersion = 9.3;
DevelopmentTeam = 523C4DWBTH;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.ApplicationGroups.iOS = {
enabled = 1;
};
};
};
294EE4C4209006C2002C9CB1 = {
CreatedOnToolsVersion = 9.3;
DevelopmentTeam = 523C4DWBTH;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.ApplicationGroups.iOS = {
enabled = 1;
};
};
};
297AE8331EC0D58A00B44A1F = {
CreatedOnToolsVersion = 8.3.2;
@@ -2359,6 +2391,7 @@
"${BUILT_PRODUCTS_DIR}/Apollo-iOS/Apollo.framework",
"${BUILT_PRODUCTS_DIR}/AutoInsetter/AutoInsetter.framework",
"${BUILT_PRODUCTS_DIR}/ContextMenu/ContextMenu.framework",
"${BUILT_PRODUCTS_DIR}/DateAgo-iOS/DateAgo.framework",
"${BUILT_PRODUCTS_DIR}/FLAnimatedImage/FLAnimatedImage.framework",
"${BUILT_PRODUCTS_DIR}/FLEX/FLEX.framework",
"${BUILT_PRODUCTS_DIR}/FlatCache/FlatCache.framework",
@@ -2373,6 +2406,7 @@
"${BUILT_PRODUCTS_DIR}/Pageboy/Pageboy.framework",
"${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework",
"${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework",
"${BUILT_PRODUCTS_DIR}/StringHelpers-iOS/StringHelpers.framework",
"${BUILT_PRODUCTS_DIR}/StyledText/StyledText.framework",
"${BUILT_PRODUCTS_DIR}/SwipeCellKit/SwipeCellKit.framework",
"${BUILT_PRODUCTS_DIR}/TUSafariActivity/TUSafariActivity.framework",
@@ -2388,6 +2422,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Apollo.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AutoInsetter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ContextMenu.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DateAgo.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FLAnimatedImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FLEX.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FlatCache.framework",
@@ -2402,6 +2437,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Pageboy.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/StringHelpers.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/StyledText.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwipeCellKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TUSafariActivity.framework",
@@ -2472,15 +2508,19 @@
"${SRCROOT}/Pods/Target Support Files/Pods-FreetimeWatch Extension/Pods-FreetimeWatch Extension-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/Alamofire-watchOS/Alamofire.framework",
"${BUILT_PRODUCTS_DIR}/Apollo-watchOS/Apollo.framework",
"${BUILT_PRODUCTS_DIR}/DateAgo-watchOS/DateAgo.framework",
"${BUILT_PRODUCTS_DIR}/GitHubAPI-watchOS/GitHubAPI.framework",
"${BUILT_PRODUCTS_DIR}/GitHubSession-watchOS/GitHubSession.framework",
"${BUILT_PRODUCTS_DIR}/StringHelpers-watchOS/StringHelpers.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Apollo.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DateAgo.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GitHubAPI.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GitHubSession.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/StringHelpers.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@@ -2528,6 +2568,7 @@
"${BUILT_PRODUCTS_DIR}/Apollo-iOS/Apollo.framework",
"${BUILT_PRODUCTS_DIR}/AutoInsetter/AutoInsetter.framework",
"${BUILT_PRODUCTS_DIR}/ContextMenu/ContextMenu.framework",
"${BUILT_PRODUCTS_DIR}/DateAgo-iOS/DateAgo.framework",
"${BUILT_PRODUCTS_DIR}/FLAnimatedImage/FLAnimatedImage.framework",
"${BUILT_PRODUCTS_DIR}/FLEX/FLEX.framework",
"${BUILT_PRODUCTS_DIR}/FlatCache/FlatCache.framework",
@@ -2542,6 +2583,7 @@
"${BUILT_PRODUCTS_DIR}/Pageboy/Pageboy.framework",
"${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework",
"${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework",
"${BUILT_PRODUCTS_DIR}/StringHelpers-iOS/StringHelpers.framework",
"${BUILT_PRODUCTS_DIR}/StyledText/StyledText.framework",
"${BUILT_PRODUCTS_DIR}/SwipeCellKit/SwipeCellKit.framework",
"${BUILT_PRODUCTS_DIR}/TUSafariActivity/TUSafariActivity.framework",
@@ -2558,6 +2600,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Apollo.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AutoInsetter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ContextMenu.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DateAgo.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FLAnimatedImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FLEX.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FlatCache.framework",
@@ -2572,6 +2615,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Pageboy.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/StringHelpers.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/StyledText.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwipeCellKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TUSafariActivity.framework",
@@ -2593,9 +2637,19 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
294EE4CD209006C2002C9CB1 /* ExtensionDelegate.swift in Sources */,
294EE4CB209006C2002C9CB1 /* InterfaceController.swift in Sources */,
294EE4CF209006C2002C9CB1 /* ComplicationController.swift in Sources */,
2949276220941865008B34EE /* SignInRowController.swift in Sources */,
2941E4D3209411D60046932D /* ExtensionDelegate.swift in Sources */,
2941E4D5209412700046932D /* RepoInboxController.swift in Sources */,
2941E4D9209416510046932D /* RepoInboxRowController.swift in Sources */,
2949276A2094BB3B008B34EE /* ErrorRowController.swift in Sources */,
2949276C2094BB82008B34EE /* NSObject+RowControllerIdentifier.swift in Sources */,
2949276E2094BCA8008B34EE /* LoadingRowController.swift in Sources */,
294927702094C088008B34EE /* V3Repository+HashableEquatable.swift in Sources */,
294EE4CB209006C2002C9CB1 /* InboxController.swift in Sources */,
294927C720966C98008B34EE /* InboxDataController.swift in Sources */,
2949276020941857008B34EE /* EmptyRowController.swift in Sources */,
2949276420941870008B34EE /* ReadAllRowController.swift in Sources */,
2941E4D7209415340046932D /* InboxRowController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2627,7 +2681,6 @@
D8BAD0661FDF224600C41071 /* WrappingStaticSpacingFlowLayout.swift in Sources */,
98003D8D1FCAD7FC00755C17 /* LabelDetails.swift in Sources */,
297DD5E11F061BBE006E7E63 /* CreateProfileViewController.swift in Sources */,
29A195041EC74C4800C3E289 /* Date+Display.swift in Sources */,
29AAB7171FB4A2AE001D5E6A /* BoundedImageSize.swift in Sources */,
29A4768E1ED07A23005D0953 /* DateDetailsFormatter.swift in Sources */,
29AF1E8C1F8ABC5A0008A0EF /* RepositoryCodeDirectoryViewController.swift in Sources */,
@@ -2949,9 +3002,7 @@
65A3152B2044376D0074E3B6 /* Route.swift in Sources */,
29DB264A1FCA10A800C3D0C9 /* GithubHighlighting.swift in Sources */,
2950AB1D2083B1E400C6F19A /* EmptyLoadingView.swift in Sources */,
29A08FC11F12F08100C5368E /* String+HashDisplay.swift in Sources */,
29B0EF871F93DF6C00870291 /* RepositoryCodeBlobViewController.swift in Sources */,
2931EA471EF7734B00AEE0FF /* String+NSRange.swift in Sources */,
98F9F4001F9CCFFE005A0266 /* ImageUploadTableViewController.swift in Sources */,
29C167671ECA005500439D62 /* Constants.swift in Sources */,
291929631F3FF0DA0012067B /* StyledTableCell.swift in Sources */,
@@ -2994,7 +3045,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
293A45751F296B7E00DD1006 /* DateDisplayTests.swift in Sources */,
293A45761F296B7E00DD1006 /* IssueTests.swift in Sources */,
49D029001F91D90C00E39094 /* ReactionTests.swift in Sources */,
DC60C6CE1F98346400241271 /* MockSearchEmptyViewDelegate.swift in Sources */,
@@ -3077,6 +3127,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = FreetimeWatch/FreetimeWatch.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
@@ -3103,6 +3154,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = FreetimeWatch/FreetimeWatch.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
@@ -3129,6 +3181,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = FreetimeWatch/FreetimeWatch.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
@@ -3154,6 +3207,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = "FreetimeWatch Extension/FreetimeWatch Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 523C4DWBTH;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -3177,6 +3231,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = "FreetimeWatch Extension/FreetimeWatch Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 523C4DWBTH;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -3200,6 +3255,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = "FreetimeWatch Extension/FreetimeWatch Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 523C4DWBTH;
GCC_C_LANGUAGE_STANDARD = gnu11;

View File

@@ -1,99 +0,0 @@
//
// DateDisplayTests.swift
// DateDisplayTests
//
// Created by Ryan Nystrom on 5/12/17.
// Copyright © 2017 Ryan Nystrom. All rights reserved.
//
import XCTest
@testable import Freetime
class DateDisplayTests: XCTestCase {
func test_whenDateFuture() {
let result = Date(timeIntervalSinceNow: 10).agoString
XCTAssertEqual(result, "in the future")
}
func test_whenDateSeconds() {
let result = Date(timeIntervalSinceNow: -5).agoString
XCTAssertEqual(result, "just now")
}
func test_whenDateMinutes_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -61).agoString
XCTAssertEqual(result, "a minute ago")
}
func test_whenDateMinutes_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -59.5).agoString
XCTAssertEqual(result, "a minute ago")
}
func test_whenDateMinutes_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -119).agoString
XCTAssertEqual(result, "2 minutes ago")
}
func test_whenDateHour_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -3601).agoString
XCTAssertEqual(result, "an hour ago")
}
func test_whenDateHour_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -3599.5).agoString
XCTAssertEqual(result, "an hour ago")
}
func test_whenDateHours_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -7199).agoString
XCTAssertEqual(result, "2 hours ago")
}
func test_whenDateDay_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -86401).agoString
XCTAssertEqual(result, "a day ago")
}
func test_whenDateDay_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -86399.5).agoString
XCTAssertEqual(result, "a day ago")
}
func test_whenDateDay_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -172799).agoString
XCTAssertEqual(result, "2 days ago")
}
func test_whenDateMonth_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -2592001).agoString
XCTAssertEqual(result, "a month ago")
}
func test_whenDateMonth_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -2591999.5).agoString
XCTAssertEqual(result, "a month ago")
}
func test_whenDateMonth_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -5183999).agoString
XCTAssertEqual(result, "2 months ago")
}
func test_whenDateYear_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -31104001).agoString
XCTAssertEqual(result, "a year ago")
}
func test_whenDateYear_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -31103999.5).agoString
XCTAssertEqual(result, "a year ago")
}
func test_whenDateYear_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -62207999).agoString
XCTAssertEqual(result, "2 years ago")
}
}

View File

@@ -0,0 +1,24 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "git-commit@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

View File

@@ -0,0 +1,24 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "git-pull-request@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,24 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "issue-opened@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "mail@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "mail@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "repo@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "repo@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 849 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "tag@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "tag@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,56 +0,0 @@
//
// ComplicationController.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/24/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import ClockKit
class ComplicationController: NSObject, CLKComplicationDataSource {
// MARK: - Timeline Configuration
func getSupportedTimeTravelDirections(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimeTravelDirections) -> Void) {
handler([.forward, .backward])
}
func getTimelineStartDate(for complication: CLKComplication, withHandler handler: @escaping (Date?) -> Void) {
handler(nil)
}
func getTimelineEndDate(for complication: CLKComplication, withHandler handler: @escaping (Date?) -> Void) {
handler(nil)
}
func getPrivacyBehavior(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationPrivacyBehavior) -> Void) {
handler(.showOnLockScreen)
}
// MARK: - Timeline Population
func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {
// Call the handler with the current timeline entry
handler(nil)
}
func getTimelineEntries(for complication: CLKComplication, before date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
// Call the handler with the timeline entries prior to the given date
handler(nil)
}
func getTimelineEntries(for complication: CLKComplication, after date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void) {
// Call the handler with the timeline entries after to the given date
handler(nil)
}
// MARK: - Placeholder Templates
func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
// This method will be called once per supported complication, and the results will be cached
handler(nil)
}
}

View File

@@ -0,0 +1,14 @@
//
// EmptyRowController.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/27/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
import WatchKit
final class EmptyRowController: NSObject {
}

View File

@@ -0,0 +1,14 @@
//
// ErrorRowController.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/28/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
import WatchKit
final class ErrorRowController: NSObject {
}

View File

@@ -7,22 +7,10 @@
//
import WatchKit
import GitHubSession
class ExtensionDelegate: NSObject, WKExtensionDelegate {
func applicationDidFinishLaunching() {
// Perform any final initialization of your application.
}
func applicationDidBecomeActive() {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillResignActive() {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, etc.
}
func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
// Sent when the system needs to launch the application in the background to process tasks. Tasks arrive in a set, so loop through and process each one.
for task in backgroundTasks {

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.whoisryannystrom.freetime</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,136 @@
//
// InboxController.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/24/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import WatchKit
import Foundation
import GitHubSession
import GitHubAPI
final class InboxController: WKInterfaceController,
WatchAppUserSessionSyncDelegate,
InboxDataControllerDelegate {
@IBOutlet var table: WKInterfaceTable!
private var client: Client?
private var dataController = InboxDataController()
private let watchAppSync = WatchAppUserSessionSync(userSession: nil)
override func awake(withContext context: Any?) {
super.awake(withContext: context)
dataController.delegate = self
// start syncing sessions
watchAppSync?.delegate = self
watchAppSync?.start()
reconfigure(userSession: watchAppSync?.lastSyncedUserSession)
}
// MARK: Overrides
override func contextForSegue(
withIdentifier segueIdentifier: String,
in table: WKInterfaceTable,
rowIndex: Int
) -> Any? {
guard let client = self.client else { return nil }
let selection = dataController.unreadNotifications[rowIndex]
return RepoInboxController.Context(
client: client,
repo: selection.repo,
notifications: selection.notifications,
dataController: dataController
)
}
// MARK: Private API
private func reconfigure(userSession: GitHubUserSession?) {
guard let userSession = userSession else {
table.setNumberOfRows(1, withRowType: SignInRowController.rowControllerIdentifier)
return
}
let networkingConfigs = userSession.networkingConfigs
let config = ConfiguredNetworkers(
token: networkingConfigs.token,
useOauth: networkingConfigs.useOauth
)
client = Client(
httpPerformer: config.alamofire,
apollo: config.apollo,
token: userSession.token
)
fetch()
}
@IBAction func fetch() {
guard let client = self.client else { return }
table.setNumberOfRows(1, withRowType: LoadingRowController.rowControllerIdentifier)
client.send(V3NotificationRequest(all: false)) { [weak self] response in
switch response {
case .failure:
self?.handleError()
case .success(let result):
self?.handleSuccess(notifications: result.data)
}
}
}
@IBAction func readAll() {
dataController.readAll()
reload()
client?.send(V3MarkNotificationsRequest()) { [weak self] result in
if case .failure = result {
self?.dataController.unreadAll()
self?.reload()
}
}
}
func handleError() {
table.setNumberOfRows(1, withRowType: ErrorRowController.rowControllerIdentifier)
}
func handleSuccess(notifications: [V3Notification]) {
dataController.supply(notifications: notifications)
}
func reload() {
let unread = dataController.unreadNotifications
guard unread.count > 0 else {
table.setNumberOfRows(1, withRowType: EmptyRowController.rowControllerIdentifier)
return
}
table.setNumberOfRows(unread.count, withRowType: InboxRowController.rowControllerIdentifier)
for (i, group) in unread.enumerated() {
guard let row = table.rowController(at: i) as? InboxRowController else {
continue
}
row.repoLabel.setText(group.repo.name)
row.ownerLabel.setText("@\(group.repo.owner.login)")
row.numberLabel.setText("\(group.notifications.count)")
}
}
// MARK: WatchAppUserSessionSyncDelegate
func sync(_ sync: WatchAppUserSessionSync, didReceive userSession: GitHubUserSession) {
reconfigure(userSession: userSession)
}
// MARK: InboxDataControllerDelegate
func didUpdate(dataController: InboxDataController) {
reload()
}
}

View File

@@ -0,0 +1,67 @@
//
// InboxDataController.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/29/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
import GitHubAPI
protocol InboxDataControllerDelegate: class {
func didUpdate(dataController: InboxDataController)
}
final class InboxDataController {
weak var delegate: InboxDataControllerDelegate?
typealias NotificationGroup = (repo: V3Repository, notifications: [V3Notification])
private var readRepos = Set<V3Repository>()
private var _groupedNotifications = [NotificationGroup]()
var unreadNotifications: [NotificationGroup] {
return _groupedNotifications.filter { !readRepos.contains($0.repo) }
}
func read(repository: V3Repository) {
readRepos.insert(repository)
delegate?.didUpdate(dataController: self)
}
func unread(repository: V3Repository) {
readRepos.remove(repository)
delegate?.didUpdate(dataController: self)
}
func readAll() {
_groupedNotifications.forEach { readRepos.insert($0.repo) }
delegate?.didUpdate(dataController: self)
}
func unreadAll() {
_groupedNotifications.forEach { readRepos.remove($0.repo) }
delegate?.didUpdate(dataController: self)
}
func supply(notifications: [V3Notification]) {
var map = [V3Repository: [V3Notification]]()
for n in notifications {
var arr = map[n.repository] ?? []
arr.append(n)
map[n.repository] = arr
}
_groupedNotifications.removeAll()
let repos = map.keys.sorted { $0.name.lowercased() < $1.name.lowercased() }
for r in repos {
guard let notes = map[r] else { continue }
_groupedNotifications.append((r, notes))
}
delegate?.didUpdate(dataController: self)
}
}

View File

@@ -0,0 +1,18 @@
//
// InboxRowController.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/27/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
import WatchKit
final class InboxRowController: NSObject {
@IBOutlet var repoLabel: WKInterfaceLabel!
@IBOutlet var ownerLabel: WKInterfaceLabel!
@IBOutlet var numberLabel: WKInterfaceLabel!
}

View File

@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>FreetimeWatch Extension</string>
<string>GitHawk Extension</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>

View File

@@ -1,31 +0,0 @@
//
// InterfaceController.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/24/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import WatchKit
import Foundation
class InterfaceController: WKInterfaceController {
override func awake(withContext context: Any?) {
super.awake(withContext: context)
// Configure interface objects here.
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
}

View File

@@ -0,0 +1,14 @@
//
// LoadingRowController.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/28/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
import WatchKit
final class LoadingRowController: NSObject {
}

View File

@@ -0,0 +1,17 @@
//
// NSObject+RowControllerIdentifier.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/28/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
extension NSObject {
static var rowControllerIdentifier: String {
return String(describing: self)
}
}

View File

@@ -0,0 +1,14 @@
//
// ReadAllRowController.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/27/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
import WatchKit
final class ReadAllRowController: NSObject {
}

View File

@@ -0,0 +1,98 @@
//
// RepoInboxController.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/27/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import WatchKit
import Foundation
import GitHubAPI
import DateAgo
import StringHelpers
final class RepoInboxController: WKInterfaceController {
struct Context {
let client: Client
let repo: V3Repository
let notifications: [V3Notification]
let dataController: InboxDataController
}
@IBOutlet var table: WKInterfaceTable!
private var context: Context?
override func awake(withContext context: Any?) {
super.awake(withContext: context)
guard let context = context as? Context else { return }
self.context = context
setTitle(context.repo.name)
reload()
}
override func table(_ table: WKInterfaceTable, didSelectRowAt rowIndex: Int) {
// only handle selections on the "mark read" button
guard rowIndex == 0, let context = self.context else { return }
let repo = context.repo
let dataController = context.dataController
dataController.read(repository: repo)
context.client.send(V3MarkRepositoryNotificationsRequest(
owner: repo.owner.login,
repo: repo.name
)) { result in
// will unwind the read even though the controller is pushed
if case .failure = result {
dataController.unread(repository: repo)
}
}
pop()
}
// MARK: Private API
func reload() {
guard let context = self.context else { return }
table.insertRows(at: IndexSet(integer: 0), withRowType: ReadAllRowController.rowControllerIdentifier)
table.insertRows(at: IndexSet(integersIn: 1 ..< context.notifications.count + 1), withRowType: RepoInboxRowController.rowControllerIdentifier)
for (i, n) in context.notifications.enumerated() {
guard let row = table.rowController(at: i+1) as? RepoInboxRowController else { continue }
row.titleLabel.setText(n.subject.title)
row.dateLabel.setText(n.updatedAt.agoString(.short))
let imageName: String
switch n.subject.type {
case .commit: imageName = "git-commit"
case .invitation: imageName = "mail"
case .issue: imageName = "issue-opened"
case .pullRequest: imageName = "git-pull-request"
case .release: imageName = "tag"
case .repo: imageName = "repo"
}
row.typeImage.setImage(UIImage(named: imageName)?.withRenderingMode(.alwaysTemplate))
if let identifier = n.subject.identifier {
let number: String
switch identifier {
case .hash(let h):
number = h.hashDisplay
case .number(let num):
number = "#\(num)"
case .release(let r):
number = r
}
row.numberLabel.setText(number)
}
}
}
}

View File

@@ -0,0 +1,19 @@
//
// RepoInboxRowController.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/27/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
import WatchKit
final class RepoInboxRowController: NSObject {
@IBOutlet var typeImage: WKInterfaceImage!
@IBOutlet var numberLabel: WKInterfaceLabel!
@IBOutlet var dateLabel: WKInterfaceLabel!
@IBOutlet var titleLabel: WKInterfaceLabel!
}

View File

@@ -0,0 +1,14 @@
//
// SignInRowController.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/27/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
import WatchKit
final class SignInRowController: NSObject {
}

View File

@@ -0,0 +1,25 @@
//
// V3Repository+HashableEquatable.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/28/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
import GitHubAPI
extension V3Repository: Hashable, Equatable {
public var hashValue: Int {
return fullName.hashValue
}
public static func ==(lhs: V3Repository, rhs: V3Repository) -> Bool {
// a little bit lazy, but fast & cheap for the watch app's purpose
return lhs.id == rhs.id
&& lhs.fork == rhs.fork
&& lhs.isPrivate == rhs.isPrivate
}
}

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "bubble@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,24 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "git-commit@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

View File

@@ -0,0 +1,24 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "git-pull-request@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,24 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "issue-opened@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "mail@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "mail@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 973 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "repo@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "repo@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 849 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "tag@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "tag@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,14 +1,163 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="AgC-eL-Hgc">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="14109" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="AgC-eL-Hgc">
<device id="watch38" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11106"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="11055"/>
<deployment identifier="watchOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="14031"/>
</dependencies>
<scenes>
<!--Interface Controller-->
<!--Repo Inbox Controller-->
<scene sceneID="yU6-EI-dgV">
<objects>
<controller id="nTx-NL-3Cj" customClass="RepoInboxController" customModule="FreetimeWatch_Extension">
<items>
<table alignment="left" id="0qK-I3-Uzz">
<items>
<tableRow identifier="ReadAllRowController" id="YQk-iq-fF7" customClass="ReadAllRowController" customModule="FreetimeWatch_Extension">
<group key="rootItem" width="1" alignment="left" id="QJe-83-yxm">
<items>
<label alignment="center" verticalAlignment="center" text="Read All" id="x13-sK-eV4"/>
</items>
<color key="backgroundColor" red="0.011764705882352941" green="0.40000000000000002" blue="0.83921568627450982" alpha="1" colorSpace="calibratedRGB"/>
</group>
</tableRow>
<tableRow identifier="RepoInboxRowController" selectable="NO" id="uiB-PM-KME" customClass="RepoInboxRowController" customModule="FreetimeWatch_Extension">
<group key="rootItem" width="1" height="0.0" alignment="left" layout="vertical" id="KlY-D5-9qt">
<items>
<group width="1" alignment="left" id="cvk-MX-HXs">
<items>
<imageView width="16" height="16" alignment="left" image="issue-opened" contentMode="scaleAspectFit" id="Bpc-Pj-IwA">
<color key="tintColor" red="0.63921568627450975" green="0.66666666666666663" blue="0.69411764705882351" alpha="1" colorSpace="calibratedRGB"/>
</imageView>
<label alignment="left" text="#123" id="0Iq-QE-kCx">
<color key="textColor" red="0.63921568627450975" green="0.66666666666666663" blue="0.69411764705882351" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="font" style="UICTFontTextStyleFootnote"/>
</label>
<label alignment="right" text="26m" id="dLc-DV-bKW">
<color key="textColor" red="0.63921568630000003" green="0.66666666669999997" blue="0.69411764710000001" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="font" style="UICTFontTextStyleFootnote"/>
</label>
</items>
</group>
<label alignment="left" text="Setup peril for improved project management" numberOfLines="0" id="3fI-s1-naN"/>
</items>
<edgeInsets key="margins" left="6" right="6" top="6" bottom="6"/>
</group>
<connections>
<outlet property="dateLabel" destination="dLc-DV-bKW" id="rCM-J0-X63"/>
<outlet property="numberLabel" destination="0Iq-QE-kCx" id="J0q-fM-9bu"/>
<outlet property="titleLabel" destination="3fI-s1-naN" id="VEm-4d-2R0"/>
<outlet property="typeImage" destination="Bpc-Pj-IwA" id="U4C-RO-etR"/>
</connections>
</tableRow>
</items>
</table>
</items>
<connections>
<outlet property="table" destination="0qK-I3-Uzz" id="6qQ-Hm-bzS"/>
</connections>
</controller>
</objects>
<point key="canvasLocation" x="423" y="30"/>
</scene>
<!--Inbox-->
<scene sceneID="aou-V4-d1y">
<objects>
<controller id="AgC-eL-Hgc" customClass="InterfaceController" customModuleProvider="target"/>
<controller title="Inbox" id="AgC-eL-Hgc" customClass="InboxController" customModule="FreetimeWatch_Extension">
<items>
<table alignment="left" id="8uq-g7-0Sk">
<items>
<tableRow identifier="InboxRowController" id="N4A-Tv-xmG" customClass="InboxRowController" customModule="FreetimeWatch_Extension">
<group key="rootItem" width="1" height="0.0" alignment="left" id="ykd-Zf-n0V">
<items>
<group width="0.80000000000000004" alignment="left" layout="vertical" id="AaP-3V-aTN">
<items>
<label alignment="left" text="GitHawk" id="JYP-tM-27D"/>
<label alignment="left" text="@GitHawkApp" id="2bk-AN-DLd">
<color key="textColor" red="0.63921568627450975" green="0.66666666666666663" blue="0.69411764705882351" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="font" style="UICTFontTextStyleFootnote"/>
</label>
</items>
</group>
<group width="0.20000000000000001" height="1" alignment="left" backgroundImage="bubble" contentMode="scaleAspectFit" id="CRw-3E-oAf">
<items>
<label alignment="center" verticalAlignment="center" text="33" id="YjR-eH-1Am">
<fontDescription key="font" type="system" weight="semibold" pointSize="13"/>
</label>
</items>
</group>
</items>
<edgeInsets key="margins" left="6" right="6" top="6" bottom="6"/>
</group>
<connections>
<outlet property="numberLabel" destination="YjR-eH-1Am" id="Wkb-0K-v1h"/>
<outlet property="ownerLabel" destination="2bk-AN-DLd" id="oVt-w4-0Do"/>
<outlet property="repoLabel" destination="JYP-tM-27D" id="hgb-ef-0Wc"/>
<segue destination="nTx-NL-3Cj" kind="push" identifier="push-repo" id="9hU-ji-VN0"/>
</connections>
</tableRow>
<tableRow identifier="EmptyRowController" selectable="NO" id="OIJ-jf-f4Z" customClass="EmptyRowController" customModule="FreetimeWatch_Extension">
<group key="rootItem" width="1" height="1" alignment="left" layout="vertical" id="d8q-bd-5fd">
<items>
<label alignment="center" verticalAlignment="center" text="🎉" id="yh9-fC-EBv">
<fontDescription key="font" type="system" pointSize="45"/>
</label>
<label alignment="center" verticalAlignment="center" text="Inbox Zero!" textAlignment="left" id="Hug-7B-qNr"/>
</items>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</group>
</tableRow>
<tableRow identifier="SignInRowController" selectable="NO" id="8bT-xf-Mmm" customClass="SignInRowController" customModule="FreetimeWatch_Extension">
<group key="rootItem" width="1" height="1" alignment="left" id="KFh-jD-PB7">
<items>
<label alignment="center" verticalAlignment="center" text="Please sign in with GitHawk" numberOfLines="0" id="08D-bo-FiB"/>
</items>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</group>
</tableRow>
<tableRow identifier="ErrorRowController" id="ebY-EG-lFZ" customClass="ErrorRowController" customModule="FreetimeWatch_Extension">
<group key="rootItem" width="1" height="1" alignment="left" layout="vertical" id="ttM-1I-ZyI">
<items>
<label alignment="center" verticalAlignment="center" text="Error loading inbox" textAlignment="center" numberOfLines="0" id="Zn0-lb-QWS"/>
<button width="1" alignment="center" verticalAlignment="center" title="Reload" id="lGO-Sa-km6">
<color key="backgroundColor" red="0.19607843137254902" green="0.49019607843137253" blue="0.84313725490196079" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</button>
</items>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</group>
</tableRow>
<tableRow identifier="LoadingRowController" id="7s6-nU-d0l" customClass="LoadingRowController" customModule="FreetimeWatch_Extension">
<group key="rootItem" width="1" height="1" alignment="left" id="Kxo-zw-8HA">
<items>
<label alignment="center" verticalAlignment="center" text="Loading..." id="GJI-5P-Szf"/>
</items>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</group>
</tableRow>
</items>
</table>
</items>
<menu key="menu" id="XZr-fZ-ech">
<items>
<menuItem title="Refresh" icon="resume" id="C6P-VE-2uA">
<connections>
<action selector="fetch" destination="AgC-eL-Hgc" id="Wdr-J5-XYs"/>
</connections>
</menuItem>
<menuItem title="Read All" icon="accept" id="5gs-6O-dzx">
<connections>
<action selector="readAll" destination="AgC-eL-Hgc" id="Q9l-YO-Quh"/>
</connections>
</menuItem>
</items>
</menu>
<connections>
<outlet property="table" destination="8uq-g7-0Sk" id="ige-to-SCn"/>
</connections>
</controller>
</objects>
</scene>
</scenes>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.whoisryannystrom.freetime</string>
</array>
</dict>
</plist>

View File

@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Freetime</string>
<string>GitHawk</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>

View File

@@ -0,0 +1,13 @@
Pod::Spec.new do |spec|
spec.name = 'DateAgo'
spec.version = '0.1.0'
spec.license = { :type => 'MIT' }
spec.homepage = 'https://github.com/GitHawkApp/githawk'
spec.authors = { 'Ryan Nystrom' => 'rnystrom@whoisryannystrom.com' }
spec.summary = '.'
spec.source = { :git => 'https://github.com/GitHawkApp/githawk/githawk.git', :tag => '#{s.version}' }
spec.source_files = 'DateAgo/*.swift'
spec.resource_bundle = { "Resources" => ["DateAgo/Localizable.stringsdict"] }
spec.ios.deployment_target = '11.0'
spec.watchos.deployment_target = '3.0'
end

View File

@@ -0,0 +1,480 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
2949278A2096565F008B34EE /* DateAgo.h in Headers */ = {isa = PBXBuildFile; fileRef = 294927882096565F008B34EE /* DateAgo.h */; settings = {ATTRIBUTES = (Public, ); }; };
294927912096567B008B34EE /* Date+Ago.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294927902096567B008B34EE /* Date+Ago.swift */; };
29492793209656B0008B34EE /* Date+AgoString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29492792209656B0008B34EE /* Date+AgoString.swift */; };
2949279D20965834008B34EE /* DateAgoLongTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2949279C20965834008B34EE /* DateAgoLongTests.swift */; };
2949279F20965834008B34EE /* DateAgo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 294927852096565F008B34EE /* DateAgo.framework */; };
294927A720965BE1008B34EE /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 294927A620965BE0008B34EE /* Localizable.stringsdict */; };
294927A820965BFC008B34EE /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 294927A620965BE0008B34EE /* Localizable.stringsdict */; };
294927AA20965D56008B34EE /* DateAgoShortTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294927A920965D56008B34EE /* DateAgoShortTests.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
294927A020965834008B34EE /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 2949277C2096565F008B34EE /* Project object */;
proxyType = 1;
remoteGlobalIDString = 294927842096565F008B34EE;
remoteInfo = DateAgo;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
294927852096565F008B34EE /* DateAgo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DateAgo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
294927882096565F008B34EE /* DateAgo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DateAgo.h; sourceTree = "<group>"; };
294927892096565F008B34EE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
294927902096567B008B34EE /* Date+Ago.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Ago.swift"; sourceTree = "<group>"; };
29492792209656B0008B34EE /* Date+AgoString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+AgoString.swift"; sourceTree = "<group>"; };
2949279A20965834008B34EE /* DateAgoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DateAgoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
2949279C20965834008B34EE /* DateAgoLongTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateAgoLongTests.swift; sourceTree = "<group>"; };
2949279E20965834008B34EE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
294927A620965BE0008B34EE /* Localizable.stringsdict */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.stringsdict; path = Localizable.stringsdict; sourceTree = "<group>"; };
294927A920965D56008B34EE /* DateAgoShortTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateAgoShortTests.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
294927812096565F008B34EE /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
2949279720965834008B34EE /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
2949279F20965834008B34EE /* DateAgo.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
2949277B2096565F008B34EE = {
isa = PBXGroup;
children = (
294927872096565F008B34EE /* DateAgo */,
2949279B20965834008B34EE /* DateAgoTests */,
294927862096565F008B34EE /* Products */,
);
sourceTree = "<group>";
};
294927862096565F008B34EE /* Products */ = {
isa = PBXGroup;
children = (
294927852096565F008B34EE /* DateAgo.framework */,
2949279A20965834008B34EE /* DateAgoTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
294927872096565F008B34EE /* DateAgo */ = {
isa = PBXGroup;
children = (
294927902096567B008B34EE /* Date+Ago.swift */,
29492792209656B0008B34EE /* Date+AgoString.swift */,
294927882096565F008B34EE /* DateAgo.h */,
294927892096565F008B34EE /* Info.plist */,
294927A620965BE0008B34EE /* Localizable.stringsdict */,
);
path = DateAgo;
sourceTree = "<group>";
};
2949279B20965834008B34EE /* DateAgoTests */ = {
isa = PBXGroup;
children = (
2949279C20965834008B34EE /* DateAgoLongTests.swift */,
294927A920965D56008B34EE /* DateAgoShortTests.swift */,
2949279E20965834008B34EE /* Info.plist */,
);
path = DateAgoTests;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
294927822096565F008B34EE /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
2949278A2096565F008B34EE /* DateAgo.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
294927842096565F008B34EE /* DateAgo */ = {
isa = PBXNativeTarget;
buildConfigurationList = 2949278D2096565F008B34EE /* Build configuration list for PBXNativeTarget "DateAgo" */;
buildPhases = (
294927802096565F008B34EE /* Sources */,
294927812096565F008B34EE /* Frameworks */,
294927822096565F008B34EE /* Headers */,
294927832096565F008B34EE /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = DateAgo;
productName = DateAgo;
productReference = 294927852096565F008B34EE /* DateAgo.framework */;
productType = "com.apple.product-type.framework";
};
2949279920965834008B34EE /* DateAgoTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 294927A220965834008B34EE /* Build configuration list for PBXNativeTarget "DateAgoTests" */;
buildPhases = (
2949279620965834008B34EE /* Sources */,
2949279720965834008B34EE /* Frameworks */,
2949279820965834008B34EE /* Resources */,
);
buildRules = (
);
dependencies = (
294927A120965834008B34EE /* PBXTargetDependency */,
);
name = DateAgoTests;
productName = DateAgoTests;
productReference = 2949279A20965834008B34EE /* DateAgoTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
2949277C2096565F008B34EE /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0930;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "Ryan Nystrom";
TargetAttributes = {
294927842096565F008B34EE = {
CreatedOnToolsVersion = 9.3;
LastSwiftMigration = 0930;
};
2949279920965834008B34EE = {
CreatedOnToolsVersion = 9.3;
};
};
};
buildConfigurationList = 2949277F2096565F008B34EE /* Build configuration list for PBXProject "DateAgo" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 2949277B2096565F008B34EE;
productRefGroup = 294927862096565F008B34EE /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
294927842096565F008B34EE /* DateAgo */,
2949279920965834008B34EE /* DateAgoTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
294927832096565F008B34EE /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
294927A720965BE1008B34EE /* Localizable.stringsdict in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
2949279820965834008B34EE /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
294927A820965BFC008B34EE /* Localizable.stringsdict in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
294927802096565F008B34EE /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
29492793209656B0008B34EE /* Date+AgoString.swift in Sources */,
294927912096567B008B34EE /* Date+Ago.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
2949279620965834008B34EE /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
294927AA20965D56008B34EE /* DateAgoShortTests.swift in Sources */,
2949279D20965834008B34EE /* DateAgoLongTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
294927A120965834008B34EE /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 294927842096565F008B34EE /* DateAgo */;
targetProxy = 294927A020965834008B34EE /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
2949278B2096565F008B34EE /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.3;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
2949278C2096565F008B34EE /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.3;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
2949278E2096565F008B34EE /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 523C4DWBTH;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = DateAgo/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.whoisryannystrom.DateAgo;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
2949278F2096565F008B34EE /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 523C4DWBTH;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = DateAgo/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.whoisryannystrom.DateAgo;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
294927A320965834008B34EE /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 523C4DWBTH;
INFOPLIST_FILE = DateAgoTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.whoisryannystrom.DateAgoTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
294927A420965834008B34EE /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 523C4DWBTH;
INFOPLIST_FILE = DateAgoTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.whoisryannystrom.DateAgoTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
2949277F2096565F008B34EE /* Build configuration list for PBXProject "DateAgo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2949278B2096565F008B34EE /* Debug */,
2949278C2096565F008B34EE /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
2949278D2096565F008B34EE /* Build configuration list for PBXNativeTarget "DateAgo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2949278E2096565F008B34EE /* Debug */,
2949278F2096565F008B34EE /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
294927A220965834008B34EE /* Build configuration list for PBXNativeTarget "DateAgoTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
294927A320965834008B34EE /* Debug */,
294927A420965834008B34EE /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 2949277C2096565F008B34EE /* Project object */;
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:DateAgo.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -1,16 +1,16 @@
//
// Date+Display.swift
// Freetime
// Date+Ago.swift
// DateAgo
//
// Created by Ryan Nystrom on 5/13/17.
// Copyright © 2017 Ryan Nystrom. All rights reserved.
// Created by Ryan Nystrom on 4/29/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
extension Date {
private enum Ago {
internal enum Ago {
case future(Int)
case seconds(Int)
case minutes(Int)
@@ -20,7 +20,7 @@ extension Date {
case years(Int)
}
private var ago: Ago {
internal var ago: Ago {
let seconds = timeIntervalSinceNow
if seconds > 0 {
return Ago.future(Int(seconds))
@@ -49,26 +49,4 @@ extension Date {
}
}
var agoString: String {
switch ago {
case .future: return NSLocalizedString("in the future", comment: "")
case .seconds: return NSLocalizedString("just now", comment: "")
case .minutes(let t):
let format = NSLocalizedString("%d minute(s) ago", comment: "")
return String(format: format, t)
case .hours(let t):
let format = NSLocalizedString("%d hour(s) ago", comment: "")
return String(format: format, t)
case .days(let t):
let format = NSLocalizedString("%d day(s) ago", comment: "")
return String(format: format, t)
case .months(let t):
let format = NSLocalizedString("%d month(s) ago", comment: "")
return String(format: format, t)
case .years(let t):
let format = NSLocalizedString("%d year(s) ago", comment: "")
return String(format: format, t)
}
}
}

View File

@@ -0,0 +1,77 @@
//
// Date+AgoString.swift
// DateAgo
//
// Created by Ryan Nystrom on 4/29/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
public extension Date {
enum AgoFormat {
case short
case long
}
private static let dateFormatter: DateComponentsFormatter = {
let f = DateComponentsFormatter()
f.unitsStyle = .abbreviated
return f
}()
private static let bundle: Bundle = {
return Bundle(identifier: "com.whoisryannystrom.DateAgo") ?? Bundle.main
}()
func agoString(_ format: AgoFormat = .long) -> String {
switch ago {
case .future:
return NSLocalizedString("in the future", bundle: Date.bundle, comment: "")
case .seconds:
return NSLocalizedString("just now", bundle: Date.bundle, comment: "")
case .minutes(let t):
switch format {
case .long:
let format = NSLocalizedString("%d minute(s) ago", bundle: Date.bundle, comment: "")
return String(format: format, t)
case .short:
return Date.dateFormatter.string(from: DateComponents(minute: t)) ?? "\(t)"
}
case .hours(let t):
switch format {
case .long:
let format = NSLocalizedString("%d hour(s) ago", bundle: Date.bundle, comment: "")
return String(format: format, t)
case .short:
return Date.dateFormatter.string(from: DateComponents(hour: t)) ?? "\(t)"
}
case .days(let t):
switch format {
case .long:
let format = NSLocalizedString("%d day(s) ago", bundle: Date.bundle, comment: "")
return String(format: format, t)
case .short:
return Date.dateFormatter.string(from: DateComponents(day: t)) ?? "\(t)"
}
case .months(let t):
switch format {
case .long:
let format = NSLocalizedString("%d month(s) ago", bundle: Date.bundle, comment: "")
return String(format: format, t)
case .short:
return Date.dateFormatter.string(from: DateComponents(month: t)) ?? "\(t)"
}
case .years(let t):
switch format {
case .long:
let format = NSLocalizedString("%d year(s) ago", bundle: Date.bundle, comment: "")
return String(format: format, t)
case .short:
return Date.dateFormatter.string(from: DateComponents(year: t)) ?? "\(t)"
}
}
}
}

View File

@@ -0,0 +1,19 @@
//
// DateAgo.h
// DateAgo
//
// Created by Ryan Nystrom on 4/29/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
#import <UIKit/UIKit.h>
//! Project version number for DateAgo.
FOUNDATION_EXPORT double DateAgoVersionNumber;
//! Project version string for DateAgo.
FOUNDATION_EXPORT const unsigned char DateAgoVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <DateAgo/PublicHeader.h>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>%@, %@, %@ and %d other(s)</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%@, %@, %@ and %#@others@</string>
<key>others</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>zero</key>
<string></string>
<key>one</key>
<string>%d other</string>
<key>two</key>
<string></string>
<key>few</key>
<string></string>
<key>many</key>
<string></string>
<key>other</key>
<string>%d others</string>
</dict>
</dict>
<key>%d minute(s) ago</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@minutes@</string>
<key>minutes</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>zero</key>
<string></string>
<key>one</key>
<string>a minute ago</string>
<key>two</key>
<string></string>
<key>few</key>
<string></string>
<key>many</key>
<string></string>
<key>other</key>
<string>%d minutes ago</string>
</dict>
</dict>
<key>%d hour(s) ago</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@hours@</string>
<key>hours</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>zero</key>
<string></string>
<key>one</key>
<string>an hour ago</string>
<key>two</key>
<string></string>
<key>few</key>
<string></string>
<key>many</key>
<string></string>
<key>other</key>
<string>%d hours ago</string>
</dict>
</dict>
<key>%d day(s) ago</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@days@</string>
<key>days</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>zero</key>
<string></string>
<key>one</key>
<string>a day ago</string>
<key>two</key>
<string></string>
<key>few</key>
<string></string>
<key>many</key>
<string></string>
<key>other</key>
<string>%d days ago</string>
</dict>
</dict>
<key>%d month(s) ago</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@months@</string>
<key>months</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>zero</key>
<string></string>
<key>one</key>
<string>a month ago</string>
<key>two</key>
<string></string>
<key>few</key>
<string></string>
<key>many</key>
<string></string>
<key>other</key>
<string>%d months ago</string>
</dict>
</dict>
<key>%d year(s) ago</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@years@</string>
<key>years</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>zero</key>
<string></string>
<key>one</key>
<string>a year ago</string>
<key>two</key>
<string></string>
<key>few</key>
<string></string>
<key>many</key>
<string></string>
<key>other</key>
<string>%d years ago</string>
</dict>
</dict>
</dict>
</plist>

View File

@@ -0,0 +1,103 @@
//
// DateAgoShortTests.swift
// DateAgoTests
//
// Created by Ryan Nystrom on 4/29/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import XCTest
@testable import DateAgo
class DateAgoShortTests: XCTestCase {
class DateDisplayTests: XCTestCase {
func test_whenDateFuture() {
let result = Date(timeIntervalSinceNow: 10).agoString(.short)
XCTAssertEqual(result, "in the future")
}
func test_whenDateSeconds() {
let result = Date(timeIntervalSinceNow: -5).agoString(.short)
XCTAssertEqual(result, "just now")
}
func test_whenDateMinutes_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -61).agoString(.short)
XCTAssertEqual(result, "1m")
}
func test_whenDateMinutes_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -59.5).agoString(.short)
XCTAssertEqual(result, "1m")
}
func test_whenDateMinutes_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -119).agoString(.short)
XCTAssertEqual(result, "2m")
}
func test_whenDateHour_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -3601).agoString(.short)
XCTAssertEqual(result, "1h")
}
func test_whenDateHour_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -3599.5).agoString(.short)
XCTAssertEqual(result, "1h")
}
func test_whenDateHours_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -7199).agoString(.short)
XCTAssertEqual(result, "2h")
}
func test_whenDateDay_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -86401).agoString(.short)
XCTAssertEqual(result, "1d")
}
func test_whenDateDay_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -86399.5).agoString(.short)
XCTAssertEqual(result, "1d")
}
func test_whenDateDay_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -172799).agoString(.short)
XCTAssertEqual(result, "2d")
}
func test_whenDateMonth_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -2592001).agoString(.short)
XCTAssertEqual(result, "1mo")
}
func test_whenDateMonth_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -2591999.5).agoString(.short)
XCTAssertEqual(result, "1mo")
}
func test_whenDateMonth_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -5183999).agoString(.short)
XCTAssertEqual(result, "2mo")
}
func test_whenDateYear_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -31104001).agoString(.short)
XCTAssertEqual(result, "1y")
}
func test_whenDateYear_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -31103999.5).agoString(.short)
XCTAssertEqual(result, "1y")
}
func test_whenDateYear_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -62207999).agoString(.short)
XCTAssertEqual(result, "2y")
}
}
}

View File

@@ -0,0 +1,103 @@
//
// DateAgoLongTests.swift
// DateAgoTests
//
// Created by Ryan Nystrom on 4/29/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import XCTest
@testable import DateAgo
class DateAgoLongTests: XCTestCase {
class DateDisplayTests: XCTestCase {
func test_whenDateFuture() {
let result = Date(timeIntervalSinceNow: 10).agoString()
XCTAssertEqual(result, "in the future")
}
func test_whenDateSeconds() {
let result = Date(timeIntervalSinceNow: -5).agoString()
XCTAssertEqual(result, "just now")
}
func test_whenDateMinutes_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -61).agoString()
XCTAssertEqual(result, "a minute ago")
}
func test_whenDateMinutes_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -59.5).agoString()
XCTAssertEqual(result, "a minute ago")
}
func test_whenDateMinutes_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -119).agoString()
XCTAssertEqual(result, "2 minutes ago")
}
func test_whenDateHour_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -3601).agoString()
XCTAssertEqual(result, "an hour ago")
}
func test_whenDateHour_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -3599.5).agoString()
XCTAssertEqual(result, "an hour ago")
}
func test_whenDateHours_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -7199).agoString()
XCTAssertEqual(result, "2 hours ago")
}
func test_whenDateDay_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -86401).agoString()
XCTAssertEqual(result, "a day ago")
}
func test_whenDateDay_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -86399.5).agoString()
XCTAssertEqual(result, "a day ago")
}
func test_whenDateDay_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -172799).agoString()
XCTAssertEqual(result, "2 days ago")
}
func test_whenDateMonth_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -2592001).agoString()
XCTAssertEqual(result, "a month ago")
}
func test_whenDateMonth_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -2591999.5).agoString()
XCTAssertEqual(result, "a month ago")
}
func test_whenDateMonth_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -5183999).agoString()
XCTAssertEqual(result, "2 months ago")
}
func test_whenDateYear_withLowerBound_withSingular() {
let result = Date(timeIntervalSinceNow: -31104001).agoString()
XCTAssertEqual(result, "a year ago")
}
func test_whenDateYear_withUpperBound_withDecimal_withSingular() {
let result = Date(timeIntervalSinceNow: -31103999.5).agoString()
XCTAssertEqual(result, "a year ago")
}
func test_whenDateYear_withUpperBound_withPlural() {
let result = Date(timeIntervalSinceNow: -62207999).agoString()
XCTAssertEqual(result, "2 years ago")
}
}
}

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@@ -0,0 +1,40 @@
//
// ConfiguredNetworkers.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/28/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
import Alamofire
import Apollo
public func ConfiguredNetworkers(
token: String?, useOauth: Bool?
) -> (alamofire: Alamofire.SessionManager, apollo: ApolloClient) {
var additionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
// for apollo + github gql endpoint
// http://dev.apollodata.com/ios/initialization.html
if let token = token, let useOauth = useOauth {
let header = useOauth ? "Bearer \(token)" : "token \(token)"
additionalHeaders["Authorization"] = header
}
let config = URLSessionConfiguration.default
config.httpAdditionalHeaders = additionalHeaders
config.timeoutIntervalForRequest = 15
// disable URL caching for the v3 API
config.requestCachePolicy = .reloadIgnoringLocalCacheData
config.urlCache = nil
let alamofire = Alamofire.SessionManager(configuration: config)
let gqlURL = URL(string: "https://api.github.com/graphql")!
let transport = HTTPNetworkTransport(url: gqlURL, configuration: config)
let apollo = ApolloClient(networkTransport: transport)
return (alamofire, apollo)
}

View File

@@ -24,3 +24,32 @@ public struct V3NotificationSubject: Codable {
public let url: URL?
}
public extension V3NotificationSubject {
enum Identifier {
case number(Int)
case hash(String)
case release(String)
}
var identifier: Identifier? {
guard let url = self.url else { return nil }
let split = url.absoluteString.components(separatedBy: "/")
guard split.count > 2,
let identifier = split.last
else { return nil }
let type = split[split.count - 2]
switch type {
case "commits":
return .hash(identifier)
case "releases":
return .release(identifier)
default:
return .number((identifier as NSString).integerValue)
}
}
}

View File

@@ -0,0 +1,22 @@
//
// GitHubUserSession+NetworkingConfigs.swift
// Freetime
//
// Created by Ryan Nystrom on 4/28/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
public extension GitHubUserSession {
var networkingConfigs: (token: String, useOauth: Bool) {
let useOauth: Bool
switch authMethod {
case .oauth: useOauth = true
case .pat: useOauth = false
}
return (token, useOauth)
}
}

View File

@@ -0,0 +1,102 @@
//
// WatchAppUserSessionSync.swift
// FreetimeWatch Extension
//
// Created by Ryan Nystrom on 4/28/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
import WatchConnectivity
import GitHubSession
public protocol WatchAppUserSessionSyncDelegate: class {
func sync(_ sync: WatchAppUserSessionSync, didReceive userSession: GitHubUserSession)
}
public class WatchAppUserSessionSync: NSObject, WCSessionDelegate {
public weak var delegate: WatchAppUserSessionSyncDelegate?
private let userSession: GitHubUserSession?
private let session: WCSession
private let key = "com.freetime.watchappsync.usersession"
public init?(userSession: GitHubUserSession? = nil) {
guard WCSession.isSupported() else { return nil }
self.session = WCSession.default
self.userSession = userSession
}
public func start() {
session.delegate = self
session.activate()
}
public var lastSyncedUserSession: GitHubUserSession? {
guard let data = UserDefaults.standard.value(forKey: key) as? Data else { return nil }
return NSKeyedUnarchiver.unarchiveObject(with: data) as? GitHubUserSession
}
// https://forums.developer.apple.com/thread/11658
public func sync(userSession: GitHubUserSession) {
for transfer in session.outstandingUserInfoTransfers {
if transfer.userInfo[key] != nil {
transfer.cancel()
}
}
let data = NSKeyedArchiver.archivedData(withRootObject: userSession)
validSession?.transferUserInfo([key: data])
}
// MARK: Private API
// https://www.natashatherobot.com/watchconnectivity-user-info/
private var validSession: WCSession? {
#if !os(watchOS)
guard session.isPaired && session.isWatchAppInstalled else {
return nil
}
#endif
return session
}
// MARK: WCSessionDelegate
public func session(
_ session: WCSession,
activationDidCompleteWith activationState: WCSessionActivationState,
error: Error?
) {
if let error = error {
print(error)
}
// don't auto sync if on watchOS
#if !os(watchOS)
if let userSession = self.userSession {
sync(userSession: userSession)
}
#endif
}
#if !os(watchOS)
public func sessionDidBecomeInactive(_ session: WCSession) {}
public func sessionDidDeactivate(_ session: WCSession) {}
#endif
// will only run on the watch
public func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
if let data = userInfo[key] as? Data,
let userSession = NSKeyedUnarchiver.unarchiveObject(with: data) as? GitHubUserSession {
UserDefaults.standard.set(data, forKey: key)
UserDefaults.standard.synchronize()
DispatchQueue.main.async { [weak self] in
guard let strongSelf = self else { return }
strongSelf.delegate?.sync(strongSelf, didReceive: userSession)
}
}
}
}

View File

@@ -0,0 +1,12 @@
Pod::Spec.new do |spec|
spec.name = 'StringHelpers'
spec.version = '0.1.0'
spec.license = { :type => 'MIT' }
spec.homepage = 'https://github.com/GitHawkApp/githawk'
spec.authors = { 'Ryan Nystrom' => 'rnystrom@whoisryannystrom.com' }
spec.summary = '.'
spec.source = { :git => 'https://github.com/GitHawkApp/githawk/githawk.git', :tag => '#{s.version}' }
spec.source_files = 'StringHelpers/*.swift'
spec.ios.deployment_target = '11.0'
spec.watchos.deployment_target = '3.0'
end

View File

@@ -0,0 +1,345 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
294927BA20966294008B34EE /* StringHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 294927B820966294008B34EE /* StringHelpers.h */; settings = {ATTRIBUTES = (Public, ); }; };
294927C1209662DE008B34EE /* String+NSRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294927C0209662DE008B34EE /* String+NSRange.swift */; };
294927C3209662F1008B34EE /* String+HashDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 294927C2209662F1008B34EE /* String+HashDisplay.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
294927B520966294008B34EE /* StringHelpers.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = StringHelpers.framework; sourceTree = BUILT_PRODUCTS_DIR; };
294927B820966294008B34EE /* StringHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StringHelpers.h; sourceTree = "<group>"; };
294927B920966294008B34EE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
294927C0209662DE008B34EE /* String+NSRange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+NSRange.swift"; sourceTree = "<group>"; };
294927C2209662F1008B34EE /* String+HashDisplay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+HashDisplay.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
294927B120966294008B34EE /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
294927AB20966294008B34EE = {
isa = PBXGroup;
children = (
294927B720966294008B34EE /* StringHelpers */,
294927B620966294008B34EE /* Products */,
);
sourceTree = "<group>";
};
294927B620966294008B34EE /* Products */ = {
isa = PBXGroup;
children = (
294927B520966294008B34EE /* StringHelpers.framework */,
);
name = Products;
sourceTree = "<group>";
};
294927B720966294008B34EE /* StringHelpers */ = {
isa = PBXGroup;
children = (
294927B820966294008B34EE /* StringHelpers.h */,
294927B920966294008B34EE /* Info.plist */,
294927C0209662DE008B34EE /* String+NSRange.swift */,
294927C2209662F1008B34EE /* String+HashDisplay.swift */,
);
path = StringHelpers;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
294927B220966294008B34EE /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
294927BA20966294008B34EE /* StringHelpers.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
294927B420966294008B34EE /* StringHelpers */ = {
isa = PBXNativeTarget;
buildConfigurationList = 294927BD20966294008B34EE /* Build configuration list for PBXNativeTarget "StringHelpers" */;
buildPhases = (
294927B020966294008B34EE /* Sources */,
294927B120966294008B34EE /* Frameworks */,
294927B220966294008B34EE /* Headers */,
294927B320966294008B34EE /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = StringHelpers;
productName = StringHelpers;
productReference = 294927B520966294008B34EE /* StringHelpers.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
294927AC20966294008B34EE /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "Ryan Nystrom";
TargetAttributes = {
294927B420966294008B34EE = {
CreatedOnToolsVersion = 9.3;
LastSwiftMigration = 0930;
};
};
};
buildConfigurationList = 294927AF20966294008B34EE /* Build configuration list for PBXProject "StringHelpers" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 294927AB20966294008B34EE;
productRefGroup = 294927B620966294008B34EE /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
294927B420966294008B34EE /* StringHelpers */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
294927B320966294008B34EE /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
294927B020966294008B34EE /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
294927C1209662DE008B34EE /* String+NSRange.swift in Sources */,
294927C3209662F1008B34EE /* String+HashDisplay.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
294927BB20966294008B34EE /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.3;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
294927BC20966294008B34EE /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.3;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
294927BE20966294008B34EE /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 523C4DWBTH;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = StringHelpers/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.whoisryannystrom.StringHelpers;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
294927BF20966294008B34EE /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 523C4DWBTH;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = StringHelpers/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.whoisryannystrom.StringHelpers;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
294927AF20966294008B34EE /* Build configuration list for PBXProject "StringHelpers" */ = {
isa = XCConfigurationList;
buildConfigurations = (
294927BB20966294008B34EE /* Debug */,
294927BC20966294008B34EE /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
294927BD20966294008B34EE /* Build configuration list for PBXNativeTarget "StringHelpers" */ = {
isa = XCConfigurationList;
buildConfigurations = (
294927BE20966294008B34EE /* Debug */,
294927BF20966294008B34EE /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 294927AC20966294008B34EE /* Project object */;
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:StringHelpers.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@@ -1,14 +1,14 @@
//
// String+HashDisplay.swift
// Freetime
// StringHelpers
//
// Created by Ryan Nystrom on 7/9/17.
// Copyright © 2017 Ryan Nystrom. All rights reserved.
// Created by Ryan Nystrom on 4/29/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
extension String {
public extension String {
var hashDisplay: String {
// trim to first <7 characters

View File

@@ -1,15 +1,16 @@
//
// String+NSRange.swift
// Freetime
// StringHelpers
//
// Created by Ryan Nystrom on 5/24/17.
// Copyright © 2017 Ryan Nystrom. All rights reserved.
// Created by Ryan Nystrom on 4/29/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import Foundation
// http://nshipster.com/nsregularexpression/
extension String {
public extension String {
/// An `NSRange` that represents the full range of the string.
var nsrange: NSRange {
return NSRange(location: 0, length: utf16.count)
@@ -27,4 +28,5 @@ extension String {
func range(from nsrange: NSRange) -> Range<Index>? {
return Range(nsrange, in: self)
}
}

View File

@@ -0,0 +1,19 @@
//
// StringHelpers.h
// StringHelpers
//
// Created by Ryan Nystrom on 4/29/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
#import <UIKit/UIKit.h>
//! Project version number for StringHelpers.
FOUNDATION_EXPORT double StringHelpersVersionNumber;
//! Project version string for StringHelpers.
FOUNDATION_EXPORT const unsigned char StringHelpersVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <StringHelpers/PublicHeader.h>

View File

@@ -6,6 +6,8 @@ inhibit_all_warnings!
def session_pods
pod 'GitHubAPI', :path => 'Local Pods/GitHubAPI'
pod 'GitHubSession', :path => 'Local Pods/GitHubSession'
pod 'DateAgo', :path => 'Local Pods/DateAgo'
pod 'StringHelpers', :path => 'Local Pods/StringHelpers'
end
def testing_pods

View File

@@ -10,6 +10,7 @@ PODS:
- ContextMenu (0.1.0)
- Crashlytics (3.9.3):
- Fabric (~> 1.7.2)
- DateAgo (0.1.0)
- Fabric (1.7.2)
- FBSnapshotTestCase (2.1.4):
- FBSnapshotTestCase/SwiftSupport (= 2.1.4)
@@ -72,6 +73,7 @@ PODS:
- FLAnimatedImage (~> 1.0)
- SDWebImage/Core
- SnapKit (4.0.0)
- StringHelpers (0.1.0)
- StyledText (0.1.0)
- SwiftLint (0.24.0)
- SwipeCellKit (1.9.0)
@@ -85,6 +87,7 @@ DEPENDENCIES:
- cmark-gfm-swift (from `https://github.com/GitHawkApp/cmark-gfm-swift.git`, branch `master`)
- ContextMenu (from `https://github.com/GitHawkApp/ContextMenu.git`, branch `master`)
- Crashlytics
- DateAgo (from `Local Pods/DateAgo`)
- Fabric
- FBSnapshotTestCase
- Firebase/Core
@@ -100,6 +103,7 @@ DEPENDENCIES:
- NYTPhotoViewer (~> 1.1.0)
- SDWebImage/GIF (~> 4.0.0)
- SnapKit (~> 4.0.0)
- StringHelpers (from `Local Pods/StringHelpers`)
- StyledText (from `https://github.com/GitHawkApp/StyledText.git`, branch `master`)
- SwiftLint
- SwipeCellKit (from `Local Pods/SwipeCellKit`)
@@ -113,6 +117,8 @@ EXTERNAL SOURCES:
ContextMenu:
:branch: master
:git: https://github.com/GitHawkApp/ContextMenu.git
DateAgo:
:path: Local Pods/DateAgo
FlatCache:
:branch: master
:git: https://github.com/GitHawkApp/FlatCache.git
@@ -129,6 +135,8 @@ EXTERNAL SOURCES:
MessageViewController:
:branch: master
:git: https://github.com/GitHawkApp/MessageViewController.git
StringHelpers:
:path: Local Pods/StringHelpers
StyledText:
:branch: master
:git: https://github.com/GitHawkApp/StyledText.git
@@ -166,6 +174,7 @@ SPEC CHECKSUMS:
cmark-gfm-swift: 8f7ffcd7d4ef6c0eeae5515c724fcde620e1028e
ContextMenu: c9a4b218acc1a5f23bd1857e65d15658582f2a33
Crashlytics: dbb07d01876c171c5ccbdf7826410380189e452c
DateAgo: c678b6435627f2b267980bc6f0a9969389686691
Fabric: 9cd6a848efcf1b8b07497e0b6a2e7d336353ba15
FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a
Firebase: 5ec5e863d269d82d66b4bf56856726f8fb8f0fb3
@@ -189,12 +198,13 @@ SPEC CHECKSUMS:
Pageboy: f0295ea949f0b0123a1b486fd347ea892d0078e0
SDWebImage: 76a6348bdc74eb5a55dd08a091ef298e56b55e41
SnapKit: a42d492c16e80209130a3379f73596c3454b7694
StringHelpers: 45c48929f335fa10b9e39ef48ba32ca2a72c89a7
StyledText: 18cf3224f09dab0c73223effe1ee2fdedefcfb8b
SwiftLint: a014c92b4664e8b13f380f8640a51bb1733778ba
SwipeCellKit: 67c91d4641d05b7e8ff1a38f57697d8c0fbcc6cc
Tabman: 69ce69b44cec1ad693b82c24cdbdf0c45915668c
TUSafariActivity: afc55a00965377939107ce4fdc7f951f62454546
PODFILE CHECKSUM: 53955f58848e544549039faf2ba2fbe9f0c942d8
PODFILE CHECKSUM: 0883a4fc29f4717acdde3419929842d158366a0f
COCOAPODS: 1.4.0

26
Pods/Local Podspecs/DateAgo.podspec.json generated Normal file
View File

@@ -0,0 +1,26 @@
{
"name": "DateAgo",
"version": "0.1.0",
"license": {
"type": "MIT"
},
"homepage": "https://github.com/GitHawkApp/githawk",
"authors": {
"Ryan Nystrom": "rnystrom@whoisryannystrom.com"
},
"summary": ".",
"source": {
"git": "https://github.com/GitHawkApp/githawk/githawk.git",
"tag": "#{s.version}"
},
"source_files": "DateAgo/*.swift",
"resource_bundles": {
"Resources": [
"DateAgo/Localizable.stringsdict"
]
},
"platforms": {
"ios": "11.0",
"watchos": "3.0"
}
}

View File

@@ -0,0 +1,21 @@
{
"name": "StringHelpers",
"version": "0.1.0",
"license": {
"type": "MIT"
},
"homepage": "https://github.com/GitHawkApp/githawk",
"authors": {
"Ryan Nystrom": "rnystrom@whoisryannystrom.com"
},
"summary": ".",
"source": {
"git": "https://github.com/GitHawkApp/githawk/githawk.git",
"tag": "#{s.version}"
},
"source_files": "StringHelpers/*.swift",
"platforms": {
"ios": "11.0",
"watchos": "3.0"
}
}

Some files were not shown because too many files have changed in this diff Show More