├── .gitignore
├── Canvas.xcodeproj
├── project.pbxproj
└── xcshareddata
│ └── xcschemes
│ ├── Canvas — Development.xcscheme
│ └── Canvas.xcscheme
├── Cartfile
├── Cartfile.resolved
├── LICENSE
├── Rakefile
├── Readme.markdown
├── Sources
├── APIClient+Canvas.swift
├── AlertController.swift
├── Analytics.swift
├── AppDelegate.swift
├── AuthorizationClient+Canvas.swift
├── AvatarView.swift
├── AvatarsView.swift
├── BannerView.swift
├── BillboardView.swift
├── CGRect+Canvas.swift
├── Canvas+Canvas.swift
├── CanvasActivitySource.swift
├── CanvasCell.swift
├── CanvasIconView.swift
├── CanvasTextView+Gestures.swift
├── CanvasTextView.swift
├── CanvasesResultsViewController.swift
├── CanvasesViewController.swift
├── ChromeActivity.swift
├── Color+Canvas.swift
├── Configuration.swift
├── CopyLinkActivity.swift
├── CopyLinkView.swift
├── CopyRepresentationActivity.swift
├── DestructiveValueCell.swift
├── DragBackgroundView.swift
├── DragContext.swift
├── DragProgressView.swift
├── EditorViewController+Actions.swift
├── EditorViewController+Connection.swift
├── EditorViewController.swift
├── FooterButton.swift
├── GrayButton.swift
├── GroupedSectionHeaderView.swift
├── IndicatorButton.swift
├── Interpolate.swift
├── LineView.swift
├── LoadCanvasViewController.swift
├── LogInViewController.swift
├── ModelsViewController.swift
├── NSDate+Canvas.swift
├── NSProcessInfo+Canvas.swift
├── NavigationBar.swift
├── NavigationController.swift
├── OAuthClient+Canvas.swift
├── OnboardingBillboardViewController.swift
├── OnboardingGesturesViewController.swift
├── OnboardingOrigamiViewController.swift
├── OnboardingSharingViewController.swift
├── OnboardingViewController.swift
├── OnboardingWelcomeViewController.swift
├── Organization+Canvas.swift
├── OrganizationAvatarView.swift
├── OrganizationCanvasesViewController.swift
├── OrganizationCell.swift
├── OrganizationsViewController.swift
├── PillButton.swift
├── PlaceholderViewController.swift
├── PrefaceButton.swift
├── PresenceViewController.swift
├── RefreshContentView.swift
├── RootViewController.swift
├── SafariActivity.swift
├── SearchBarContainer.swift
├── SectionHeaderView.swift
├── SessionFormViewController.swift
├── SettingsViewController.swift
├── SharedWebCredentials.swift
├── SignUpViewController.swift
├── SleepPickerViewController.swift
├── SleepPrevention.swift
├── SplitViewController.swift
├── StackViewController.swift
├── TableView.swift
├── TableViewController.swift
├── TextField.swift
├── TextView.swift
├── TickingLabel.swift
├── TintableEnvironment.swift
├── TintableView.swift
├── TitleView.swift
├── UIActivity+Canvas.swift
├── UIColor+Canvas.swift
├── UIEdgeInsets+Canvas.swift
├── UIFont+Canvas.swift
├── UISplitViewController+Canvas.swift
├── UIViewController+Canvas.swift
├── UserCell.swift
├── ValueCell.swift
├── VerifyViewController.swift
├── WebActivity.swift
└── WebViewController.swift
├── Support
├── Assets.xcassets
│ ├── 1Password.imageset
│ │ ├── 1Password.pdf
│ │ └── Contents.json
│ ├── Activity Icons
│ │ ├── Chrome.imageset
│ │ │ ├── Chrome.pdf
│ │ │ ├── Chrome~iPad.pdf
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── Copy HTML.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Copy HTML.pdf
│ │ │ └── Copy HTML~iPad.pdf
│ │ ├── Copy JSON.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Copy JSON.pdf
│ │ │ └── Copy JSON~iPad.pdf
│ │ ├── Copy Link.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Copy Link.pdf
│ │ │ └── Copy Link~iPad.pdf
│ │ ├── Copy Markdown.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Copy Markdown.pdf
│ │ │ └── Copy Markdown~iPad.pdf
│ │ └── Safari.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Safari.pdf
│ │ │ └── Safari~iPad.pdf
│ ├── AppIcon-Dev.appiconset
│ │ ├── Contents.json
│ │ ├── Settings.png
│ │ ├── Settings@2x-1.png
│ │ ├── Settings@2x.png
│ │ ├── Settings@3x.png
│ │ ├── Spotlight.png
│ │ ├── Spotlight@2x-1.png
│ │ ├── Spotlight@2x.png
│ │ ├── Spotlight@3x.png
│ │ ├── iPad Pro@2x.png
│ │ ├── iPad.png
│ │ ├── iPad@2x.png
│ │ ├── iPhone@2x.png
│ │ └── iPhone@3x.png
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Settings.png
│ │ ├── Settings@2x-1.png
│ │ ├── Settings@2x.png
│ │ ├── Settings@3x.png
│ │ ├── Spotlight.png
│ │ ├── Spotlight@2x-1.png
│ │ ├── Spotlight@2x.png
│ │ ├── Spotlight@3x.png
│ │ ├── iPad Pro@2x.png
│ │ ├── iPad.png
│ │ ├── iPad@2x.png
│ │ ├── iPhone@2x.png
│ │ └── iPhone@3x.png
│ ├── Contents.json
│ ├── Document Icons
│ │ ├── Contents.json
│ │ ├── Document Globe-Background.imageset
│ │ │ ├── Contents.json
│ │ │ └── Document Globe-Background.pdf
│ │ ├── Document Globe.imageset
│ │ │ ├── Contents.json
│ │ │ └── Document Globe.pdf
│ │ ├── Document-Blank.imageset
│ │ │ ├── Contents.json
│ │ │ └── empty-document.pdf
│ │ └── Document.imageset
│ │ │ ├── Contents.json
│ │ │ └── document.pdf
│ ├── Gesture Icons
│ │ ├── CheckList.imageset
│ │ │ ├── CheckList.pdf
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── Heading2.imageset
│ │ │ ├── Contents.json
│ │ │ └── Heading2.pdf
│ │ ├── Heading3.imageset
│ │ │ ├── Contents.json
│ │ │ └── Heading3.pdf
│ │ ├── Indent.imageset
│ │ │ ├── Contents.json
│ │ │ └── Indent.pdf
│ │ ├── OrderedList.imageset
│ │ │ ├── Contents.json
│ │ │ └── OrderedList.pdf
│ │ ├── Outdent.imageset
│ │ │ ├── Contents.json
│ │ │ └── Outdent.pdf
│ │ └── Paragraph.imageset
│ │ │ ├── Contents.json
│ │ │ └── Paragraph.pdf
│ ├── Icon-Small.imageset
│ │ ├── Contents.json
│ │ └── Icon-Small.pdf
│ ├── Illustration.imageset
│ │ ├── Contents.json
│ │ └── Illustration.pdf
│ ├── IllustrationLight.imageset
│ │ ├── Contents.json
│ │ └── IllustrationLight.pdf
│ ├── Illustrations
│ │ ├── Contents.json
│ │ ├── Email.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Email@2x.png
│ │ │ └── Email@3x.png
│ │ ├── No Participants.imageset
│ │ │ ├── Contents.json
│ │ │ ├── No Participants.png
│ │ │ ├── No Participants@2x.png
│ │ │ └── No Participants@3x.png
│ │ └── Not Found.imageset
│ │ │ ├── 404 Illustration.png
│ │ │ ├── 404 Illustration@2x.png
│ │ │ ├── 404 Illustration@3x.png
│ │ │ └── Contents.json
│ ├── New Canvas Shortcut.imageset
│ │ ├── Compose-Shortcut.pdf
│ │ └── Contents.json
│ ├── Onboarding
│ │ ├── Contents.json
│ │ ├── GesturesCompact.imageset
│ │ │ ├── Contents.json
│ │ │ ├── GesturesCompact@2x.png
│ │ │ ├── GesturesCompact@2x~iPad.png
│ │ │ └── GesturesCompact@3x.png
│ │ ├── GesturesRegular.imageset
│ │ │ ├── Contents.json
│ │ │ └── GesturesRegular@2x~iPad.png
│ │ ├── OrigamiCompact.imageset
│ │ │ ├── Contents.json
│ │ │ ├── OrigamiCompact@2x.png
│ │ │ ├── OrigamiCompact@2x~iPad.png
│ │ │ └── OrigamiCompact@3x.png
│ │ ├── OrigamiRegular.imageset
│ │ │ ├── Contents.json
│ │ │ └── OrigamiRegular@2x~iPad.png
│ │ ├── ShareCompact.imageset
│ │ │ ├── Contents.json
│ │ │ ├── ShareCompact@2x.png
│ │ │ ├── ShareCompact@2x~iPad.png
│ │ │ └── ShareCompact@3x.png
│ │ ├── ShareRegular.imageset
│ │ │ ├── Contents.json
│ │ │ └── ShareRegular@2x~iPad.png
│ │ ├── WelcomeCompact.imageset
│ │ │ ├── Contents.json
│ │ │ ├── WelcomeCompact@2x.png
│ │ │ ├── WelcomeCompact@2x~iPad.png
│ │ │ └── WelcomeCompact@3x.png
│ │ └── WelcomeRegular.imageset
│ │ │ ├── Contents.json
│ │ │ └── WelcomeRegular@2x~iPad.png
│ ├── Primaries
│ │ ├── ChevronLeft.imageset
│ │ │ ├── ChevronLeft.pdf
│ │ │ └── Contents.json
│ │ ├── ChevronRightSmall.imageset
│ │ │ ├── ChevronRightSmall.pdf
│ │ │ └── Contents.json
│ │ ├── Close.imageset
│ │ │ ├── Close.pdf
│ │ │ └── Contents.json
│ │ ├── Compose.imageset
│ │ │ ├── Compose.pdf
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── Gear.imageset
│ │ │ ├── Contents.json
│ │ │ └── Gear.pdf
│ │ ├── Help.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Help@2x.png
│ │ │ └── Help@3x.png
│ │ ├── Lock.imageset
│ │ │ ├── Contents.json
│ │ │ └── Lock.pdf
│ │ ├── Moon.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Moon@2x.png
│ │ │ └── Moon@3x.png
│ │ ├── More.imageset
│ │ │ ├── Contents.json
│ │ │ └── More.pdf
│ │ ├── SearchSmall.imageset
│ │ │ ├── Contents.json
│ │ │ └── SearchSmall.pdf
│ │ ├── SidebarLeft.imageset
│ │ │ ├── Contents.json
│ │ │ └── SidebarLeft.pdf
│ │ ├── SignOut.imageset
│ │ │ ├── Contents.json
│ │ │ ├── SignOut@2x.png
│ │ │ └── SignOut@3x.png
│ │ ├── User.imageset
│ │ │ ├── Contents.json
│ │ │ ├── User@2x.png
│ │ │ └── User@3x.png
│ │ └── Username.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Username@2x.png
│ │ │ └── Username@3x.png
│ └── Pull To Refresh
│ │ ├── Contents.json
│ │ ├── RefreshViewBackground.imageset
│ │ ├── Background.pdf
│ │ └── Contents.json
│ │ ├── RefreshViewGradient.imageset
│ │ ├── Contents.json
│ │ └── Gradient 2.pdf
│ │ └── RefreshViewOutline.imageset
│ │ ├── Contents.json
│ │ └── Outline.pdf
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Canvas Dev.entitlements
├── Canvas.entitlements
├── Info.plist
├── Settings.bundle
│ ├── Root.plist
│ └── en.lproj
│ │ └── Root.strings
├── UITests-Info.plist
└── apple-app-site-association.json
├── UITests
├── SnapshotHelper.swift
└── Snapshots.swift
└── fastlane
├── Appfile
├── Deliverfile
├── Fastfile
├── README.md
├── metadata
├── copyright.txt
├── en-US
│ ├── description.txt
│ ├── keywords.txt
│ ├── marketing_url.txt
│ ├── name.txt
│ ├── privacy_url.txt
│ ├── release_notes.txt
│ └── support_url.txt
├── primary_category.txt
└── secondary_category.txt
└── screenshots
├── README.txt
└── en-US
├── ipadPro_1.png
├── ipadPro_2.png
├── ipadPro_3.png
├── ipad_1.png
├── ipad_2.png
├── ipad_3.png
├── iphone35_1.png
├── iphone35_2.png
├── iphone35_3.png
├── iphone35_4.png
├── iphone35_5.png
├── iphone4_1.png
├── iphone4_2.png
├── iphone4_3.png
├── iphone4_4.png
├── iphone4_5.png
├── iphone6Plus_1.png
├── iphone6Plus_2.png
├── iphone6Plus_3.png
├── iphone6Plus_4.png
├── iphone6Plus_5.png
├── iphone6_1.png
├── iphone6_2.png
├── iphone6_3.png
├── iphone6_4.png
└── iphone6_5.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X
2 | .DS_Store
3 |
4 | # Xcode
5 | *xcuserdata/
6 | *.mode1v3
7 | *.pbxuser
8 | *.xcworkspace
9 |
10 | # Carthage
11 | Carthage
12 |
13 | # Fastlane
14 | fastlane/report.xml
15 | fastlane/Preview.html
16 | fastlane/test_output
17 | Preview.html
18 |
19 | # Products
20 | *.zip
21 | *.ipa
22 |
--------------------------------------------------------------------------------
/Canvas.xcodeproj/xcshareddata/xcschemes/Canvas — Development.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/Cartfile:
--------------------------------------------------------------------------------
1 | github "intercom/intercom-ios"
2 | github "soffes/GradientView"
3 | github "soffes/Mixpanel"
4 | github "soffes/SSPullToRefresh" "v2.0.0-beta.2"
5 | github "usecanvas/CanvasCore" "master"
6 | github "usecanvas/onepassword-app-extension"
7 | github "usecanvas/sentry-swift"
8 | github "venmo/Static"
9 |
--------------------------------------------------------------------------------
/Cartfile.resolved:
--------------------------------------------------------------------------------
1 | github "soffes/Cache" "v0.1.0"
2 | github "soffes/CommonCrypto" "v1.0"
3 | github "soffes/Diff" "v0.1.2"
4 | github "soffes/GradientView" "v2.1.1"
5 | github "soffes/ISO8601" "v0.6.0"
6 | github "usecanvas/KSCrash" "1.6.4"
7 | github "soffes/Mixpanel" "v0.1.1"
8 | github "usecanvas/OperationalTransformation" "v0.1.1"
9 | github "soffes/SAMKeychain" "v1.5.0"
10 | github "soffes/SSPullToRefresh" "v2.0.0-beta.2"
11 | github "usecanvas/Starscream" "1.1.3"
12 | github "venmo/Static" "v1.1.1"
13 | github "soffes/X" "v0.3.1"
14 | github "intercom/intercom-ios" "3.0.10"
15 | github "usecanvas/onepassword-app-extension" "framework/1.8.2"
16 | github "usecanvas/CanvasKit" "v0.5.0"
17 | github "usecanvas/CanvasNative" "v0.1.2"
18 | github "soffes/Crypto" "v0.4.0"
19 | github "usecanvas/sentry-swift" "0.3.1"
20 | github "usecanvas/CanvasText" "566bd91dda39ac98960cb6aafaf16f48a073be7f"
21 | github "usecanvas/CanvasCore" "6948ef3d63925a33b7e37c1aae65f0ad9895b809"
22 |
--------------------------------------------------------------------------------
/Readme.markdown:
--------------------------------------------------------------------------------
1 | # Canvas for iOS
2 |
3 | Canvas client for iOS V1.
4 |
5 | *Note:* This app was designed to work against V1 of Canvas, which is not released. There is no iOS client for V2. This repo is open sourced for reference only.
6 |
7 |
8 | ## Building
9 |
10 | You will need [Xcode](https://itunes.apple.com/app/xcode/id497799835) 7.3.1 and [Carthage](https://github.com/carthage/carthage) 0.17.2 to build Canvas for iOS. You should ensure you have Xcode installed before beginning since that can take quite awhile. Be sure to open it at least once after downloading it.
11 |
12 | 1. Clone the code.
13 |
14 | $ git clone https://github.com/usecanvas/ios-v1
15 | $ cd ios-v1
16 |
17 | 2. Now, simply run the following command:
18 |
19 | $ rake bootstrap
20 |
21 | This will walk you through setting up everything you need to build Canvas for iOS.
22 |
23 | 3. Open `Canvas.xcodeproj` and click ▶️
24 |
25 | If you have trouble building, quit Xcode, run `rake clean bootstrap`, and open Xcode again. If you are still having trouble, ask @soffes in Slack.
26 |
27 |
28 | ## Running
29 |
30 | By default, the app will use the production services. You can change this in `Configuration.swift` at the bottom.
31 |
--------------------------------------------------------------------------------
/Sources/APIClient+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // APIClient+Canvas.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/22/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import CanvasCore
10 | import CanvasKit
11 |
12 | extension CanvasCore.APIClient {
13 | convenience init(account: Account) {
14 | self.init(account: account, config: config)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/AlertController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AlertController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 11/27/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 |
12 | final class AlertController: UIAlertController {
13 |
14 | // MARK: - Properties
15 |
16 | /// Used when return is pressed while the controller is showing
17 | var primaryAction: (Void -> Void)?
18 |
19 |
20 | // MARK: - UIResponder
21 |
22 | override func canBecomeFirstResponder() -> Bool {
23 | return true
24 | }
25 |
26 | override var keyCommands: [UIKeyCommand]? {
27 | return (super.keyCommands ?? []) + [
28 | UIKeyCommand(input: UIKeyInputEscape, modifierFlags: [], action: #selector(cancel)),
29 | UIKeyCommand(input: "\r", modifierFlags: [], action: #selector(selectFirstAction))
30 | ]
31 | }
32 |
33 |
34 | // MARK: - UIViewController
35 |
36 | override func viewWillAppear(animated: Bool) {
37 | super.viewWillAppear(animated)
38 |
39 | adjustSubviews([view])
40 | }
41 |
42 |
43 | // MARK: - Actions
44 |
45 | func cancel(sender: AnyObject?) {
46 | dismissViewControllerAnimated(true, completion: nil)
47 | }
48 |
49 | func selectFirstAction(sender: AnyObject?) {
50 | dismissViewControllerAnimated(true) {
51 | self.primaryAction?()
52 | }
53 | }
54 |
55 |
56 | // MARK: - Private
57 |
58 | private func adjustSubviews(subviews: [UIView]) {
59 | for subview in subviews {
60 | if let label = subview as? UILabel {
61 | adjustLabel(label)
62 | } else if subview.bounds.height > 0 && subview.bounds.height <= 1 {
63 | subview.backgroundColor = Swatch.border
64 | }
65 |
66 | adjustSubviews(subview.subviews)
67 | }
68 | }
69 |
70 | private func adjustLabel(label: UILabel) {
71 | for action in actions {
72 | if label.text == title {
73 | label.attributedText = NSAttributedString(string: label.text ?? "", attributes: [
74 | NSFontAttributeName: label.font,
75 | NSForegroundColorAttributeName: Swatch.darkGray
76 | ])
77 | return
78 | }
79 |
80 | if label.text == action.title {
81 | switch action.style {
82 | case .Default, .Cancel:
83 | label.attributedText = NSAttributedString(string: label.text ?? "", attributes: [
84 | NSFontAttributeName: label.font,
85 | NSForegroundColorAttributeName: Swatch.brand
86 | ])
87 | case .Destructive:
88 | label.attributedText = NSAttributedString(string: label.text ?? "", attributes: [
89 | NSFontAttributeName: label.font,
90 | NSForegroundColorAttributeName: Swatch.destructive
91 | ])
92 | }
93 | }
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/Sources/Analytics.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Analytics.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 11/25/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import Mixpanel
10 | import Intercom
11 | import CanvasKit
12 | import CanvasCore
13 |
14 | struct Analytics {
15 |
16 | // MARK: - Types
17 |
18 | enum Event {
19 | case LoggedOut
20 | case LoggedIn
21 | case LaunchedApp
22 | case ChangedOrganization(organization: Organization)
23 | case OpenedCanvas
24 |
25 | var name: String {
26 | switch self {
27 | case .LoggedOut: return "Logged Out"
28 | case .LoggedIn: return "Logged In"
29 | case .LaunchedApp: return "Launched App"
30 | case .ChangedOrganization(_): return "Changed Organization"
31 | case .OpenedCanvas: return "Opened Canvas"
32 | }
33 | }
34 |
35 | var parameters: [String: AnyObject]? {
36 | switch self {
37 | case .ChangedOrganization(let organization): return ["organization_name": organization.name]
38 | default: return nil
39 | }
40 | }
41 | }
42 |
43 |
44 | // MARK: - Properties
45 |
46 | private static let mixpanel: Mixpanel = {
47 | var mp = Mixpanel(token: config.mixpanelToken)
48 |
49 | let uniqueIdentifier: String
50 | let key = "Identifier"
51 | if let identifier = NSUserDefaults.standardUserDefaults().stringForKey(key) {
52 | uniqueIdentifier = identifier
53 | } else {
54 | let identifier = NSUUID().UUIDString
55 | NSUserDefaults.standardUserDefaults().setObject(identifier, forKey: key)
56 | uniqueIdentifier = identifier
57 | }
58 |
59 | mp.identify(uniqueIdentifier)
60 |
61 | #if DEBUG
62 | mp.enabled = false
63 | #endif
64 |
65 | return mp
66 | }()
67 |
68 |
69 | // MARK: - Tracking
70 |
71 | static func track(event: Event) {
72 | // Params
73 | let params = event.parameters ?? [:]
74 | var mixpanelParams = params
75 |
76 | // Current user
77 | if let account = AccountController.sharedController.currentAccount {
78 | mixpanelParams["id"] = account.user.id
79 | mixpanelParams["$username"] = account.user.username
80 | }
81 |
82 | // Mixpanel
83 | mixpanel.track(event.name, parameters: mixpanelParams)
84 |
85 | // Intercom
86 | var intercomParams = params
87 | intercomParams["source"] = "ios"
88 | Intercom.logEventWithName(event.name, metaData: params)
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Sources/AuthorizationClient+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AuthorizationClient.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/19/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import CanvasKit
10 |
11 | extension AuthorizationClient {
12 | init() {
13 | self.init(clientID: config.canvasClientID, clientSecret: config.canvasClientSecret, baseURL: config.environment.apiURL)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/AvatarView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AvatarView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 6/8/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasKit
12 |
13 | final class AvatarView: UIImageView {
14 |
15 | // MARK: - Properties
16 |
17 | var user: User? {
18 | didSet {
19 | updateAvatar()
20 | }
21 | }
22 |
23 |
24 | // MARK: - Initializers
25 |
26 | init(user: User? = nil) {
27 | self.user = user
28 |
29 | super.init(frame: .zero)
30 |
31 | backgroundColor = Swatch.lightGray
32 | layer.cornerRadius = 16
33 | layer.masksToBounds = true
34 |
35 | updateAvatar()
36 | }
37 |
38 | required init?(coder aDecoder: NSCoder) {
39 | fatalError("init(coder:) has not been implemented")
40 | }
41 |
42 |
43 | // MARK: - UIView
44 |
45 | override func intrinsicContentSize() -> CGSize {
46 | return CGSize(width: 32, height: 32)
47 | }
48 |
49 |
50 | // MARK: - Private
51 |
52 | private func updateAvatar() {
53 | guard let user = user, url = user.avatarURL.flatMap(imgix) else {
54 | image = nil
55 | return
56 | }
57 |
58 | image = AvatarsController.sharedController.fetchImage(id: user.id, url: url) { [weak self] id, image in
59 | if id == self?.user?.id {
60 | self?.image = image
61 | }
62 | }
63 | }
64 |
65 | private func imgix(url: NSURL) -> NSURL? {
66 | let parameters = [
67 | NSURLQueryItem(name: "dpr", value: "\(Int(traitCollection.displayScale))"),
68 | NSURLQueryItem(name: "w", value: "\(32)"),
69 | NSURLQueryItem(name: "h", value: "\(32)"),
70 | NSURLQueryItem(name: "fit", value: "crop"),
71 | NSURLQueryItem(name: "crop", value: "faces")
72 | ]
73 |
74 | return ImgixController.sign(url: url, parameters: parameters, configuration: config)
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Sources/AvatarsView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AvatarsView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 6/8/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasKit
11 |
12 | final class AvatarsView: UIStackView {
13 |
14 | // MARK: - Properties
15 |
16 | var users = [User]() {
17 | didSet {
18 | arrangedSubviews.forEach { $0.removeFromSuperview() }
19 |
20 | for user in users {
21 | let view = AvatarView(user: user)
22 | addArrangedSubview(view)
23 | }
24 | }
25 | }
26 |
27 |
28 | // MARK: - Initializers
29 |
30 | convenience init() {
31 | self.init(frame: .zero)
32 | }
33 |
34 | override init(frame: CGRect) {
35 | super.init(frame: frame)
36 |
37 | axis = .Vertical
38 | spacing = 8
39 | }
40 |
41 | required init?(coder aDecoder: NSCoder) {
42 | fatalError("init(coder:) has not been implemented")
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Sources/BannerView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BannerView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/1/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasText
12 |
13 | final class BannerView: UIView {
14 |
15 | // MARK: - Types
16 |
17 | enum Style {
18 | case success
19 | case info
20 | case failure
21 |
22 | var foregroundColor: UIColor {
23 | return Swatch.white
24 | }
25 |
26 | var backgroundColor: UIColor {
27 | switch self {
28 | case .success: return Swatch.green
29 | case .info: return Swatch.darkGray
30 | case .failure: return Swatch.destructive
31 | }
32 | }
33 | }
34 |
35 |
36 | // MARK: - Properties
37 |
38 | let textLabel: UILabel = {
39 | let label = UILabel()
40 | label.translatesAutoresizingMaskIntoConstraints = false
41 | label.numberOfLines = 0
42 | label.textAlignment = .Center
43 | return label
44 | }()
45 |
46 |
47 | // MARK: - Initializers
48 |
49 | init(style: Style) {
50 | super.init(frame: .zero)
51 |
52 | backgroundColor = style.backgroundColor
53 |
54 | textLabel.textColor = style.foregroundColor
55 | addSubview(textLabel)
56 |
57 | NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(updateFont), name: UIContentSizeCategoryDidChangeNotification, object: nil)
58 | updateFont()
59 |
60 | NSLayoutConstraint.activateConstraints([
61 | textLabel.centerXAnchor.constraintEqualToAnchor(centerXAnchor),
62 | textLabel.centerYAnchor.constraintEqualToAnchor(centerYAnchor),
63 | textLabel.leadingAnchor.constraintGreaterThanOrEqualToAnchor(leadingAnchor, constant: 16),
64 | textLabel.trailingAnchor.constraintLessThanOrEqualToAnchor(trailingAnchor, constant: -16),
65 | textLabel.topAnchor.constraintGreaterThanOrEqualToAnchor(topAnchor, constant: 12),
66 | textLabel.bottomAnchor.constraintGreaterThanOrEqualToAnchor(bottomAnchor, constant: -12),
67 | ])
68 | }
69 |
70 | required init?(coder aDecoder: NSCoder) {
71 | fatalError("init(coder:) has not been implemented")
72 | }
73 |
74 |
75 | // MARK: - Private
76 |
77 | @objc private func updateFont() {
78 | textLabel.font = TextStyle.callout.font(weight: .medium)
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Sources/BillboardView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BillboardView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/5/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasText
12 |
13 | final class BillboardView: UIStackView {
14 |
15 | // MARK: - Properties
16 |
17 | let illustrationView = UIImageView()
18 |
19 | let titleLabel: UILabel = {
20 | let label = UILabel()
21 | label.textColor = Swatch.black
22 | return label
23 | }()
24 |
25 | let subtitleLabel: UILabel = {
26 | let label = UILabel()
27 | label.textColor = Swatch.darkGray
28 | label.numberOfLines = 0
29 | label.textAlignment = .Center
30 | return label
31 | }()
32 |
33 |
34 | // MARK: - Initializers
35 |
36 | convenience init() {
37 | self.init(frame: .zero)
38 | }
39 |
40 | override init(frame: CGRect) {
41 | super.init(frame: frame)
42 |
43 | axis = .Vertical
44 | alignment = .Center
45 | layoutMargins = UIEdgeInsets(top: 16, left: 32, bottom: 16, right: 32)
46 | layoutMarginsRelativeArrangement = true
47 |
48 | addArrangedSubview(illustrationView)
49 | addSpace(32)
50 | addArrangedSubview(titleLabel)
51 | addSpace(8)
52 | addArrangedSubview(subtitleLabel)
53 |
54 | NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(updateFonts), name: UIContentSizeCategoryDidChangeNotification, object: nil)
55 | updateFonts()
56 | }
57 |
58 | required init?(coder aDecoder: NSCoder) {
59 | fatalError("init(coder:) has not been implemented")
60 | }
61 |
62 |
63 | // MARK: - Private
64 |
65 | @objc private func updateFonts() {
66 | titleLabel.font = TextStyle.title1.font()
67 | subtitleLabel.font = TextStyle.body.font()
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Sources/CGRect+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGRect+Canvas.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 11/26/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import CoreGraphics
10 |
11 | extension CGRect {
12 | var floor: CGRect {
13 | return CGRect(
14 | x: CoreGraphics.floor(origin.x),
15 | y: CoreGraphics.floor(origin.y),
16 | width: CoreGraphics.floor(size.width),
17 | height: CoreGraphics.floor(size.height)
18 | )
19 | }
20 |
21 | var ceil: CGRect {
22 | return CGRect(
23 | x: CoreGraphics.ceil(origin.x),
24 | y: CoreGraphics.ceil(origin.y),
25 | width: CoreGraphics.ceil(size.width),
26 | height: CoreGraphics.ceil(size.height)
27 | )
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/Canvas+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Canvas+Canvas.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 12/2/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasKit
12 | import Static
13 |
14 | extension Canvas {
15 | enum Kind {
16 | case Document
17 | case Blank
18 |
19 | var icon: UIImage! {
20 | switch self {
21 | case .Document: return UIImage(named: "Document")
22 | case .Blank: return UIImage(named: "Document-Blank")
23 | }
24 | }
25 | }
26 |
27 | var row: Row {
28 | return Row(
29 | text: displayTitle,
30 | detailText: summary,
31 | cellClass: CanvasCell.self,
32 | context: ["canvas": self]
33 | )
34 | }
35 |
36 | var kind: Kind {
37 | return isEmpty ? .Blank : .Document
38 | }
39 |
40 | var displayTitle: String {
41 | return title.isEmpty ? LocalizedString.Untitled.string : title
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sources/CanvasActivitySource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CanvasActivitySource.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/18/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasKit
11 |
12 | final class CanvasActivitySource: NSObject {
13 |
14 | // MARK: - Properties
15 |
16 | private let title: String
17 | private let url: NSURL
18 |
19 |
20 | // MARK: - Initializers
21 |
22 | init?(canvas: Canvas) {
23 | guard let url = canvas.url else { return nil }
24 |
25 | title = canvas.title
26 | self.url = url
27 |
28 | super.init()
29 | }
30 | }
31 |
32 |
33 | extension CanvasActivitySource: UIActivityItemSource {
34 | func activityViewControllerPlaceholderItem(activityViewController: UIActivityViewController) -> AnyObject {
35 | return url
36 | }
37 |
38 | func activityViewController(activityViewController: UIActivityViewController, itemForActivityType activityType: String) -> AnyObject? {
39 | switch activityType {
40 | case UIActivityTypePostToFacebook, UIActivityTypePostToTwitter, UIActivityTypePostToWeibo, UIActivityTypeMessage, UIActivityTypeMail, UIActivityTypePostToTencentWeibo:
41 | return "\(title) — \(url)"
42 | case UIActivityTypeAirDrop:
43 | return url
44 | default:
45 | return url
46 | }
47 | }
48 |
49 | func activityViewController(activityViewController: UIActivityViewController, subjectForActivityType activityType: String?) -> String {
50 | // TODO: Localize
51 | return "Check out this Canvas"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Sources/CanvasTextView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CanvasTextView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 4/19/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasNative
12 | import CanvasText
13 |
14 | protocol CanvasTextViewFormattingDelegate: class {
15 | func textViewDidToggleBoldface(textView: CanvasTextView, sender: AnyObject?)
16 | func textViewDidToggleItalics(textView: CanvasTextView, sender: AnyObject?)
17 | }
18 |
19 | final class CanvasTextView: TextView {
20 |
21 | // MARK: - Properties
22 |
23 | weak var textController: TextController? {
24 | didSet {
25 | guard let theme = textController?.theme else { return }
26 |
27 | var attributes = theme.titleAttributes
28 | attributes[NSForegroundColorAttributeName] = theme.titlePlaceholderColor
29 |
30 | placeholderLabel.attributedText = NSAttributedString(
31 | string: LocalizedString.CanvasTitlePlaceholder.string,
32 | attributes: attributes
33 | )
34 | }
35 | }
36 |
37 | weak var formattingDelegate: CanvasTextViewFormattingDelegate?
38 |
39 | let dragGestureRecognizer: UIPanGestureRecognizer
40 | let dragThreshold: CGFloat = 60
41 | var dragContext: DragContext?
42 |
43 | let placeholderLabel: UILabel = {
44 | let label = UILabel()
45 | label.userInteractionEnabled = false
46 | label.hidden = true
47 | return label
48 | }()
49 |
50 |
51 | // MARK: - Initializers
52 |
53 | override init(frame: CGRect, textContainer: NSTextContainer?) {
54 | dragGestureRecognizer = UIPanGestureRecognizer()
55 |
56 | super.init(frame: frame, textContainer: textContainer)
57 |
58 | // allowsEditingTextAttributes = true
59 | alwaysBounceVertical = true
60 | keyboardDismissMode = .Interactive
61 | backgroundColor = .clearColor()
62 |
63 | registerGestureRecognizers()
64 |
65 | managedSubviews.insert(placeholderLabel)
66 | addSubview(placeholderLabel)
67 | }
68 |
69 | required init?(coder aDecoder: NSCoder) {
70 | fatalError("init(coder:) has not been implemented")
71 | }
72 |
73 |
74 | // MARK: - UIResponder
75 |
76 | override func toggleBoldface(sender: AnyObject?) {
77 | formattingDelegate?.textViewDidToggleBoldface(self, sender: sender)
78 | }
79 |
80 | override func toggleItalics(sender: AnyObject?) {
81 | formattingDelegate?.textViewDidToggleItalics(self, sender: sender)
82 | }
83 |
84 | override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
85 | // Disable underline
86 | if action == #selector(toggleUnderline) {
87 | return false
88 | }
89 |
90 | return super.canPerformAction(action, withSender: sender)
91 | }
92 |
93 |
94 | // MARK: - UIView
95 |
96 | override func layoutSubviews() {
97 | super.layoutSubviews()
98 | layoutPlaceholder()
99 | }
100 |
101 | override func tintColorDidChange() {
102 | super.tintColorDidChange()
103 |
104 | textController?.setTintColor(tintColor)
105 | }
106 |
107 |
108 | // MARK: - Private
109 |
110 | private func layoutPlaceholder() {
111 | placeholderLabel.sizeToFit()
112 |
113 | var frame = placeholderLabel.frame
114 | frame.origin.x = textContainerInset.left
115 | frame.origin.y = textContainerInset.top
116 | placeholderLabel.frame = frame
117 | }
118 | }
119 |
120 |
121 | extension CanvasTextView: TextControllerAnnotationDelegate {
122 | func textController(textController: TextController, willAddAnnotation annotation: Annotation) {
123 | annotation.view.backgroundColor = .clearColor()
124 | managedSubviews.insert(annotation.view)
125 | insertSubview(annotation.view, atIndex: 0)
126 | }
127 |
128 | func textController(textController: TextController, willRemoveAnnotation annotation: Annotation) {
129 | managedSubviews.remove(annotation.view)
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/Sources/CanvasesResultsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CanvasesResultsViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 12/9/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasKit
12 |
13 | final class CanvasesResultsViewController: CanvasesViewController {
14 |
15 | // MARK: - UIViewController
16 |
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 |
20 | canRefresh = false
21 |
22 | let line = LineView()
23 | line.translatesAutoresizingMaskIntoConstraints = false
24 | view.addSubview(line)
25 |
26 | NSLayoutConstraint.activateConstraints([
27 | // Add search bar height :(
28 | line.topAnchor.constraintEqualToAnchor(topLayoutGuide.bottomAnchor, constant: 44),
29 |
30 | line.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor),
31 | line.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor)
32 | ])
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Sources/CanvasesViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CanvasesViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 12/8/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Static
11 | import CanvasCore
12 | import CanvasKit
13 | import CanvasNative
14 |
15 | class CanvasesViewController: ModelsViewController, Accountable {
16 |
17 | // MARK: - Properties
18 |
19 | var account: Account
20 |
21 |
22 | // MARK: - Initializers
23 |
24 | init(account: Account, style: UITableViewStyle = .Plain) {
25 | self.account = account
26 | super.init(style: style)
27 | }
28 |
29 | required init?(coder aDecoder: NSCoder) {
30 | fatalError("init(coder:) has not been implemented")
31 | }
32 |
33 |
34 | // MARK: - UIViewController
35 |
36 | override func viewDidLoad() {
37 | super.viewDidLoad()
38 |
39 | tableView.rowHeight = 72
40 |
41 | navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .Plain, target: nil, action: nil)
42 | }
43 |
44 |
45 | // MARK: - ModelsViewController
46 |
47 | func openCanvas(canvas: Canvas) {
48 | guard !opening else { return }
49 |
50 | if let editor = currentEditor() where editor.canvas == canvas {
51 | return
52 | }
53 |
54 | opening = true
55 |
56 | if !CanvasNative.supports(nativeVersion: canvas.nativeVersion) {
57 | if let indexPath = tableView.indexPathForSelectedRow {
58 | tableView.deselectRowAtIndexPath(indexPath, animated: true)
59 | }
60 |
61 | let alert = UIAlertController(title: LocalizedString.UnsupportedTitle.string, message: LocalizedString.UnsupportedMessage.string, preferredStyle: .Alert)
62 |
63 | #if !APP_STORE
64 | alert.addAction(UIAlertAction(title: LocalizedString.CheckForUpdatesButton.string, style: .Default, handler: { _ in
65 | UIApplication.sharedApplication().openURL(config.updatesURL)
66 | }))
67 | #endif
68 |
69 | alert.addAction(UIAlertAction(title: LocalizedString.OpenInSafariButton.string, style: .Default, handler: { _ in
70 | guard let url = canvas.url else { return }
71 | UIApplication.sharedApplication().openURL(url)
72 | }))
73 | alert.addAction(UIAlertAction(title: LocalizedString.Cancel.string, style: .Cancel, handler: nil))
74 |
75 | opening = false
76 | presentViewController(alert, animated: true, completion: nil)
77 |
78 | return
79 | }
80 |
81 | Analytics.track(.OpenedCanvas)
82 | let viewController = EditorViewController(account: account, canvas: canvas)
83 | showDetailViewController(NavigationController(rootViewController: viewController), sender: self)
84 |
85 | dispatch_async(dispatch_get_main_queue()) { [weak self] in
86 | self?.opening = false
87 | }
88 | }
89 |
90 |
91 | // MARK: - Utilities
92 |
93 | func currentEditor() -> EditorViewController? {
94 | guard let splitViewController = splitViewController where splitViewController.viewControllers.count == 2 else { return nil }
95 | return (splitViewController.viewControllers.last as? UINavigationController)?.topViewController as? EditorViewController
96 | }
97 |
98 | func rowForCanvas(canvas: Canvas) -> Row {
99 | var row = canvas.row
100 | row.selection = { [weak self] in self?.openCanvas(canvas) }
101 | return row
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/Sources/ChromeActivity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChromeActivity.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 11/18/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class ChromeActivity: WebActivity {
12 |
13 | // MARK: - UIActivity
14 |
15 | override func activityType() -> String? {
16 | return "open-in-chrome"
17 | }
18 |
19 | override func activityTitle() -> String? {
20 | return "Open in Chrome"
21 | }
22 |
23 | override func activityImage() -> UIImage? {
24 | return UIImage(named: "Chrome")
25 | }
26 |
27 | override func canPerformWithActivityItems(activityItems: [AnyObject]) -> Bool {
28 | for activityItem in activityItems {
29 | if let activityURL = activityItem as? NSURL, chromeScheme = chromeSchemeForURL(activityURL), chromeURL = NSURL(string: "\(chromeScheme)://") where UIApplication.sharedApplication().canOpenURL(chromeURL) {
30 | return true
31 | }
32 | }
33 |
34 | return false
35 | }
36 |
37 | override func performActivity() {
38 | guard let URL = self.URL else {
39 | activityDidFinish(false)
40 | return
41 | }
42 |
43 |
44 | guard let components = NSURLComponents(URL: URL, resolvingAgainstBaseURL: true),
45 | chromeScheme = chromeSchemeForURL(URL)
46 | else {
47 | activityDidFinish(false)
48 | return
49 | }
50 |
51 | components.scheme = chromeScheme
52 |
53 | let completed = components.URL.flatMap { UIApplication.sharedApplication().openURL($0) } ?? false
54 | activityDidFinish(completed)
55 | }
56 |
57 |
58 | // MARK: - Private
59 |
60 | private func chromeSchemeForURL(URL: NSURL) -> String? {
61 | if URL.scheme == "http" {
62 | return "googlechrome"
63 | }
64 |
65 | if URL.scheme == "https" {
66 | return "googlechromes"
67 | }
68 |
69 | return nil
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Sources/Color+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Color+Canvas.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 1/25/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasKit
11 |
12 | extension Organization.Color {
13 | var uiColor: UIColor {
14 | return UIColor(red: CGFloat(red), green: CGFloat(green), blue: CGFloat(blue), alpha: 1)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Sources/Configuration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Configuration.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 12/2/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import CanvasCore
10 |
11 | private let canvasClientID = "5QdrPgUUYQs2yvGLIUT5PL"
12 |
13 | private let canvasClientSecretPart4 = "aef895c32"
14 | private let canvasClientSecretPart2 = "f5bd59c7866e85"
15 | private let canvasClientSecretPart1 = "60ff40c860274eb9afb6"
16 | private let canvasClientSecretPart3 = "97bdcc48ae89946"
17 | private let canvasClientSecret = "\(canvasClientSecretPart1)fb\(canvasClientSecretPart2)2e\(canvasClientSecretPart3)75\(canvasClientSecretPart4)"
18 |
19 | let config = Configuration(environment: .production, canvasClientID: canvasClientID, canvasClientSecret: canvasClientSecret)
20 |
--------------------------------------------------------------------------------
/Sources/CopyLinkActivity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CopyLinkActivity.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/15/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // TODO: Localize
12 | final class CopyLinkActivity: UIActivity {
13 |
14 | // MARK: - Properties
15 |
16 | private var url: NSURL?
17 |
18 |
19 | // MARK: - UIActivity
20 |
21 | override func canPerformWithActivityItems(activityItems: [AnyObject]) -> Bool {
22 | guard let url = activityItems.first as? NSURL else { return false }
23 |
24 | self.url = url
25 | return true
26 | }
27 |
28 | override func performActivity() {
29 | UIPasteboard.generalPasteboard().URL = url
30 | showBanner(text: "Copied link!")
31 | }
32 |
33 | override func activityType() -> String? {
34 | return "copy-link"
35 | }
36 |
37 | override func activityTitle() -> String? {
38 | return "Copy Link"
39 | }
40 |
41 | override func activityImage() -> UIImage? {
42 | return UIImage(named: "Copy Link")
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Sources/CopyLinkView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CopyLinkView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 8/9/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 |
12 | // TODO: Localize
13 | final class CopyLinkView: UIStackView {
14 |
15 | // MARK: - Properties
16 |
17 | let button: UIButton = {
18 | let button = GrayButton()
19 | button.setTitle("Copy Link", forState: .Normal)
20 | return button
21 | }()
22 |
23 |
24 | // MARK: - Initializers
25 |
26 | init() {
27 | super.init(frame: .zero)
28 |
29 | axis = .Vertical
30 | alignment = .Center
31 | spacing = 16
32 |
33 | let label = UILabel()
34 | label.text = "Invite more participants"
35 | label.textColor = Swatch.gray
36 | addArrangedSubview(label)
37 |
38 | addArrangedSubview(button)
39 | }
40 |
41 | required init?(coder aDecoder: NSCoder) {
42 | fatalError("init(coder:) has not been implemented")
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Sources/CopyRepresentationActivity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CopyRepresentationActivity.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/15/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class CopyRepresentationActivity: UIActivity {
12 |
13 | // MARK: - Types
14 |
15 | // TODO: Localize
16 | enum Representation: String {
17 | case markdown
18 | case html
19 | case json
20 |
21 | var activityType: String {
22 | return "copy-\(rawValue)"
23 | }
24 |
25 | var activityTitle: String {
26 | switch self {
27 | case .markdown: return "Copy Markdown"
28 | case .html: return "Copy HTML"
29 | case .json: return "Copy JSON"
30 | }
31 | }
32 |
33 | var activityImage: UIImage? {
34 | switch self {
35 | case .markdown: return UIImage(named: "Copy Markdown")
36 | case .html: return UIImage(named: "Copy HTML")
37 | case .json: return UIImage(named: "Copy JSON")
38 | }
39 | }
40 |
41 | var ext: String {
42 | return rawValue
43 | }
44 |
45 | var successMessage: String {
46 | switch self {
47 | case .markdown: return "Copied markdown!"
48 | case .html: return "Copied HTML!"
49 | case .json: return "Copied JSON!"
50 | }
51 | }
52 |
53 | var failureMessage: String {
54 | switch self {
55 | case .markdown: return "Failed to copy markdown."
56 | case .html: return "Failed to copy HTML."
57 | case .json: return "Failed to copy JSON."
58 | }
59 | }
60 | }
61 |
62 |
63 | // MARK: - Properties
64 |
65 | let representation: Representation
66 | let session: NSURLSession
67 |
68 | private var canvasID: String?
69 |
70 |
71 | // MARK: - Initializers
72 |
73 | init(representation: Representation, session: NSURLSession = NSURLSession.sharedSession()) {
74 | self.representation = representation
75 | self.session = session
76 | super.init()
77 | }
78 |
79 |
80 | // MARK: - UIActivity
81 |
82 | override func canPerformWithActivityItems(activityItems: [AnyObject]) -> Bool {
83 | guard let url = activityItems.first as? NSURL else { return false }
84 |
85 | if url.host == "usecanvas.com", let components = url.pathComponents where components.count == 4 && (components[3] as NSString).length == 22 {
86 | canvasID = components[3]
87 | return true
88 | }
89 |
90 | return false
91 | }
92 |
93 | override func performActivity() {
94 | guard let canvasID = canvasID,
95 | url = NSURL(string: "https://usecanvas.com/-/-/\(canvasID).\(representation.ext)")
96 | else {
97 | showBanner(text: representation.failureMessage, style: .failure)
98 | return
99 | }
100 |
101 | let request = NSURLRequest(URL: url)
102 | session.dataTaskWithRequest(request) { [weak self] data, _, _ in
103 | guard let representation = self?.representation else{ return }
104 | let string = data.flatMap { String(data: $0, encoding: NSUTF8StringEncoding) }
105 |
106 | dispatch_async(dispatch_get_main_queue()) {
107 | if let string = string {
108 | UIPasteboard.generalPasteboard().string = string
109 | self?.showBanner(text: representation.successMessage)
110 | } else {
111 | self?.showBanner(text: representation.failureMessage, style: .failure)
112 | }
113 | }
114 | }.resume()
115 | }
116 |
117 | override func activityType() -> String? {
118 | return representation.activityType
119 | }
120 |
121 | override func activityTitle() -> String? {
122 | return representation.activityTitle
123 | }
124 |
125 | override func activityImage() -> UIImage? {
126 | return representation.activityImage
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/Sources/DestructiveValueCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DestructiveValueCell.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/18/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Static
11 | import CanvasCore
12 |
13 | final class DestructiveButtonCell: UITableViewCell, CellType {
14 | override func tintColorDidChange() {
15 | textLabel?.textColor = tintAdjustmentMode == .Dimmed ? tintColor: Swatch.destructive
16 | imageView?.tintColor = textLabel?.textColor
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Sources/DragBackgroundView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DragBackgroundView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/20/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 |
12 | // TODO: Get colors from theme
13 | final class DragBackgroundView: UIView {
14 | override init(frame: CGRect) {
15 | super.init(frame: frame)
16 |
17 | backgroundColor = .whiteColor()
18 | userInteractionEnabled = false
19 |
20 | let topBorder = LineView()
21 | topBorder.translatesAutoresizingMaskIntoConstraints = false
22 | addSubview(topBorder)
23 |
24 | let bottomBorder = LineView()
25 | bottomBorder.translatesAutoresizingMaskIntoConstraints = false
26 | addSubview(bottomBorder)
27 |
28 | NSLayoutConstraint.activateConstraints([
29 | topBorder.leadingAnchor.constraintEqualToAnchor(leadingAnchor),
30 | topBorder.trailingAnchor.constraintEqualToAnchor(trailingAnchor),
31 | topBorder.bottomAnchor.constraintEqualToAnchor(topAnchor),
32 |
33 | bottomBorder.leadingAnchor.constraintEqualToAnchor(leadingAnchor),
34 | bottomBorder.trailingAnchor.constraintEqualToAnchor(trailingAnchor),
35 | bottomBorder.topAnchor.constraintEqualToAnchor(bottomAnchor)
36 | ])
37 | }
38 |
39 | required init?(coder aDecoder: NSCoder) {
40 | fatalError("init(coder:) has not been implemented")
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/DragProgressView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DragProgressView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/20/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 |
12 | final class DragProgressView: UIView {
13 |
14 | // MARK: - Properties
15 |
16 | private let imageView: UIImageView = {
17 | let view = UIImageView()
18 | view.translatesAutoresizingMaskIntoConstraints = false
19 | view.tintColor = Swatch.gray
20 | view.contentMode = .Center
21 | return view
22 | }()
23 |
24 |
25 | // MARK: - Initializers
26 |
27 | init(icon: UIImage?, isLeading: Bool) {
28 | super.init(frame: .zero)
29 | backgroundColor = Swatch.extraLightGray
30 | userInteractionEnabled = false
31 |
32 | imageView.image = icon
33 | addSubview(imageView)
34 |
35 | imageView.centerYAnchor.constraintEqualToAnchor(centerYAnchor).active = true
36 |
37 | if isLeading {
38 | let x = imageView.trailingAnchor.constraintEqualToAnchor(trailingAnchor, constant: -8)
39 | x.priority = UILayoutPriorityDefaultLow
40 |
41 | NSLayoutConstraint.activateConstraints([
42 | x,
43 | imageView.trailingAnchor.constraintLessThanOrEqualToAnchor(leadingAnchor, constant: DragContext.threshold)
44 | ])
45 | } else {
46 | let x = imageView.leadingAnchor.constraintEqualToAnchor(leadingAnchor, constant: 8)
47 | x.priority = UILayoutPriorityDefaultLow
48 |
49 | NSLayoutConstraint.activateConstraints([
50 | x,
51 | imageView.leadingAnchor.constraintGreaterThanOrEqualToAnchor(trailingAnchor, constant: -DragContext.threshold)
52 | ])
53 | }
54 | }
55 |
56 | required init?(coder aDecoder: NSCoder) {
57 | fatalError("init(coder:) has not been implemented")
58 | }
59 |
60 |
61 | // MARK: - Translation
62 |
63 | func translate(x x: CGFloat) {
64 | let progress = min(abs(x) / DragContext.threshold, 1)
65 | imageView.tintColor = Swatch.extraLightGray.interpolateTo(color: Swatch.darkGray, progress: progress)
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Sources/FooterButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FooterButton.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/13/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class FooterButton: PrefaceButton {
12 |
13 | // MARK: - Properties
14 |
15 | let lineView: LineView = {
16 | let view = LineView()
17 | view.translatesAutoresizingMaskIntoConstraints = false
18 | return view
19 | }()
20 |
21 |
22 | // MARK: - Initializers
23 |
24 | override init(frame: CGRect) {
25 | super.init(frame: frame)
26 |
27 | addSubview(lineView)
28 |
29 | NSLayoutConstraint.activateConstraints([
30 | lineView.leadingAnchor.constraintEqualToAnchor(leadingAnchor),
31 | lineView.trailingAnchor.constraintEqualToAnchor(trailingAnchor),
32 | lineView.topAnchor.constraintEqualToAnchor(topAnchor),
33 |
34 | heightAnchor.constraintEqualToConstant(48)
35 | ])
36 | }
37 |
38 | required init?(coder aDecoder: NSCoder) {
39 | fatalError("init(coder:) has not been implemented")
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Sources/GrayButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GrayButton.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 8/9/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasText
12 |
13 | final class GrayButton: UIButton {
14 |
15 | // MARK: - Initializers
16 |
17 | override init(frame: CGRect) {
18 | super.init(frame: frame)
19 |
20 | backgroundColor = Swatch.lightGray
21 |
22 | layer.cornerRadius = 4
23 |
24 | setTitleColor(Swatch.darkGray, forState: .Normal)
25 | setTitleColor(Swatch.black, forState: .Highlighted)
26 | setTitleColor(Swatch.extraLightGray, forState: .Disabled)
27 |
28 | NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(updateFont), name: UIContentSizeCategoryDidChangeNotification, object: nil)
29 | updateFont()
30 | }
31 |
32 | required init?(coder aDecoder: NSCoder) {
33 | fatalError("init(coder:) has not been implemented")
34 | }
35 |
36 |
37 | // MARK: - UIView
38 |
39 | override func intrinsicContentSize() -> CGSize {
40 | var size = super.intrinsicContentSize()
41 | size.height = 32
42 | size.width += 32 * 2
43 | return size
44 | }
45 |
46 |
47 | // MARK: - UIControl
48 |
49 | override var enabled: Bool {
50 | didSet {
51 | backgroundColor = enabled ? Swatch.lightGray.colorWithAlphaComponent(0.5) : Swatch.lightGray
52 | }
53 | }
54 |
55 | override var highlighted: Bool {
56 | didSet {
57 | backgroundColor = highlighted ? Swatch.lightGray.colorWithAlphaComponent(0.8) : Swatch.lightGray
58 | }
59 | }
60 |
61 | override var selected: Bool {
62 | didSet {
63 | backgroundColor = selected ? Swatch.lightGray.colorWithAlphaComponent(0.8) : Swatch.lightGray
64 | }
65 | }
66 |
67 |
68 | // MARK: - Private
69 |
70 | @objc func updateFont() {
71 | titleLabel?.font = TextStyle.body.font(weight: .medium)
72 | }
73 | }
--------------------------------------------------------------------------------
/Sources/GroupedSectionHeaderView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GroupedSectionHeaderView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 6/6/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasText
12 |
13 | final class GroupedSectionHeaderView: SectionHeaderView {
14 |
15 | // MARK: - Initializers
16 |
17 | override init(frame: CGRect) {
18 | super.init(frame: frame)
19 |
20 | backgroundColor = Swatch.groupedTableBackground
21 | tintColor = Swatch.darkGray
22 | }
23 |
24 | required init?(coder aDecoder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 |
28 |
29 | // MARK: - UIView
30 |
31 | override func tintColorDidChange() {
32 | super.tintColorDidChange()
33 | textLabel.textColor = tintColor
34 | }
35 |
36 |
37 | // MARK: - Private
38 |
39 | override func updateFont() {
40 | super.updateFont()
41 | textLabel.font = TextStyle.footnote.font()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sources/IndicatorButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IndicatorButton.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 5/13/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 |
12 | final class IndicatorButton: PillButton {
13 |
14 | // MARK: - Properties
15 |
16 | var loading = false {
17 | didSet {
18 | titleLabel?.alpha = loading ? 0 : 1
19 | enabled = !loading
20 |
21 | if loading {
22 | activityIndicator.startAnimating()
23 | } else {
24 | activityIndicator.stopAnimating()
25 | }
26 | }
27 | }
28 |
29 | let activityIndicator: UIActivityIndicatorView = {
30 | let indicator = UIActivityIndicatorView(activityIndicatorStyle: .Gray)
31 | indicator.translatesAutoresizingMaskIntoConstraints = false
32 | indicator.userInteractionEnabled = false
33 | indicator.hidesWhenStopped = true
34 | indicator.color = Swatch.darkGray
35 | return indicator
36 | }()
37 |
38 |
39 | // MARK: - Initializers
40 |
41 | override init(frame: CGRect) {
42 | super.init(frame: frame)
43 |
44 | addSubview(activityIndicator)
45 |
46 | NSLayoutConstraint.activateConstraints([
47 | activityIndicator.centerXAnchor.constraintEqualToAnchor(centerXAnchor),
48 | activityIndicator.centerYAnchor.constraintEqualToAnchor(centerYAnchor)
49 | ])
50 | }
51 |
52 | required init?(coder aDecoder: NSCoder) {
53 | fatalError("init(coder:) has not been implemented")
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Sources/Interpolate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Interpolate.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/25/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | func interpolate(start start: CGFloat, end: CGFloat, progress: CGFloat) -> CGFloat {
12 | return (end - start) * progress + start
13 | }
14 |
15 |
16 | extension UIColor {
17 | func interpolateTo(color end: UIColor, progress: CGFloat) -> UIColor {
18 | var r1: CGFloat = 0
19 | var g1: CGFloat = 0
20 | var b1: CGFloat = 0
21 | var a1: CGFloat = 0
22 | getRed(&r1, green: &g1, blue: &b1, alpha: &a1)
23 |
24 | var r2: CGFloat = 0
25 | var g2: CGFloat = 0
26 | var b2: CGFloat = 0
27 | var a2: CGFloat = 0
28 | end.getRed(&r2, green: &g2, blue: &b2, alpha: &a2)
29 |
30 | return UIColor(
31 | red: interpolate(start: r1, end: r2, progress: progress),
32 | green: interpolate(start: g1, end: g2, progress: progress),
33 | blue: interpolate(start: b1, end: b2, progress: progress),
34 | alpha: interpolate(start: a1, end: a2, progress: progress)
35 | )
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Sources/LineView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LineView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 6/3/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 |
12 | final class LineView: UIView {
13 |
14 | // MARK: - Initializers
15 |
16 | override init(frame: CGRect) {
17 | super.init(frame: frame)
18 | backgroundColor = Swatch.border
19 | }
20 |
21 | required init?(coder aDecoder: NSCoder) {
22 | fatalError("init(coder:) has not been implemented")
23 | }
24 |
25 |
26 | // MARK: - UIView
27 |
28 | override func sizeThatFits(size: CGSize) -> CGSize {
29 | return CGSize(width: size.width, height: intrinsicContentSize().height)
30 | }
31 |
32 | override func intrinsicContentSize() -> CGSize {
33 | return CGSize(width: UIViewNoIntrinsicMetric, height: 1 / max(1, traitCollection.displayScale))
34 | }
35 |
36 | override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
37 | super.traitCollectionDidChange(previousTraitCollection)
38 | invalidateIntrinsicContentSize()
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Sources/LoadCanvasViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoadCanvasViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 5/31/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasKit
12 |
13 | final class LoadCanvasViewController: UIViewController, Accountable {
14 |
15 | // MARK: - Properties
16 |
17 | var account: Account
18 | let canvasID: String
19 |
20 | private var fetching = false
21 | private let activityIndicator: UIActivityIndicatorView = {
22 | let view = UIActivityIndicatorView(activityIndicatorStyle: .Gray)
23 | view.translatesAutoresizingMaskIntoConstraints = false
24 | view.startAnimating()
25 | return view
26 | }()
27 |
28 |
29 | // MARK: - Initializers
30 |
31 | init(account: Account, canvasID: String) {
32 | self.account = account
33 | self.canvasID = canvasID
34 |
35 | super.init(nibName: nil, bundle: nil)
36 | }
37 |
38 | required init?(coder aDecoder: NSCoder) {
39 | fatalError("init(coder:) has not been implemented")
40 | }
41 |
42 |
43 | // MARK: - UIViewController
44 |
45 | override func viewDidLoad() {
46 | super.viewDidLoad()
47 |
48 | view.backgroundColor = Swatch.white
49 | view.addSubview(activityIndicator)
50 |
51 | navigationItem.hidesBackButton = true
52 |
53 | NSLayoutConstraint.activateConstraints([
54 | activityIndicator.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor),
55 | activityIndicator.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor),
56 | ])
57 | }
58 |
59 | override func viewDidAppear(animated: Bool) {
60 | super.viewDidAppear(animated)
61 | fetch()
62 | }
63 |
64 |
65 | // MARK: - Private
66 |
67 | private func fetch() {
68 | if fetching {
69 | return
70 | }
71 |
72 | fetching = true
73 |
74 | APIClient(account: account).showCanvas(id: canvasID) { result in
75 | dispatch_async(dispatch_get_main_queue()) { [weak self] in
76 | switch result {
77 | case .Success(let canvas): self?.showEditor(canvas: canvas)
78 | case .Failure(let message): self?.showError(message: message)
79 | }
80 | }
81 | }
82 | }
83 |
84 | private func showEditor(canvas canvas: Canvas) {
85 | guard let navigationController = navigationController else { return }
86 |
87 | let viewController = EditorViewController(account: account, canvas: canvas)
88 | viewController.navigationItem.leftBarButtonItem = UIBarButtonItem(title: LocalizedString.CloseCommand.string, style: .Plain, target: viewController, action: #selector(EditorViewController.closeNavigationControllerModal))
89 |
90 | var viewControllers = navigationController.viewControllers
91 | viewControllers[viewControllers.count - 1] = viewController
92 | navigationController.setViewControllers(viewControllers, animated: false)
93 | }
94 |
95 | private func showError(message message: String) {
96 | activityIndicator.stopAnimating()
97 |
98 | let billboard = BillboardView()
99 | billboard.translatesAutoresizingMaskIntoConstraints = false
100 | billboard.illustrationView.image = UIImage(named: "Not Found")
101 | billboard.titleLabel.text = LocalizedString.NotFoundHeading.string
102 | billboard.subtitleLabel.text = LocalizedString.NotFoundMessage.string
103 | view.addSubview(billboard)
104 |
105 | NSLayoutConstraint.activateConstraints([
106 | billboard.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor),
107 | billboard.widthAnchor.constraintLessThanOrEqualToAnchor(view.widthAnchor),
108 | billboard.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor),
109 | ])
110 |
111 | title = LocalizedString.NotFoundTitle.string
112 | navigationItem.leftBarButtonItem = UIBarButtonItem(title: LocalizedString.CloseCommand.string, style: .Plain, target: self, action: #selector(close))
113 | }
114 |
115 | @objc private func close() {
116 | dismissViewControllerAnimated(true, completion: nil)
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/Sources/ModelsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ModelsViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 11/23/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasKit
12 | import Static
13 | import PullToRefresh
14 |
15 | // TODO: Localize this class
16 | class ModelsViewController: TableViewController {
17 |
18 | // MARK: - Properties
19 |
20 | var loading = false {
21 | didSet {
22 | UIApplication.sharedApplication().networkActivityIndicatorVisible = loading
23 |
24 | if loading {
25 | refreshView.startRefreshing(false)
26 | } else {
27 | refreshView.finishRefreshing()
28 | }
29 | }
30 | }
31 |
32 | var opening = false
33 |
34 | let refreshView = RefreshView()
35 |
36 |
37 | // MARK: - Initializers
38 |
39 | override init(style: UITableViewStyle) {
40 | super.init(style: style)
41 |
42 | refreshView.expandedHeight = 48 + 32
43 | refreshView.delegate = self
44 | refreshView.contentView = RefreshContentView()
45 | }
46 |
47 | required init?(coder aDecoder: NSCoder) {
48 | fatalError("init(coder:) has not been implemented")
49 | }
50 |
51 | deinit {
52 | refreshView.scrollView = nil
53 | }
54 |
55 |
56 | // MARK: - UIResponder
57 |
58 | override func canBecomeFirstResponder() -> Bool {
59 | return true
60 | }
61 |
62 | override var keyCommands: [UIKeyCommand] {
63 | var commands = super.keyCommands ?? []
64 |
65 | if let navigationController = navigationController where navigationController.viewControllers.count > 1 {
66 | let previousTitle = (navigationController.viewControllers[navigationController.viewControllers.count - 2]).title
67 | let backTitle = previousTitle.flatMap { "Back to \($0)" } ?? "Back"
68 |
69 | commands += [
70 | UIKeyCommand(input: UIKeyInputLeftArrow, modifierFlags: [], action: #selector(goBack), discoverabilityTitle: backTitle),
71 | UIKeyCommand(input: "w", modifierFlags: [.Command], action: #selector(goBack))
72 | ]
73 | }
74 |
75 | if canRefresh {
76 | commands.append(UIKeyCommand(input: "R", modifierFlags: [.Command], action: #selector(refresh), discoverabilityTitle: "Refresh"))
77 | }
78 |
79 | return commands
80 | }
81 |
82 |
83 | // MARK: - UIViewController
84 |
85 | override func viewWillAppear(animated: Bool) {
86 | super.viewWillAppear(animated)
87 | opening = false
88 | refresh()
89 | }
90 |
91 | override func viewDidLayoutSubviews() {
92 | super.viewDidLayoutSubviews()
93 |
94 | if canRefresh && refreshView.scrollView == nil {
95 | refreshView.scrollView = tableView
96 | }
97 |
98 | refreshView.defaultContentInsets = UIEdgeInsetsMake(topLayoutGuide.length, 0, 0, 0)
99 | }
100 |
101 |
102 | // MARK: - Configuration
103 |
104 | var canRefresh = true
105 |
106 |
107 | // MARK: - Actions
108 |
109 | func refresh() {
110 | // Subclasses should override this
111 | }
112 |
113 |
114 | // MARK: - Private
115 |
116 | @objc private func goBack() {
117 | navigationController?.popViewControllerAnimated(true)
118 | }
119 | }
120 |
121 |
122 | extension ModelsViewController: RefreshViewDelegate {
123 | func refreshViewDidStartRefreshing(refreshView: RefreshView) {
124 | refresh()
125 | }
126 |
127 | func refreshViewShouldStartRefreshing(refreshView: RefreshView) -> Bool { return true }
128 | func refreshViewDidFinishRefreshing(refreshView: RefreshView) {}
129 | func lastUpdatedAtForRefreshView(refreshView: RefreshView) -> NSDate? { return nil }
130 | func refreshView(refreshView: RefreshView, didUpdateContentInset contentInset: UIEdgeInsets) {}
131 | func refreshView(refreshView: RefreshView, willTransitionTo to: RefreshView.State, from: RefreshView.State, animated: Bool) {}
132 | func refreshView(refreshView: RefreshView, didTransitionTo to: RefreshView.State, from: RefreshView.State, animated: Bool) {}
133 | }
134 |
--------------------------------------------------------------------------------
/Sources/NSDate+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSDate+Canvas.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 12/2/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension NSDate {
12 | var briefTimeAgoInWords: String {
13 | let components = NSCalendar.currentCalendar().components([.Second, .Minute, .Hour, .Day, .Year], fromDate: self, toDate: NSDate(), options: [])
14 |
15 | if components.year > 0 {
16 | return "\(components.year)y"
17 | }
18 |
19 | if components.day > 0 {
20 | return "\(components.day)d"
21 | }
22 |
23 | if components.hour > 0 {
24 | return "\(components.hour)h"
25 | }
26 |
27 | if components.minute > 0 {
28 | return "\(components.minute)m"
29 | }
30 |
31 | return "\(components.second)s"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/NSProcessInfo+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSProcessInfo+Canvas.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/18/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension NSProcessInfo {
12 | var isSnapshotting: Bool {
13 | return arguments.contains("-snapshot")
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/NavigationBar.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NavigationBar.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 2/5/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 |
12 | final class NavigationBar: UINavigationBar {
13 |
14 | // MARK: - Properties
15 |
16 | var titleColor: UIColor? {
17 | didSet {
18 | updateTitleColor()
19 | }
20 | }
21 |
22 | var borderColor: UIColor? {
23 | set {
24 | borderView.backgroundColor = newValue
25 | }
26 |
27 | get {
28 | return borderView.backgroundColor
29 | }
30 | }
31 |
32 | private let borderView: LineView = {
33 | let view = LineView()
34 | view.translatesAutoresizingMaskIntoConstraints = false
35 | return view
36 | }()
37 |
38 |
39 | // MARK: - Initializers
40 |
41 | override init(frame: CGRect) {
42 | super.init(frame: frame)
43 |
44 | barTintColor = Swatch.white
45 | translucent = false
46 | shadowImage = UIImage()
47 | backIndicatorImage = UIImage(named: "ChevronLeft")
48 | backIndicatorTransitionMaskImage = UIImage(named: "ChevronLeft")
49 |
50 | borderColor = Swatch.border
51 |
52 | addSubview(borderView)
53 |
54 | NSLayoutConstraint.activateConstraints([
55 | borderView.topAnchor.constraintEqualToAnchor(bottomAnchor),
56 | borderView.leadingAnchor.constraintEqualToAnchor(leadingAnchor),
57 | borderView.trailingAnchor.constraintEqualToAnchor(trailingAnchor)
58 | ])
59 | }
60 |
61 | required init?(coder aDecoder: NSCoder) {
62 | fatalError("init(coder:) has not been implemented")
63 | }
64 |
65 | override func tintColorDidChange() {
66 | super.tintColorDidChange()
67 | updateTitleColor()
68 | }
69 |
70 |
71 | // MARK: - Private
72 |
73 | private func updateTitleColor() {
74 | titleTextAttributes = [
75 | NSFontAttributeName: Font.sansSerif(weight: .medium),
76 | NSForegroundColorAttributeName: tintAdjustmentMode == .Dimmed ? tintColor : (titleColor ?? Swatch.darkGray)
77 | ]
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Sources/NavigationController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NavigationController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 1/12/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 |
12 | final class NavigationController: UINavigationController {
13 |
14 | // MARK: - Properties
15 |
16 | private let defaultTintColor = Swatch.brand
17 | private let defaultTitleColor = Swatch.black
18 |
19 |
20 | // MARK: - Initializers
21 |
22 | override init(rootViewController: UIViewController) {
23 | super.init(navigationBarClass: NavigationBar.self, toolbarClass: nil)
24 |
25 | viewControllers = [rootViewController]
26 |
27 | updateTintColor(view.tintColor)
28 |
29 | delegate = self
30 | }
31 |
32 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
33 | super.init(nibName: nil, bundle: nil)
34 | }
35 |
36 | required init?(coder aDecoder: NSCoder) {
37 | fatalError("init(coder:) has not been implemented")
38 | }
39 |
40 |
41 | // MARK: - Private
42 |
43 | private func updateTintColor(viewController: UIViewController) {
44 | var target = viewController
45 |
46 | // Handle nested navigation controllers for when the split view is collapsed
47 | if let top = (viewController as? UINavigationController)?.topViewController {
48 | target = top
49 | }
50 |
51 | let tintColor = (target as? TintableEnvironment)?.preferredTintColor
52 | updateTintColor(tintColor)
53 | }
54 |
55 | private func updateTintColor(tintColor: UIColor?) {
56 | let itemsColor = tintColor ?? defaultTintColor
57 | view.tintColor = itemsColor
58 | navigationBar.tintColor = itemsColor
59 | }
60 | }
61 |
62 |
63 | extension NavigationController: UINavigationControllerDelegate {
64 | func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
65 | // Call didShow if the animation is canceled
66 | transitionCoordinator()?.notifyWhenInteractionEndsUsingBlock { [weak self] context in
67 | guard context.isCancelled() else { return }
68 | guard let delegate = self, from = context.viewControllerForKey(UITransitionContextFromViewControllerKey) else { return }
69 | delegate.navigationController(navigationController, willShowViewController: from, animated: animated)
70 |
71 | let animationCompletion = context.transitionDuration() * NSTimeInterval(context.percentComplete())
72 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(animationCompletion) * Int64(NSEC_PER_SEC)), dispatch_get_main_queue()) {
73 | delegate.navigationController(navigationController, didShowViewController: from, animated: animated)
74 | }
75 | }
76 |
77 | updateTintColor(viewController)
78 | }
79 |
80 | func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) {
81 | updateTintColor(viewController)
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Sources/OAuthClient+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OAuthClient+Canvas.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 8/12/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import CanvasKit
10 |
11 | extension OAuthClient {
12 | init() {
13 | self.init(clientID: config.canvasClientID, clientSecret: config.canvasClientSecret, baseURL: config.environment.apiURL)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/OnboardingBillboardViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnboardingViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/7/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasText
12 |
13 | class OnboardingBillboardViewController: StackViewController {
14 |
15 | // MARK: - UIViewController
16 |
17 | var illustrationName: String? {
18 | didSet {
19 | updateIllustration()
20 | }
21 | }
22 |
23 | private let illustrationView: UIImageView = {
24 | let view = UIImageView()
25 | view.contentMode = .Center
26 | return view
27 | }()
28 |
29 | var text: String? {
30 | get {
31 | return textLabel.text
32 | }
33 |
34 | set {
35 | textLabel.text = newValue
36 | }
37 | }
38 |
39 | private let textLabel: UILabel = {
40 | let label = UILabel()
41 | label.textColor = Swatch.black
42 | label.numberOfLines = 0
43 | label.textAlignment = .Center
44 | return label
45 | }()
46 |
47 | var detailText: String? {
48 | get {
49 | return detailTextLabel.text
50 | }
51 |
52 | set {
53 | detailTextLabel.text = newValue
54 | }
55 | }
56 |
57 | private let detailTextLabel: UILabel = {
58 | let label = UILabel()
59 | label.textColor = Swatch.darkGray
60 | label.numberOfLines = 0
61 | label.textAlignment = .Center
62 | return label
63 | }()
64 |
65 | private var textIllustrationSpacing: NSLayoutConstraint!
66 |
67 |
68 | // MARK: - UIViewController
69 |
70 | override func viewDidLoad() {
71 | super.viewDidLoad()
72 |
73 | stackView.axis = .Vertical
74 | stackView.alignment = .Center
75 | stackView.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 16 + 44, right: 16)
76 | stackView.layoutMarginsRelativeArrangement = true
77 |
78 | stackView.addArrangedSubview(textLabel)
79 | stackView.addSpace(12)
80 | stackView.addArrangedSubview(detailTextLabel)
81 |
82 | let spacer = UIView()
83 | spacer.translatesAutoresizingMaskIntoConstraints = false
84 | stackView.addArrangedSubview(spacer)
85 |
86 | textIllustrationSpacing = spacer.heightAnchor.constraintEqualToConstant(0)
87 | textIllustrationSpacing.active = true
88 |
89 | stackView.addArrangedSubview(illustrationView)
90 |
91 | NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(updateFonts), name: UIContentSizeCategoryDidChangeNotification, object: nil)
92 | updateFonts()
93 | }
94 |
95 | override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
96 | super.traitCollectionDidChange(previousTraitCollection)
97 |
98 | let spacing: CGFloat
99 |
100 | if view.bounds.height > 480 {
101 | spacing = traitCollection.horizontalSizeClass == .Regular ? 48 : 32
102 | } else {
103 | spacing = 16
104 | }
105 |
106 | textIllustrationSpacing.constant = spacing
107 |
108 | updateIllustration()
109 | }
110 |
111 |
112 | // MARK: - Private
113 |
114 | @objc private func updateFonts() {
115 | textLabel.font = TextStyle.title1.font()
116 | detailTextLabel.font = TextStyle.body.font()
117 | }
118 |
119 | private func updateIllustration() {
120 | guard let illustrationName = illustrationName else {
121 | illustrationView.image = nil
122 | return
123 | }
124 |
125 | var name = illustrationName
126 |
127 | switch traitCollection.horizontalSizeClass {
128 | case .Compact, .Unspecified:
129 | name += "Compact"
130 | case .Regular:
131 | name += "Regular"
132 | }
133 |
134 | illustrationView.image = UIImage(named: name)
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/Sources/OnboardingGesturesViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnboardingGesturesViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/7/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // TODO: Localize
12 | final class OnboardingGesturesViewController: OnboardingBillboardViewController {
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | text = "Easy to the Touch"
17 | detailText = "Swipe gestures turn paragraphs\ninto lists and headings."
18 | illustrationName = "Gestures"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/OnboardingOrigamiViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnboardingOrigamiViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/7/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // TODO: Localize
12 | final class OnboardingOrigamiViewController: OnboardingBillboardViewController {
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | text = "Origami Markdown"
17 | detailText = "Folds away Markdown syntax\nwhen you don’t need it."
18 | illustrationName = "Origami"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/OnboardingSharingViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnboardingSharingViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/7/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // TODO: Localize
12 | final class OnboardingSharingViewController: OnboardingBillboardViewController {
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | text = "Simple Sharing"
17 | detailText = "Collaboration is as easy\nas sharing a URL."
18 | illustrationName = "Share"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/OnboardingWelcomeViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OnboardingWelcomeViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/7/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // TODO: Localize
12 | final class OnboardingWelcomeViewController: OnboardingBillboardViewController {
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 |
16 | text = "Welcome to Canvas"
17 | detailText = "Collaborative notes\nfor teams of nerds."
18 | illustrationName = "Welcome"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/Organization+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Organization+Canvas.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 1/12/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasKit
12 | import Static
13 |
14 | extension Organization {
15 | var isPersonalNotes: Bool {
16 | guard let account = AccountController.sharedController.currentAccount else { return false }
17 | return slug == account.user.username
18 | }
19 |
20 | var displayName: String {
21 | return isPersonalNotes ? LocalizedString.PersonalNotes.string : name
22 | }
23 |
24 | var row: Row {
25 | // TODO: Localize
26 | var detailText = "\(membersCount) member"
27 | if membersCount != 1 {
28 | detailText += "s"
29 | }
30 |
31 | return Row(
32 | text: displayName,
33 | detailText: detailText,
34 | context: [
35 | "organization": self
36 | ],
37 | cellClass: OrganizationCell.self
38 | )
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Sources/OrganizationAvatarView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OrganizationAvatarView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 1/12/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasKit
12 |
13 | final class OrganizationAvatarView: UIView {
14 |
15 | // MARK: - Properties
16 |
17 | var highlighted = false {
18 | didSet {
19 | updateUI()
20 | }
21 | }
22 |
23 | var organization: Organization? {
24 | didSet {
25 | updateUI()
26 | }
27 | }
28 |
29 | private let avatarView = AvatarView()
30 |
31 | private let initialsLabel: UILabel = {
32 | let label = UILabel()
33 | label.textColor = Swatch.white
34 | label.textAlignment = .Center
35 | label.font = Font.sansSerif(weight: .medium, size: .small)
36 | return label
37 | }()
38 |
39 |
40 | // MARK: - UIView
41 |
42 | override func tintColorDidChange() {
43 | if let organization = organization where organization.isPersonalNotes {
44 | return
45 | }
46 |
47 | backgroundColor = tintColor
48 | }
49 |
50 | override func layoutSubviews() {
51 | if initialsLabel.superview != nil {
52 | initialsLabel.frame = bounds
53 | }
54 |
55 | if avatarView.superview != nil {
56 | avatarView.frame = bounds
57 | }
58 | }
59 |
60 |
61 | // MARK: - Private
62 |
63 | private func updateUI() {
64 | guard let organization = organization else {
65 | initialsLabel.removeFromSuperview()
66 | initialsLabel.text = nil
67 | tintColor = highlighted ? Swatch.white : Swatch.cellDisclosureIndicator
68 | avatarView.removeFromSuperview()
69 | avatarView.user = nil
70 |
71 | tintColor = highlighted ? Swatch.white : Swatch.cellDisclosureIndicator
72 | return
73 | }
74 |
75 | if organization.isPersonalNotes, let user = AccountController.sharedController.currentAccount?.user {
76 | initialsLabel.removeFromSuperview()
77 | initialsLabel.text = nil
78 |
79 | avatarView.user = user
80 |
81 | if avatarView.superview == nil {
82 | layer.cornerRadius = 0
83 | addSubview(avatarView)
84 | setNeedsLayout()
85 | }
86 |
87 | backgroundColor = .clearColor()
88 | return
89 | }
90 |
91 | avatarView.removeFromSuperview()
92 | avatarView.user = nil
93 |
94 | let orgColor = organization.color?.uiColor ?? Swatch.brand
95 |
96 | tintColor = highlighted ? Swatch.white : orgColor
97 |
98 | let name = organization.name
99 | initialsLabel.text = name.substringToIndex(name.startIndex.advancedBy(2))
100 | initialsLabel.textColor = highlighted ? orgColor : Swatch.white
101 |
102 | if initialsLabel.superview == nil {
103 | layer.cornerRadius = 4
104 | tintColorDidChange()
105 | addSubview(initialsLabel)
106 | setNeedsLayout()
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/Sources/OrganizationCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OrganizationCell.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 1/13/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Static
11 | import CanvasCore
12 | import CanvasKit
13 | import CanvasText
14 |
15 | final class OrganizationCell: UITableViewCell, CellType {
16 |
17 | // MARK: - Properties
18 |
19 | let avatarView: OrganizationAvatarView = {
20 | let view = OrganizationAvatarView()
21 | view.translatesAutoresizingMaskIntoConstraints = false
22 | return view
23 | }()
24 |
25 | let titleLabel: UILabel = {
26 | let label = UILabel()
27 | label.translatesAutoresizingMaskIntoConstraints = false
28 | label.backgroundColor = Swatch.white
29 | label.textColor = Swatch.black
30 | label.highlightedTextColor = Swatch.white
31 | label.setContentCompressionResistancePriority(UILayoutPriorityDefaultLow, forAxis: .Horizontal)
32 | return label
33 | }()
34 |
35 | let disclosureIndicatorView = UIImageView(image: UIImage(named: "ChevronRightSmall"))
36 |
37 |
38 | // MARK: - Initializers
39 |
40 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
41 | super.init(style: .Subtitle, reuseIdentifier: reuseIdentifier)
42 |
43 | let view = UIView()
44 | view.backgroundColor = tintColor
45 | selectedBackgroundView = view
46 |
47 | accessoryView = disclosureIndicatorView
48 |
49 | setupViews()
50 | setupConstraints()
51 |
52 | NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(updateFont), name: UIContentSizeCategoryDidChangeNotification, object: nil)
53 | updateFont()
54 | }
55 |
56 | required init?(coder aDecoder: NSCoder) {
57 | fatalError("init(coder:) has not been implemented")
58 | }
59 |
60 |
61 | // MARK: - UITableViewCell
62 |
63 | override func setHighlighted(highlighted: Bool, animated: Bool) {
64 | super.setHighlighted(highlighted, animated: animated)
65 | updateHighlighted()
66 | }
67 |
68 | override func setSelected(selected: Bool, animated: Bool) {
69 | super.setSelected(selected, animated: animated)
70 | updateHighlighted()
71 | }
72 |
73 |
74 | // MARK: - Configuration
75 |
76 | func setupViews() {
77 | contentView.addSubview(avatarView)
78 | contentView.addSubview(titleLabel)
79 | }
80 |
81 | func setupConstraints() {
82 | NSLayoutConstraint.activateConstraints([
83 | contentView.heightAnchor.constraintGreaterThanOrEqualToConstant(56),
84 |
85 | NSLayoutConstraint(item: avatarView, attribute: .Leading, relatedBy: .Equal, toItem: contentView, attribute: .LeadingMargin, multiplier: 1, constant: 0),
86 | avatarView.widthAnchor.constraintEqualToConstant(32),
87 | avatarView.heightAnchor.constraintEqualToConstant(32),
88 | avatarView.centerYAnchor.constraintEqualToAnchor(contentView.centerYAnchor),
89 |
90 | titleLabel.centerYAnchor.constraintEqualToAnchor(contentView.centerYAnchor),
91 | titleLabel.leadingAnchor.constraintEqualToAnchor(avatarView.trailingAnchor, constant: 8),
92 | NSLayoutConstraint(item: titleLabel, attribute: .Trailing, relatedBy: .LessThanOrEqual, toItem: contentView, attribute: .TrailingMargin, multiplier: 1, constant: 0),
93 | ])
94 | }
95 |
96 |
97 | // MARK: - CellType
98 |
99 | func configure(row row: Row) {
100 | titleLabel.text = row.text
101 |
102 | let organization = row.context?["organization"] as? Organization
103 | avatarView.organization = organization
104 | selectedBackgroundView?.backgroundColor = organization?.color?.uiColor ?? Swatch.brand
105 | }
106 |
107 |
108 | // MARK: - Private
109 |
110 | private func updateHighlighted() {
111 | avatarView.highlighted = highlighted || selected
112 | disclosureIndicatorView.tintColor = highlighted || selected ? Swatch.white : Swatch.cellDisclosureIndicator
113 | }
114 |
115 | @objc private func updateFont() {
116 | titleLabel.font = TextStyle.body.font(weight: .medium)
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/Sources/PillButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PillButton.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 11/25/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasText
12 |
13 | class PillButton: UIButton {
14 |
15 | // MARK: - Initializers
16 |
17 | override init(frame: CGRect) {
18 | super.init(frame: frame)
19 |
20 | backgroundColor = .clearColor()
21 |
22 | layer.cornerRadius = 24
23 | layer.borderWidth = 2
24 |
25 | setTitleColor(Swatch.brand, forState: .Normal)
26 | setTitleColor(Swatch.lightBlue, forState: .Highlighted)
27 | setTitleColor(Swatch.darkGray, forState: .Disabled)
28 |
29 | NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(updateFont), name: UIContentSizeCategoryDidChangeNotification, object: nil)
30 | updateFont()
31 | updateBorderColor()
32 | }
33 |
34 | required init?(coder aDecoder: NSCoder) {
35 | fatalError("init(coder:) has not been implemented")
36 | }
37 |
38 |
39 | // MARK: - UIView
40 |
41 | override func intrinsicContentSize() -> CGSize {
42 | var size = super.intrinsicContentSize()
43 | size.height = 48
44 | size.width += 32 * 2
45 | return size
46 | }
47 |
48 |
49 | // MARK: - UIControl
50 |
51 | override var enabled: Bool {
52 | didSet {
53 | updateBorderColor()
54 | }
55 | }
56 |
57 | override var highlighted: Bool {
58 | didSet {
59 | updateBorderColor()
60 | }
61 | }
62 |
63 | override var selected: Bool {
64 | didSet {
65 | updateBorderColor()
66 | }
67 | }
68 |
69 |
70 | // MARK: - Private
71 |
72 | private func updateBorderColor() {
73 | layer.borderColor = titleColorForState(state)?.CGColor
74 | }
75 |
76 | @objc func updateFont() {
77 | titleLabel?.font = TextStyle.body.font(weight: .medium)
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Sources/PlaceholderViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PlaceholderViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 5/10/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasText
12 |
13 | final class PlaceholderViewController: UIViewController {
14 |
15 | // MARK: - Properties
16 |
17 | private let textLabel: UILabel = {
18 | let label = UILabel()
19 | label.translatesAutoresizingMaskIntoConstraints = false
20 | label.text = "No Canvas Selected"
21 | label.textColor = Swatch.darkGray
22 | return label
23 | }()
24 |
25 |
26 | // MARK: - UIViewController
27 |
28 | override func viewDidLoad() {
29 | super.viewDidLoad()
30 |
31 | view.backgroundColor = Swatch.white
32 |
33 | view.addSubview(textLabel)
34 |
35 | NSLayoutConstraint.activateConstraints([
36 | textLabel.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor),
37 | textLabel.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor),
38 | ])
39 |
40 | NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(updateFont), name: UIContentSizeCategoryDidChangeNotification, object: nil)
41 | updateFont()
42 | }
43 |
44 | override func viewDidAppear(animated: Bool) {
45 | super.viewDidAppear(animated)
46 | UIDevice.currentDevice().batteryMonitoringEnabled = false
47 | }
48 |
49 |
50 | // MARK: - Private
51 |
52 | @objc private func updateFont() {
53 | textLabel.font = TextStyle.body.font()
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Sources/PrefaceButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PrefaceButton.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/13/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 |
12 | class PrefaceButton: PillButton {
13 |
14 | // MARK: - Initializers
15 |
16 | override init(frame: CGRect) {
17 | super.init(frame: frame)
18 |
19 | titleLabel?.numberOfLines = 0
20 | titleLabel?.textAlignment = .Center
21 | layer.borderWidth = 0
22 | }
23 |
24 | required init?(coder aDecoder: NSCoder) {
25 | fatalError("init(coder:) has not been implemented")
26 | }
27 |
28 |
29 | // MARK: - Preface
30 |
31 | func set(preface preface: String, title: String) {
32 | // Use non-breaking spaces for the title
33 | let title = title.stringByReplacingOccurrencesOfString(" ", withString: "\u{00A0}")
34 |
35 | // TODO: Localize
36 | let string = "\(preface) \(title)"
37 | let emphasizedRange = NSRange(
38 | location: (preface as NSString).length + 1,
39 | length: (title as NSString).length
40 | )
41 |
42 | let normalText = NSMutableAttributedString(string: string, attributes: [
43 | NSFontAttributeName: Font.sansSerif(size: .body),
44 | NSForegroundColorAttributeName: Swatch.darkGray
45 | ])
46 |
47 | normalText.setAttributes([
48 | NSFontAttributeName: Font.sansSerif(size: .body, weight: .medium),
49 | NSForegroundColorAttributeName: Swatch.brand
50 | ], range: emphasizedRange)
51 |
52 | setAttributedTitle(normalText, forState: .Normal)
53 |
54 | let highlightedText = NSMutableAttributedString(string: string, attributes: [
55 | NSFontAttributeName: Font.sansSerif(size: .body),
56 |
57 | // TODO: Use a named color for this
58 | NSForegroundColorAttributeName: Swatch.darkGray.colorWithAlphaComponent(0.6)
59 | ])
60 |
61 | highlightedText.setAttributes([
62 | NSFontAttributeName: Font.sansSerif(size: .body, weight: .medium),
63 | NSForegroundColorAttributeName: Swatch.lightBlue
64 | ], range: emphasizedRange)
65 |
66 | setAttributedTitle(highlightedText, forState: .Highlighted)
67 |
68 | let disabledText = NSAttributedString(string: string, attributes: [
69 | NSFontAttributeName: Font.sansSerif(size: .body),
70 | NSForegroundColorAttributeName: Swatch.darkGray
71 | ])
72 | setAttributedTitle(disabledText, forState: .Disabled)
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Sources/SafariActivity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SafariActivity.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 11/18/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class SafariActivity: WebActivity {
12 |
13 | // MARK: - UIActivity
14 |
15 | override func activityType() -> String? {
16 | return "open-in-safari"
17 | }
18 |
19 | override func activityTitle() -> String? {
20 | return "Open in Safari"
21 | }
22 |
23 | override func activityImage() -> UIImage? {
24 | return UIImage(named: "Safari")
25 | }
26 |
27 | override func canPerformWithActivityItems(activityItems: [AnyObject]) -> Bool {
28 | for activityItem in activityItems {
29 | if let URL = activityItem as? NSURL where UIApplication.sharedApplication().canOpenURL(URL) {
30 | return true
31 | }
32 | }
33 |
34 | return false
35 | }
36 |
37 | override func performActivity() {
38 | let completed = URL.flatMap { UIApplication.sharedApplication().openURL($0) } ?? false
39 | activityDidFinish(completed)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Sources/SearchBarContainer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SearchBarContainer.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 2/9/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 |
12 | final class SearchBarContainer: UIView {
13 |
14 | // MARK: - Properties
15 |
16 | let searchBar: UISearchBar
17 |
18 | private let topBorderView = UIView()
19 | private let bottomBorderView = UIView()
20 |
21 |
22 | // MARK: - Initializers
23 |
24 | init(searchBar: UISearchBar) {
25 | self.searchBar = searchBar
26 |
27 | super.init(frame: searchBar.bounds)
28 |
29 | autoresizingMask = [.FlexibleWidth]
30 |
31 | searchBar.barTintColor = Swatch.white
32 | searchBar.layer.borderColor = Swatch.white.CGColor
33 | searchBar.layer.borderWidth = 1
34 | searchBar.backgroundColor = Swatch.white
35 | searchBar.translucent = false
36 | searchBar.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
37 | searchBar.setImage(UIImage(named: "SearchSmall"), forSearchBarIcon: .Search, state: .Normal)
38 | addSubview(searchBar)
39 |
40 | if let string = searchBar.placeholder {
41 | let placeholder = NSAttributedString(string: string, attributes: [
42 | NSForegroundColorAttributeName: Swatch.darkGray,
43 | NSFontAttributeName: Font.sansSerif(size: .small)
44 | ])
45 | UITextField.appearanceWhenContainedInInstancesOfClasses([UISearchBar.self]).attributedPlaceholder = placeholder
46 | }
47 |
48 | topBorderView.backgroundColor = Swatch.border
49 | addSubview(topBorderView)
50 |
51 | bottomBorderView.backgroundColor = Swatch.border
52 | addSubview(bottomBorderView)
53 | }
54 |
55 | required init?(coder aDecoder: NSCoder) {
56 | fatalError("init(coder:) has not been implemented")
57 | }
58 |
59 |
60 | // MARK: - UIView
61 |
62 | override func addSubview(view: UIView) {
63 | super.addSubview(view)
64 |
65 | // UISearchController removes this view and then adds it back. Move it to the back when it's added so it stays
66 | // below the borders.
67 | if view == searchBar {
68 | sendSubviewToBack(view)
69 | }
70 | }
71 |
72 | override func sizeThatFits(size: CGSize) -> CGSize {
73 | return CGSize(width: size.width, height: 44)
74 | }
75 |
76 | override func layoutSubviews() {
77 | let borderHeight = 1 / traitCollection.displayScale
78 |
79 | topBorderView.frame = CGRect(x: 0, y: 0, width: bounds.width, height: borderHeight)
80 | bottomBorderView.frame = CGRect(x: 0, y: bounds.height - borderHeight, width: bounds.width, height: borderHeight)
81 | }
82 |
83 | override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
84 | super.traitCollectionDidChange(previousTraitCollection)
85 | setNeedsLayout()
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Sources/SectionHeaderView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SectionHeaderView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 6/3/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasText
12 |
13 | class SectionHeaderView: UIView {
14 |
15 | // MARK: - Properties
16 |
17 | let textLabel: UILabel = {
18 | let label = UILabel()
19 | label.translatesAutoresizingMaskIntoConstraints = false
20 | label.textColor = Swatch.black
21 | return label
22 | }()
23 |
24 |
25 | // MARK: - Initializers
26 |
27 | convenience init(title: String) {
28 | self.init(frame: CGRect(x: 0, y: 0, width: 320, height: 30))
29 | textLabel.text = title
30 | }
31 |
32 | override init(frame: CGRect) {
33 | super.init(frame: frame)
34 |
35 | autoresizingMask = [.FlexibleWidth]
36 |
37 | addSubview(textLabel)
38 |
39 | NSLayoutConstraint.activateConstraints([
40 | textLabel.leadingAnchor.constraintEqualToAnchor(leadingAnchor, constant: 16),
41 | textLabel.trailingAnchor.constraintLessThanOrEqualToAnchor(trailingAnchor, constant: -16),
42 | textLabel.topAnchor.constraintEqualToAnchor(topAnchor, constant: 4),
43 | textLabel.bottomAnchor.constraintEqualToAnchor(bottomAnchor, constant: -4)
44 | ])
45 |
46 | NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(updateFont), name: UIContentSizeCategoryDidChangeNotification, object: nil)
47 | updateFont()
48 | }
49 |
50 | required init?(coder aDecoder: NSCoder) {
51 | fatalError("init(coder:) has not been implemented")
52 | }
53 |
54 |
55 | // MARK: - UIView
56 |
57 | override func tintColorDidChange() {
58 | super.tintColorDidChange()
59 | backgroundColor = tintAdjustmentMode == .Dimmed ? Swatch.extraLightGray.desaturated : Swatch.extraLightGray
60 | }
61 |
62 |
63 | // MARK: - Fonts
64 |
65 | func updateFont() {
66 | textLabel.font = TextStyle.callout.font(weight: .medium)
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Sources/SharedWebCredentials.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SharedWebCredentials.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 6/10/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Security
11 |
12 | struct SharedWebCredentials {
13 |
14 | // MARK: - Types
15 |
16 | struct Credential {
17 | let domain: String
18 | let account: String
19 | let password: String
20 |
21 | init?(dictionary: NSDictionary) {
22 | let dict = dictionary as Dictionary
23 |
24 | guard let domain = dict[kSecAttrServer] as? String,
25 | account = dict[kSecAttrAccount] as? String,
26 | password = dict[kSecSharedPassword] as? String
27 | else { return nil }
28 |
29 | self.domain = domain
30 | self.account = account
31 | self.password = password
32 | }
33 | }
34 |
35 |
36 | // MARK: - Accessing Credentials
37 |
38 | static func get(domain domain: String? = nil, account: String? = nil, completion: (credential: Credential?, error: CFError?) -> Void) {
39 | if NSProcessInfo.processInfo().isSnapshotting {
40 | completion(credential: nil, error: nil)
41 | return
42 | }
43 |
44 | SecRequestSharedWebCredential(domain, account) { array, error in
45 | let credential: Credential?
46 |
47 | if let array = array as Array?, dictionary = array.first as? NSDictionary {
48 | credential = Credential(dictionary: dictionary)
49 | } else {
50 | credential = nil
51 | }
52 |
53 | completion(credential: credential, error: error)
54 | }
55 | }
56 |
57 | static func add(domain domain: String, account: String, password: String, completion: ((error: CFError?) -> Void)? = nil) {
58 | if NSProcessInfo.processInfo().isSnapshotting {
59 | completion?(error: nil)
60 | return
61 | }
62 |
63 | SecAddSharedWebCredential(domain, account, password) { error in
64 | completion?(error: error)
65 | }
66 | }
67 |
68 | static func remove(domain domain: String, account: String, completion: ((error: CFError?) -> Void)? = nil) {
69 | if NSProcessInfo.processInfo().isSnapshotting {
70 | completion?(error: nil)
71 | return
72 | }
73 |
74 | SecAddSharedWebCredential(domain, account, nil) { error in
75 | completion?(error: error)
76 | }
77 | }
78 |
79 | static func generatePassword() -> String? {
80 | return SecCreateSharedWebCredentialPassword() as String?
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Sources/SignUpViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SignUpViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 6/25/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasKit
12 | import OnePasswordExtension
13 |
14 | // TODO: Localize
15 | final class SignUpViewController: SessionFormViewController {
16 |
17 | // MARK: - Properties
18 |
19 | let usernameTextField: UITextField = {
20 | let textField = TextField()
21 | textField.keyboardType = .ASCIICapable
22 | textField.placeholder = "username"
23 | textField.returnKeyType = .Next
24 | textField.autocapitalizationType = .None
25 | textField.autocorrectionType = .No
26 | textField.setContentCompressionResistancePriority(UILayoutPriorityDefaultLow, forAxis: .Horizontal)
27 | return textField
28 | }()
29 |
30 |
31 | // MARK: - UIViewController
32 |
33 | override func viewDidLoad() {
34 | super.viewDidLoad()
35 |
36 | title = "Sign up for Canvas"
37 | submitButton.setTitle("Sign Up", forState: .Normal)
38 |
39 | emailTextField.placeholder = "email@example.com"
40 |
41 | footerButton.set(preface: "Already have an account?", title: "Log in.")
42 | }
43 |
44 |
45 | // MARK: - SessionsViewController
46 |
47 | override var textFields: [UITextField] {
48 | var fields = super.textFields
49 | fields.insert(usernameTextField, atIndex: 0)
50 | return fields
51 | }
52 |
53 |
54 | // MARK: - Actions
55 |
56 | override func submit() {
57 | guard let email = emailTextField.text, username = usernameTextField.text, password = passwordTextField.text
58 | where !email.isEmpty && !username.isEmpty && !password.isEmpty
59 | else { return }
60 |
61 | loading = true
62 |
63 | let client = AuthorizationClient()
64 | client.createAccount(email: email, username: username, password: password) { [weak self] in
65 | switch $0 {
66 | case .Success(_):
67 | dispatch_async(dispatch_get_main_queue()) {
68 | UIApplication.sharedApplication().networkActivityIndicatorVisible = false
69 | self?.showVerify()
70 | // Analytics.track(.LoggedIn)
71 | }
72 | case .Failure(let errorMessage):
73 | dispatch_async(dispatch_get_main_queue()) { [weak self] in
74 | self?.loading = false
75 | // self?.passwordTextField.becomeFirstResponder()
76 | //
77 | let alert = UIAlertController(title: "Double Check That", message: errorMessage, preferredStyle: .Alert)
78 | alert.addAction(UIAlertAction(title: LocalizedString.Okay.string, style: .Cancel, handler: nil))
79 | self?.presentViewController(alert, animated: true, completion: nil)
80 | }
81 | }
82 | }
83 | }
84 |
85 | override func onePassword(sender: AnyObject?) {
86 | let details = [
87 | AppExtensionTitleKey: "Canvas"
88 | ]
89 |
90 | let passwordOptions = [
91 | AppExtensionGeneratedPasswordMinLengthKey: 8,
92 | AppExtensionGeneratedPasswordMaxLengthKey: 128
93 | ]
94 |
95 | OnePasswordExtension.sharedExtension().storeLoginForURLString("https://usecanvas.com", loginDetails: details, passwordGenerationOptions: passwordOptions, forViewController: self, sender: sender, completion: signUp)
96 | }
97 |
98 |
99 | // MARK: - Private
100 |
101 | private func showVerify() {
102 | guard let rootViewController = UIApplication.sharedApplication().delegate?.window??.rootViewController as? RootViewController else { return }
103 | rootViewController.viewController = VerifyViewController()
104 | }
105 |
106 | private func signUp(onePassword loginDictionary: [NSObject: AnyObject]?, error: NSError?) {
107 | if let username = loginDictionary?[AppExtensionUsernameKey] as? String {
108 | if username.containsString("@") {
109 | emailTextField.text = username
110 | usernameTextField.becomeFirstResponder()
111 | } else {
112 | usernameTextField.text = username
113 | emailTextField.becomeFirstResponder()
114 | }
115 | }
116 |
117 | if let password = loginDictionary?[AppExtensionPasswordKey] as? String {
118 | passwordTextField.text = password
119 | }
120 | }
121 | }
122 |
123 |
--------------------------------------------------------------------------------
/Sources/SleepPickerViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SleepPickerViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 6/28/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Static
11 |
12 | final class SleepPickerViewController: TableViewController {
13 |
14 | // MARK: - Initializers
15 |
16 | convenience init() {
17 | self.init(style: .Grouped)
18 | title = "Prevent Display Sleep"
19 | }
20 |
21 |
22 | // MARK: - UIViewController
23 |
24 | override func viewDidLoad() {
25 | super.viewDidLoad()
26 |
27 | let preference = SleepPrevention.currentPreference
28 | let rows: [Row] = SleepPrevention.all.map { option in
29 | let accessory: Row.Accessory = option == preference ? .Checkmark : .None
30 | return Row(text: option.description, selection: { [weak self] in
31 | self?.select(option)
32 | }, accessory: accessory)
33 | }
34 |
35 | dataSource.sections = [
36 | Section(rows: rows)
37 | ]
38 | }
39 |
40 |
41 | // MARK: - Private
42 |
43 | private func select(preference: SleepPrevention) {
44 | SleepPrevention.select(preference)
45 | navigationController?.popViewControllerAnimated(true)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Sources/SleepPrevention.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SleepPrevention.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 6/28/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum SleepPrevention: String, CustomStringConvertible {
12 | case never
13 | case whilePluggedIn
14 | case always
15 |
16 | var description: String {
17 | switch self {
18 | case .never: return "System Default"
19 | case .whilePluggedIn: return "While Plugged In"
20 | case .always: return "Never Sleep"
21 | }
22 | }
23 |
24 | static let all: [SleepPrevention] = [.never, .whilePluggedIn, .always]
25 |
26 | static let defaultsKey = "PreventSleep"
27 |
28 | static var currentPreference: SleepPrevention {
29 | guard let string = NSUserDefaults.standardUserDefaults().stringForKey(defaultsKey) else { return .whilePluggedIn }
30 | return SleepPrevention(rawValue: string) ?? .whilePluggedIn
31 | }
32 |
33 | static func select(preference: SleepPrevention) {
34 | NSUserDefaults.standardUserDefaults().setObject(preference.rawValue, forKey: defaultsKey)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Sources/StackViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StackViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 6/25/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 |
12 | class StackViewController: UIViewController {
13 |
14 | // MARK: - Properties
15 |
16 | let stackView: UIStackView = {
17 | let view = UIStackView()
18 | view.translatesAutoresizingMaskIntoConstraints = false
19 | view.axis = .Vertical
20 | view.alignment = .Fill
21 | return view
22 | }()
23 |
24 | private var centerYConstraint: NSLayoutConstraint? {
25 | willSet {
26 | guard let old = centerYConstraint else { return }
27 | NSLayoutConstraint.deactivateConstraints([old])
28 | }
29 |
30 | didSet {
31 | guard let new = centerYConstraint else { return }
32 | NSLayoutConstraint.activateConstraints([new])
33 | }
34 | }
35 |
36 | private var keyboardFrame: CGRect? {
37 | didSet {
38 | keyboardFrameDidChange()
39 | }
40 | }
41 |
42 | private var visible = false
43 |
44 |
45 | // MARK: - UIViewController
46 |
47 | override func viewDidLoad() {
48 | super.viewDidLoad()
49 |
50 | view.backgroundColor = Swatch.white
51 | view.addSubview(stackView)
52 |
53 | let width = stackView.widthAnchor.constraintEqualToAnchor(view.widthAnchor, multiplier: 0.8)
54 | width.priority = UILayoutPriorityDefaultHigh
55 |
56 | let top = stackView.topAnchor.constraintGreaterThanOrEqualToAnchor(view.topAnchor, constant: 64)
57 | top.priority = UILayoutPriorityDefaultLow
58 |
59 | NSLayoutConstraint.activateConstraints([
60 | stackView.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor),
61 | top,
62 | width,
63 | stackView.widthAnchor.constraintLessThanOrEqualToConstant(400)
64 | ])
65 |
66 | NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWillChangeFrame), name: UIKeyboardWillChangeFrameNotification, object: nil)
67 | keyboardFrameDidChange()
68 | }
69 |
70 | override func viewDidAppear(animated: Bool) {
71 | super.viewDidAppear(animated)
72 |
73 | dispatch_async(dispatch_get_main_queue()) { [weak self] in
74 | self?.visible = true
75 | }
76 | }
77 |
78 | override func viewDidDisappear(animated: Bool) {
79 | super.viewDidDisappear(animated)
80 | visible = false
81 | }
82 |
83 |
84 | // MARK: - Private
85 |
86 | @objc private func keyboardWillChangeFrame(notification: NSNotification) {
87 | guard let dictionary = notification.userInfo as? [String: AnyObject],
88 | duration = dictionary[UIKeyboardAnimationDurationUserInfoKey] as? NSTimeInterval,
89 | curve = (dictionary[UIKeyboardAnimationCurveUserInfoKey] as? Int).flatMap(UIViewAnimationCurve.init),
90 | rect = (dictionary[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
91 | else { return }
92 |
93 | let frame = view.convertRect(rect, fromView: nil)
94 |
95 | let change = { [weak self] in
96 | self?.keyboardFrame = frame
97 | self?.view.layoutIfNeeded()
98 | }
99 |
100 | if visible {
101 | UIView.beginAnimations(nil, context: nil)
102 | UIView.setAnimationDuration(duration)
103 | UIView.setAnimationCurve(curve)
104 | change()
105 | UIView.commitAnimations()
106 | } else {
107 | UIView.performWithoutAnimation(change)
108 | }
109 | }
110 |
111 | private func keyboardFrameDidChange() {
112 | guard let keyboardFrame = keyboardFrame else {
113 | centerYConstraint = stackView.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor)
114 | return
115 | }
116 |
117 | var rect = view.bounds
118 | rect.size.height -= rect.intersect(keyboardFrame).height
119 | rect.origin.y += UIApplication.sharedApplication().statusBarFrame.size.height
120 | rect.size.height -= UIApplication.sharedApplication().statusBarFrame.size.height
121 |
122 | let contstraint = stackView.centerYAnchor.constraintEqualToAnchor(view.topAnchor, constant: rect.midY)
123 | contstraint.priority = UILayoutPriorityDefaultHigh
124 |
125 | centerYConstraint = contstraint
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/Sources/TableView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TableView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 6/6/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 |
12 | final class TableView: UITableView {
13 | override func tintColorDidChange() {
14 | super.tintColorDidChange()
15 |
16 | if style != .Grouped {
17 | return
18 | }
19 |
20 | backgroundColor = tintAdjustmentMode == .Dimmed ? Swatch.groupedTableBackground.desaturated : Swatch.groupedTableBackground
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/TableViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TableViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 11/23/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Static
11 | import CanvasCore
12 |
13 | class TableViewController: UIViewController {
14 |
15 | // MARK: - Properties
16 |
17 | let tableView: UITableView
18 |
19 | /// Table view data source.
20 | var dataSource = DataSource() {
21 | willSet {
22 | dataSource.tableView = nil
23 | }
24 |
25 | didSet {
26 | dataSource.tableView = tableView
27 | }
28 | }
29 |
30 | // MARK: - Initializers
31 |
32 | init(style: UITableViewStyle) {
33 | tableView = TableView(frame: .zero, style: style)
34 | tableView.translatesAutoresizingMaskIntoConstraints = false
35 | tableView.separatorColor = Swatch.border
36 |
37 | dataSource.tableView = tableView
38 |
39 | super.init(nibName: nil, bundle: nil)
40 | }
41 |
42 | required init?(coder aDecoder: NSCoder) {
43 | fatalError("init(coder:) has not been implemented")
44 | }
45 |
46 |
47 | // MARK: - UIViewController
48 |
49 | override func viewDidLoad() {
50 | super.viewDidLoad()
51 |
52 | view.addSubview(tableView)
53 |
54 | NSLayoutConstraint.activateConstraints([
55 | tableView.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor),
56 | tableView.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor),
57 | tableView.topAnchor.constraintEqualToAnchor(view.topAnchor),
58 | tableView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor),
59 | ])
60 |
61 | dataSource.automaticallyDeselectRows = false
62 | dataSource.tableView = tableView
63 | }
64 |
65 | override func viewWillAppear(animated: Bool) {
66 | super.viewWillAppear(animated)
67 |
68 | tableView.indexPathsForSelectedRows?.forEach { indexPath in
69 | tableView.deselectRowAtIndexPath(indexPath, animated: false)
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Sources/TextField.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TextField.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 11/26/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasText
12 |
13 | final class TextField: UITextField {
14 |
15 | // MARK: - Properties
16 |
17 | override var placeholder: String? {
18 | didSet {
19 | guard let placeholder = placeholder, font = font else { return }
20 | attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [
21 | NSFontAttributeName: font,
22 | NSForegroundColorAttributeName: Swatch.darkGray
23 | ])
24 | }
25 | }
26 |
27 | // MARK: - Initializers
28 |
29 | override init(frame: CGRect) {
30 | super.init(frame: frame)
31 |
32 | backgroundColor = Swatch.extraLightGray
33 |
34 | textColor = Swatch.black
35 | tintColor = Swatch.brand
36 |
37 | layer.cornerRadius = 4
38 |
39 | NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(updateFont), name: UIContentSizeCategoryDidChangeNotification, object: nil)
40 | updateFont()
41 | }
42 |
43 | required init?(coder aDecoder: NSCoder) {
44 | fatalError("init(coder:) has not been implemented")
45 | }
46 |
47 |
48 | // MARK: - UIView
49 |
50 | override func intrinsicContentSize() -> CGSize {
51 | var size = super.intrinsicContentSize()
52 | size.height = 48
53 | return size
54 | }
55 |
56 |
57 | // MARK: - UITextField
58 |
59 | override func textRectForBounds(bounds: CGRect) -> CGRect {
60 | var rect = bounds
61 |
62 | if rightView != nil {
63 | rect.size.width -= rect.intersect(rightViewRectForBounds(bounds)).width
64 | }
65 |
66 | return CGRectInset(rect, 12, 12)
67 | }
68 |
69 | override func placeholderRectForBounds(bounds: CGRect) -> CGRect {
70 | return textRectForBounds(bounds)
71 | }
72 |
73 | override func editingRectForBounds(bounds: CGRect) -> CGRect {
74 | return textRectForBounds(bounds)
75 | }
76 |
77 | override func rightViewRectForBounds(bounds: CGRect) -> CGRect {
78 | var rect = super.rightViewRectForBounds(bounds)
79 | rect.origin.x -= 6
80 | return rect
81 | }
82 |
83 |
84 | // MARK: - Private
85 |
86 | @objc private func updateFont() {
87 | font = TextStyle.body.font()
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/Sources/TextView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TextView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 3/8/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasText
11 |
12 | class TextView: UITextView {
13 |
14 | // MARK: - Properties
15 |
16 | var managedSubviews = Set()
17 |
18 |
19 | // MARK: - UIView
20 |
21 | // Allow subviews to receive user input
22 | override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
23 | for view in managedSubviews {
24 | if view.superview == self && view.userInteractionEnabled && view.frame.contains(point) {
25 | return view
26 | }
27 | }
28 |
29 | return super.hitTest(point, withEvent: event)
30 | }
31 |
32 |
33 | // MARK: - UITextInput
34 |
35 | // Only display the caret in the used rect (if available).
36 | override func caretRectForPosition(position: UITextPosition) -> CGRect {
37 | var rect = super.caretRectForPosition(position)
38 |
39 | if let layoutManager = textContainer.layoutManager {
40 | layoutManager.ensureLayoutForTextContainer(textContainer)
41 |
42 | let characterIndex = offsetFromPosition(beginningOfDocument, toPosition: position)
43 | if characterIndex == textStorage.length {
44 | return rect
45 | }
46 |
47 | let glyphIndex = layoutManager.glyphIndexForCharacterAtIndex(characterIndex)
48 |
49 | if UInt(glyphIndex) == UInt.max - 1 {
50 | return rect
51 | }
52 |
53 | let usedRect = layoutManager.lineFragmentUsedRectForGlyphAtIndex(glyphIndex, effectiveRange: nil)
54 |
55 | if usedRect.height > 0 {
56 | rect.origin.y = usedRect.minY + textContainerInset.top
57 | rect.size.height = usedRect.height
58 | }
59 | }
60 |
61 | return rect
62 | }
63 |
64 | // Omit empty width rect when drawing selection rects.
65 | override func selectionRectsForRange(range: UITextRange) -> [AnyObject] {
66 | let selectionRects = super.selectionRectsForRange(range)
67 | return selectionRects.filter({ selection in
68 | guard let selection = selection as? UITextSelectionRect else { return false }
69 | return selection.rect.size.width > 0
70 | })
71 | }
72 |
73 | func rectsForRange(range: NSRange) -> [CGRect] {
74 | // Become first responder if we aren't already. The text view has to be first responder for any of the position
75 | // or text range APIs to work. Annoying :(
76 | let wasFirstResponder = isFirstResponder()
77 | if !wasFirstResponder {
78 | becomeFirstResponder()
79 | }
80 |
81 | // Get starting position
82 | guard let start = positionFromPosition(beginningOfDocument, offset: range.location) else {
83 | if !wasFirstResponder {
84 | resignFirstResponder()
85 | }
86 | return []
87 | }
88 |
89 | // Empty selection
90 | if range.length == 0 {
91 | if !wasFirstResponder {
92 | resignFirstResponder()
93 | }
94 | return [caretRectForPosition(start)]
95 | }
96 |
97 | // Selection
98 | guard let end = positionFromPosition(start, offset: range.length),
99 | textRange = textRangeFromPosition(start, toPosition: end),
100 | selectionRects = (super.selectionRectsForRange(textRange) as? [UITextSelectionRect])?.map({ $0.rect }),
101 | firstRect = selectionRects.first
102 | else {
103 | // Use extra line if there aren't any rects
104 | var rect = layoutManager.extraLineFragmentUsedRect
105 | rect.origin.x += textContainerInset.left
106 | rect.origin.y += textContainerInset.top
107 |
108 | if !wasFirstResponder {
109 | resignFirstResponder()
110 | }
111 |
112 | return [rect]
113 | }
114 |
115 | if !wasFirstResponder {
116 | resignFirstResponder()
117 | }
118 |
119 | let filtered = selectionRects.filter { $0.width > 0 }
120 |
121 | if filtered.isEmpty {
122 | return [firstRect]
123 | }
124 |
125 | return filtered
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/Sources/TickingLabel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TickingLabel.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 1/28/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final class TickingLabel: UILabel {
12 |
13 | // MARK: - Properties
14 |
15 | var date: NSDate? {
16 | didSet {
17 | tick()
18 | }
19 | }
20 |
21 | private static var timer: NSTimer?
22 | private static let tickNotificationName = "TickingLabel.tickNotification"
23 | private static var setupToken: dispatch_once_t = 0
24 |
25 |
26 | // MARK: - Initializers
27 |
28 | override init(frame: CGRect) {
29 | super.init(frame: frame)
30 |
31 | NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(tick), name: self.dynamicType.tickNotificationName, object: nil)
32 |
33 | dispatch_once(&self.dynamicType.setupToken) {
34 | self.dynamicType.setupTimer()
35 | }
36 | }
37 |
38 | required init?(coder aDecoder: NSCoder) {
39 | fatalError("init(coder:) has not been implemented")
40 | }
41 |
42 |
43 | // MARK: - Private
44 |
45 | private class func setupTimer() {
46 | NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(applicationWillResignActive), name: UIApplicationWillResignActiveNotification, object: nil)
47 | NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(applicationDidBecomeActive), name: UIApplicationDidBecomeActiveNotification, object: nil)
48 | applicationDidBecomeActive()
49 | }
50 |
51 | @objc private class func fire() {
52 | NSNotificationCenter.defaultCenter().postNotificationName(tickNotificationName, object: nil)
53 | }
54 |
55 | @objc private class func applicationWillResignActive() {
56 | timer?.invalidate()
57 | timer = nil
58 | }
59 |
60 | @objc private class func applicationDidBecomeActive() {
61 | let timer = NSTimer(timeInterval: 1, target: self, selector: #selector(fire), userInfo: nil, repeats: true)
62 | timer.tolerance = 0.5
63 | self.timer = timer
64 |
65 | NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
66 | }
67 |
68 | @objc private func tick() {
69 | text = date?.briefTimeAgoInWords
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Sources/TintableEnvironment.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TintableEnvironment.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 1/12/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol TintableEnvironment {
12 | var preferredTintColor: UIColor { get }
13 | }
14 |
--------------------------------------------------------------------------------
/Sources/TintableView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TintableView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 1/14/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class TintableView: UIView {
12 |
13 | // MARK: - Properties
14 |
15 | var highlighted = false {
16 | didSet {
17 | updateTintColor()
18 | }
19 | }
20 |
21 | var normalTintColor: UIColor? {
22 | didSet {
23 | updateTintColor()
24 | }
25 | }
26 |
27 | var highlightedTintColor: UIColor? {
28 | didSet {
29 | updateTintColor()
30 | }
31 | }
32 |
33 | private var settingTintColor = false
34 |
35 |
36 | // MARK: - UIView
37 |
38 | override func tintColorDidChange() {
39 | super.tintColorDidChange()
40 |
41 | if settingTintColor {
42 | settingTintColor = false
43 | return
44 | }
45 |
46 | normalTintColor = tintColor
47 | }
48 |
49 |
50 | // MARK: - Tinting
51 |
52 | func updateTintColor() {
53 | settingTintColor = true
54 | tintColor = highlighted ? highlightedTintColor : normalTintColor
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Sources/TitleView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TitleView.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 6/29/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 |
12 | final class TitleView: UIView {
13 |
14 | // MARK: - Properties
15 |
16 | var showsLock = false {
17 | didSet {
18 | lockView.hidden = !showsLock
19 | setNeedsLayout()
20 | }
21 | }
22 |
23 | var title = "" {
24 | didSet {
25 | titleLabel.text = title
26 | setNeedsLayout()
27 | }
28 | }
29 |
30 | private let lockView: UIImageView = {
31 | let view = UIImageView(image: UIImage(named: "Lock"))
32 | view.tintColor = Swatch.darkGray
33 | return view
34 | }()
35 |
36 | private let titleLabel: UILabel = {
37 | let label = UILabel()
38 | label.textColor = Swatch.darkGray
39 | label.font = Font.sansSerif(weight: .medium)
40 | return label
41 | }()
42 |
43 | private let spacing: CGFloat = 4
44 |
45 |
46 | // MARK: - Initializers
47 |
48 | init() {
49 | super.init(frame: .zero)
50 |
51 | autoresizingMask = [.FlexibleWidth]
52 |
53 | lockView.sizeToFit()
54 |
55 | addSubview(lockView)
56 | addSubview(titleLabel)
57 | }
58 |
59 | required init?(coder aDecoder: NSCoder) {
60 | fatalError("init(coder:) has not been implemented")
61 | }
62 |
63 |
64 | // MARK: - UIView
65 |
66 | override class func layerClass() -> AnyClass {
67 | return CATransformLayer.self
68 | }
69 |
70 | override func layoutSubviews() {
71 | let size = bounds.size
72 | let titleSize = titleLabel.sizeThatFits(size)
73 | var titleFrame = CGRect(x: round((size.width - titleSize.width) / 2), y: round((size.height - titleSize.height) / 2), width: titleSize.width, height: titleSize.height)
74 |
75 | if showsLock {
76 | let lockSize = lockView.bounds.size
77 | titleFrame.origin.x += round((lockSize.width + spacing) / 2)
78 | lockView.frame = CGRect(x: titleFrame.origin.x - lockSize.width - spacing, y: round((size.height - lockSize.height) / 2), width: lockSize.width, height: lockSize.height)
79 | }
80 |
81 | if titleFrame.maxX > bounds.width {
82 | if showsLock {
83 | lockView.frame.origin.x = 0
84 | titleFrame.origin.x = lockView.frame.maxX + spacing
85 | } else {
86 | titleFrame.origin.x = 0
87 | }
88 |
89 | titleFrame.size.width = bounds.width - titleFrame.minX
90 | }
91 |
92 | titleLabel.frame = titleFrame
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/Sources/UIActivity+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIActivity+Canvas.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/16/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIActivity {
12 | func showBanner(text text: String, style: BannerView.Style = .success) {
13 | guard let rootViewController = UIApplication.sharedApplication().delegate?.window??.rootViewController as? RootViewController,
14 | splitViewController = rootViewController.viewController as? SplitViewController,
15 | var viewController = splitViewController.viewControllers.last
16 | else { return }
17 |
18 | if let top = (viewController as? UINavigationController)?.topViewController {
19 | viewController = top
20 | }
21 |
22 | rootViewController._showBanner(text: text, style: style, inViewController: viewController)
23 |
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Sources/UIColor+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+Canvas.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 6/6/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIColor {
12 | var desaturated: UIColor {
13 | var hue: CGFloat = 0
14 | var brightness: CGFloat = 0
15 | var alpha: CGFloat = 0
16 |
17 | getHue(&hue, saturation: nil, brightness: &brightness, alpha: &alpha)
18 |
19 | return self.dynamicType.init(hue: hue, saturation: 0, brightness: brightness, alpha: alpha)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/UIEdgeInsets+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIEdgeInsets+Canvas.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 11/26/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIEdgeInsets {
12 | init(_ value: CGFloat) {
13 | top = value
14 | left = value
15 | right = value
16 | bottom = value
17 | }
18 |
19 | static let zero = UIEdgeInsets(0)
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/UIFont+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIFont+Canvas.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 12/16/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIFont {
12 | var fontWithMonospaceNumbers: UIFont {
13 | let fontDescriptor = UIFontDescriptor(name: fontName, size: pointSize).fontDescriptorByAddingAttributes([
14 | UIFontDescriptorFeatureSettingsAttribute: [
15 | [
16 | UIFontFeatureTypeIdentifierKey: kNumberSpacingType,
17 | UIFontFeatureSelectorIdentifierKey: kMonospacedNumbersSelector
18 | ]
19 | ]
20 | ])
21 |
22 | return UIFont(descriptor: fontDescriptor, size: pointSize)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Sources/UISplitViewController+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UISplitViewController+Canvas.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 6/8/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UISplitViewController {
12 | convenience init(masterViewController: UIViewController, detailViewController: UIViewController) {
13 | self.init()
14 | viewControllers = [masterViewController, detailViewController]
15 | }
16 |
17 | var masterViewController: UIViewController? {
18 | return viewControllers.first
19 | }
20 |
21 | var detailViewController: UIViewController? {
22 | guard viewControllers.count == 2 else { return nil }
23 | return viewControllers.last
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Sources/UIViewController+Canvas.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Canvas.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 5/11/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIViewController {
12 | func present(actionSheet actionSheet: UIViewController, sender: AnyObject?, animated: Bool = true, completion: (() -> Void)? = nil) {
13 | if let popover = actionSheet.popoverPresentationController {
14 | if let button = sender as? UIBarButtonItem {
15 | popover.barButtonItem = button
16 | } else if let sourceView = sender as? UIView {
17 | popover.sourceView = sourceView
18 | } else {
19 | popover.sourceView = view
20 | }
21 | }
22 |
23 | presentViewController(actionSheet, animated: animated, completion: completion)
24 | }
25 |
26 | func dismissDetailViewController(sender: AnyObject?) {
27 | if let splitViewController = splitViewController where !splitViewController.collapsed {
28 | splitViewController.dismissDetailViewController(sender)
29 | return
30 | }
31 |
32 | if let presenter = targetViewControllerForAction(#selector(dismissDetailViewController), sender: sender) {
33 | presenter.dismissDetailViewController(self)
34 | }
35 | }
36 |
37 | func showBanner(text text: String, style: BannerView.Style = .success) {
38 | guard let rootViewController = UIApplication.sharedApplication().delegate?.window??.rootViewController as? RootViewController else { return }
39 | rootViewController._showBanner(text: text, style: style, inViewController: self)
40 |
41 | }
42 | }
43 |
44 |
45 | extension UINavigationController {
46 | override func dismissDetailViewController(sender: AnyObject?) {
47 | // Hack to fix nested navigation controllers that split view makes. Ugh.
48 | if viewControllers.count == 1 {
49 | navigationController?.popViewControllerAnimated(true)
50 | return
51 | }
52 | popViewControllerAnimated(true)
53 | }
54 | }
55 |
56 |
57 | extension UISplitViewController {
58 | override func dismissDetailViewController(sender: AnyObject?) {
59 | showDetailViewController(NavigationController(rootViewController: PlaceholderViewController()), sender: sender)
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Sources/UserCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserCell.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 8/9/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CanvasCore
11 | import CanvasKit
12 | import Static
13 |
14 | final class UserCell: UITableViewCell {
15 |
16 | // MARK: - Properties
17 |
18 | private let avatarView: AvatarView = {
19 | let view = AvatarView()
20 | view.translatesAutoresizingMaskIntoConstraints = false
21 | return view
22 | }()
23 |
24 | private let usernameLabel: UILabel = {
25 | let label = UILabel()
26 | label.translatesAutoresizingMaskIntoConstraints = false
27 | label.textColor = Swatch.black
28 | return label
29 | }()
30 |
31 |
32 | // MARK: - Initializers
33 |
34 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
35 | super.init(style: style, reuseIdentifier: reuseIdentifier)
36 |
37 | contentView.addSubview(avatarView)
38 | contentView.addSubview(usernameLabel)
39 |
40 | NSLayoutConstraint.activateConstraints([
41 | avatarView.topAnchor.constraintEqualToAnchor(contentView.layoutMarginsGuide.topAnchor),
42 | avatarView.bottomAnchor.constraintEqualToAnchor(contentView.layoutMarginsGuide.bottomAnchor),
43 | avatarView.leadingAnchor.constraintEqualToAnchor(contentView.layoutMarginsGuide.leadingAnchor),
44 |
45 | usernameLabel.centerYAnchor.constraintEqualToAnchor(avatarView.centerYAnchor),
46 | usernameLabel.leadingAnchor.constraintEqualToAnchor(avatarView.trailingAnchor, constant: 16),
47 | usernameLabel.trailingAnchor.constraintLessThanOrEqualToAnchor(contentView.layoutMarginsGuide.trailingAnchor)
48 | ])
49 | }
50 |
51 | required init?(coder aDecoder: NSCoder) {
52 | fatalError("init(coder:) has not been implemented")
53 | }
54 | }
55 |
56 |
57 | extension UserCell: CellType {
58 | func configure(row row: Row) {
59 | usernameLabel.text = row.text
60 | avatarView.user = row.context?["user"] as? User
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Sources/ValueCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ValueCell.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 7/1/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Static
11 | import CanvasCore
12 |
13 | final class ValueCell: UITableViewCell, CellType {
14 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
15 | super.init(style: .Value1, reuseIdentifier: reuseIdentifier)
16 | textLabel?.textColor = Swatch.black
17 | detailTextLabel?.textColor = Swatch.darkGray
18 | }
19 |
20 | required init?(coder aDecoder: NSCoder) {
21 | fatalError("init(coder:) has not been implemented")
22 | }
23 |
24 | func configure(row row: Row) {
25 | textLabel?.text = row.text
26 | detailTextLabel?.text = row.detailText
27 | imageView?.image = row.image
28 |
29 | switch row.accessory {
30 | case .DisclosureIndicator:
31 | let view = UIImageView(image: UIImage(named: "ChevronRightSmall"))
32 | view.tintColor = Swatch.lightGray
33 | accessoryView = view
34 | default:
35 | accessoryType = row.accessory.type
36 | accessoryView = row.accessory.view
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Sources/WebActivity.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WebActivity.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 11/18/15.
6 | // Copyright © 2015 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class WebActivity: UIActivity {
12 |
13 | // MARK: - Properties
14 |
15 | var URL: NSURL?
16 | var schemePrefix: String?
17 |
18 |
19 | // MARK: - UIActivity
20 |
21 | override func prepareWithActivityItems(activityItems: [AnyObject]) {
22 | for activityItem in activityItems {
23 | if let URL = activityItem as? NSURL {
24 | self.URL = URL
25 | return
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Sources/WebViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WebViewController.swift
3 | // Canvas
4 | //
5 | // Created by Sam Soffes on 1/28/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SafariServices
11 |
12 | final class WebViewController: SFSafariViewController {
13 |
14 | // MARK: - Properties
15 |
16 | let originalURL: NSURL
17 |
18 |
19 | // MARK: - Initializers
20 |
21 | convenience init(URL: NSURL) {
22 | self.init(URL: URL, entersReaderIfAvailable: false)
23 | }
24 |
25 | override init(URL: NSURL, entersReaderIfAvailable: Bool) {
26 | originalURL = URL
27 | super.init(URL: URL, entersReaderIfAvailable: entersReaderIfAvailable)
28 | }
29 |
30 |
31 | // MARK: - UIViewController
32 |
33 | override func previewActionItems() -> [UIPreviewActionItem] {
34 | let copyAction = UIPreviewAction(title: "Copy URL", style: .Default) { [weak self] _, _ in
35 | UIPasteboard.generalPasteboard().URL = self?.originalURL
36 | }
37 |
38 | let safariAction = UIPreviewAction(title: "Open in Safari", style: .Default) { [weak self] _, _ in
39 | guard let URL = self?.originalURL else { return }
40 | UIApplication.sharedApplication().openURL(URL)
41 | }
42 |
43 | return [copyAction, safariAction]
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Support/Assets.xcassets/1Password.imageset/1Password.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/1Password.imageset/1Password.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/1Password.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "1Password.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Chrome.imageset/Chrome.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Activity Icons/Chrome.imageset/Chrome.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Chrome.imageset/Chrome~iPad.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Activity Icons/Chrome.imageset/Chrome~iPad.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Chrome.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "filename" : "Chrome.pdf"
6 | },
7 | {
8 | "idiom" : "ipad",
9 | "filename" : "Chrome~iPad.pdf"
10 | }
11 | ],
12 | "info" : {
13 | "version" : 1,
14 | "author" : "xcode"
15 | }
16 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Copy HTML.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "filename" : "Copy HTML.pdf"
6 | },
7 | {
8 | "idiom" : "ipad",
9 | "filename" : "Copy HTML~iPad.pdf"
10 | }
11 | ],
12 | "info" : {
13 | "version" : 1,
14 | "author" : "xcode"
15 | }
16 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Copy HTML.imageset/Copy HTML.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Activity Icons/Copy HTML.imageset/Copy HTML.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Copy HTML.imageset/Copy HTML~iPad.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Activity Icons/Copy HTML.imageset/Copy HTML~iPad.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Copy JSON.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "filename" : "Copy JSON.pdf"
6 | },
7 | {
8 | "idiom" : "ipad",
9 | "filename" : "Copy JSON~iPad.pdf"
10 | }
11 | ],
12 | "info" : {
13 | "version" : 1,
14 | "author" : "xcode"
15 | }
16 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Copy JSON.imageset/Copy JSON.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Activity Icons/Copy JSON.imageset/Copy JSON.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Copy JSON.imageset/Copy JSON~iPad.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Activity Icons/Copy JSON.imageset/Copy JSON~iPad.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Copy Link.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "filename" : "Copy Link.pdf"
6 | },
7 | {
8 | "idiom" : "ipad",
9 | "filename" : "Copy Link~iPad.pdf"
10 | }
11 | ],
12 | "info" : {
13 | "version" : 1,
14 | "author" : "xcode"
15 | }
16 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Copy Link.imageset/Copy Link.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Activity Icons/Copy Link.imageset/Copy Link.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Copy Link.imageset/Copy Link~iPad.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Activity Icons/Copy Link.imageset/Copy Link~iPad.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Copy Markdown.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "filename" : "Copy Markdown.pdf"
6 | },
7 | {
8 | "idiom" : "ipad",
9 | "filename" : "Copy Markdown~iPad.pdf"
10 | }
11 | ],
12 | "info" : {
13 | "version" : 1,
14 | "author" : "xcode"
15 | }
16 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Copy Markdown.imageset/Copy Markdown.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Activity Icons/Copy Markdown.imageset/Copy Markdown.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Copy Markdown.imageset/Copy Markdown~iPad.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Activity Icons/Copy Markdown.imageset/Copy Markdown~iPad.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Safari.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "filename" : "Safari.pdf"
6 | },
7 | {
8 | "idiom" : "ipad",
9 | "filename" : "Safari~iPad.pdf"
10 | }
11 | ],
12 | "info" : {
13 | "version" : 1,
14 | "author" : "xcode"
15 | }
16 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Safari.imageset/Safari.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Activity Icons/Safari.imageset/Safari.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Activity Icons/Safari.imageset/Safari~iPad.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Activity Icons/Safari.imageset/Safari~iPad.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon-Dev.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "29x29",
5 | "idiom" : "iphone",
6 | "filename" : "Settings@2x-1.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "29x29",
11 | "idiom" : "iphone",
12 | "filename" : "Settings@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "40x40",
17 | "idiom" : "iphone",
18 | "filename" : "Spotlight@2x.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "40x40",
23 | "idiom" : "iphone",
24 | "filename" : "Spotlight@3x.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "60x60",
29 | "idiom" : "iphone",
30 | "filename" : "iPhone@2x.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "60x60",
35 | "idiom" : "iphone",
36 | "filename" : "iPhone@3x.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "29x29",
41 | "idiom" : "ipad",
42 | "filename" : "Settings.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "29x29",
47 | "idiom" : "ipad",
48 | "filename" : "Settings@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "40x40",
53 | "idiom" : "ipad",
54 | "filename" : "Spotlight.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "40x40",
59 | "idiom" : "ipad",
60 | "filename" : "Spotlight@2x-1.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "76x76",
65 | "idiom" : "ipad",
66 | "filename" : "iPad.png",
67 | "scale" : "1x"
68 | },
69 | {
70 | "size" : "76x76",
71 | "idiom" : "ipad",
72 | "filename" : "iPad@2x.png",
73 | "scale" : "2x"
74 | },
75 | {
76 | "size" : "83.5x83.5",
77 | "idiom" : "ipad",
78 | "filename" : "iPad Pro@2x.png",
79 | "scale" : "2x"
80 | }
81 | ],
82 | "info" : {
83 | "version" : 1,
84 | "author" : "xcode"
85 | },
86 | "properties" : {
87 | "pre-rendered" : true
88 | }
89 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon-Dev.appiconset/Settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon-Dev.appiconset/Settings.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon-Dev.appiconset/Settings@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon-Dev.appiconset/Settings@2x-1.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon-Dev.appiconset/Settings@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon-Dev.appiconset/Settings@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon-Dev.appiconset/Settings@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon-Dev.appiconset/Settings@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon-Dev.appiconset/Spotlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon-Dev.appiconset/Spotlight.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon-Dev.appiconset/Spotlight@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon-Dev.appiconset/Spotlight@2x-1.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon-Dev.appiconset/Spotlight@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon-Dev.appiconset/Spotlight@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon-Dev.appiconset/Spotlight@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon-Dev.appiconset/Spotlight@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon-Dev.appiconset/iPad Pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon-Dev.appiconset/iPad Pro@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon-Dev.appiconset/iPad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon-Dev.appiconset/iPad.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon-Dev.appiconset/iPad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon-Dev.appiconset/iPad@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon-Dev.appiconset/iPhone@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon-Dev.appiconset/iPhone@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon-Dev.appiconset/iPhone@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon-Dev.appiconset/iPhone@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "29x29",
5 | "idiom" : "iphone",
6 | "filename" : "Settings@2x-1.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "29x29",
11 | "idiom" : "iphone",
12 | "filename" : "Settings@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "40x40",
17 | "idiom" : "iphone",
18 | "filename" : "Spotlight@2x-1.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "40x40",
23 | "idiom" : "iphone",
24 | "filename" : "Spotlight@3x.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "60x60",
29 | "idiom" : "iphone",
30 | "filename" : "iPhone@2x.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "60x60",
35 | "idiom" : "iphone",
36 | "filename" : "iPhone@3x.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "29x29",
41 | "idiom" : "ipad",
42 | "filename" : "Settings.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "29x29",
47 | "idiom" : "ipad",
48 | "filename" : "Settings@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "40x40",
53 | "idiom" : "ipad",
54 | "filename" : "Spotlight.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "40x40",
59 | "idiom" : "ipad",
60 | "filename" : "Spotlight@2x.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "76x76",
65 | "idiom" : "ipad",
66 | "filename" : "iPad.png",
67 | "scale" : "1x"
68 | },
69 | {
70 | "size" : "76x76",
71 | "idiom" : "ipad",
72 | "filename" : "iPad@2x.png",
73 | "scale" : "2x"
74 | },
75 | {
76 | "size" : "83.5x83.5",
77 | "idiom" : "ipad",
78 | "filename" : "iPad Pro@2x.png",
79 | "scale" : "2x"
80 | }
81 | ],
82 | "info" : {
83 | "version" : 1,
84 | "author" : "xcode"
85 | },
86 | "properties" : {
87 | "pre-rendered" : true
88 | }
89 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon.appiconset/Settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon.appiconset/Settings.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon.appiconset/Settings@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon.appiconset/Settings@2x-1.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon.appiconset/Settings@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon.appiconset/Settings@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon.appiconset/Settings@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon.appiconset/Settings@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon.appiconset/Spotlight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon.appiconset/Spotlight.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon.appiconset/Spotlight@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon.appiconset/Spotlight@2x-1.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon.appiconset/Spotlight@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon.appiconset/Spotlight@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon.appiconset/Spotlight@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon.appiconset/Spotlight@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon.appiconset/iPad Pro@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon.appiconset/iPad Pro@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon.appiconset/iPad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon.appiconset/iPad.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon.appiconset/iPad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon.appiconset/iPad@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon.appiconset/iPhone@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon.appiconset/iPhone@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/AppIcon.appiconset/iPhone@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/AppIcon.appiconset/iPhone@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Document Icons/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Document Icons/Document Globe-Background.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Document Globe-Background.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Document Icons/Document Globe-Background.imageset/Document Globe-Background.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Document Icons/Document Globe-Background.imageset/Document Globe-Background.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Document Icons/Document Globe.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Document Globe.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Document Icons/Document Globe.imageset/Document Globe.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Document Icons/Document Globe.imageset/Document Globe.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Document Icons/Document-Blank.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "empty-document.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Document Icons/Document-Blank.imageset/empty-document.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Document Icons/Document-Blank.imageset/empty-document.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Document Icons/Document.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "document.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "original"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Document Icons/Document.imageset/document.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Document Icons/Document.imageset/document.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/CheckList.imageset/CheckList.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Gesture Icons/CheckList.imageset/CheckList.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/CheckList.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "CheckList.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/Heading2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Heading2.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/Heading2.imageset/Heading2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Gesture Icons/Heading2.imageset/Heading2.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/Heading3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Heading3.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/Heading3.imageset/Heading3.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Gesture Icons/Heading3.imageset/Heading3.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/Indent.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Indent.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/Indent.imageset/Indent.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Gesture Icons/Indent.imageset/Indent.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/OrderedList.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "OrderedList.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/OrderedList.imageset/OrderedList.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Gesture Icons/OrderedList.imageset/OrderedList.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/Outdent.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Outdent.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/Outdent.imageset/Outdent.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Gesture Icons/Outdent.imageset/Outdent.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/Paragraph.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Paragraph.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Gesture Icons/Paragraph.imageset/Paragraph.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Gesture Icons/Paragraph.imageset/Paragraph.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Icon-Small.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Icon-Small.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Icon-Small.imageset/Icon-Small.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Icon-Small.imageset/Icon-Small.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Illustration.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Illustration.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Illustration.imageset/Illustration.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Illustration.imageset/Illustration.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/IllustrationLight.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "IllustrationLight.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/IllustrationLight.imageset/IllustrationLight.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/IllustrationLight.imageset/IllustrationLight.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Illustrations/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Illustrations/Email.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "Email@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "Email@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Illustrations/Email.imageset/Email@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Illustrations/Email.imageset/Email@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Illustrations/Email.imageset/Email@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Illustrations/Email.imageset/Email@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Illustrations/No Participants.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "No Participants.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "No Participants@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "No Participants@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Illustrations/No Participants.imageset/No Participants.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Illustrations/No Participants.imageset/No Participants.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Illustrations/No Participants.imageset/No Participants@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Illustrations/No Participants.imageset/No Participants@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Illustrations/No Participants.imageset/No Participants@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Illustrations/No Participants.imageset/No Participants@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Illustrations/Not Found.imageset/404 Illustration.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Illustrations/Not Found.imageset/404 Illustration.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Illustrations/Not Found.imageset/404 Illustration@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Illustrations/Not Found.imageset/404 Illustration@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Illustrations/Not Found.imageset/404 Illustration@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Illustrations/Not Found.imageset/404 Illustration@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Illustrations/Not Found.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "404 Illustration.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "404 Illustration@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "404 Illustration@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/New Canvas Shortcut.imageset/Compose-Shortcut.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/New Canvas Shortcut.imageset/Compose-Shortcut.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/New Canvas Shortcut.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Compose-Shortcut.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/GesturesCompact.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "iphone",
9 | "filename" : "GesturesCompact@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "iphone",
14 | "filename" : "GesturesCompact@3x.png",
15 | "scale" : "3x"
16 | },
17 | {
18 | "idiom" : "ipad",
19 | "scale" : "1x"
20 | },
21 | {
22 | "idiom" : "ipad",
23 | "filename" : "GesturesCompact@2x~iPad.png",
24 | "scale" : "2x"
25 | }
26 | ],
27 | "info" : {
28 | "version" : 1,
29 | "author" : "xcode"
30 | }
31 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/GesturesCompact.imageset/GesturesCompact@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/GesturesCompact.imageset/GesturesCompact@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/GesturesCompact.imageset/GesturesCompact@2x~iPad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/GesturesCompact.imageset/GesturesCompact@2x~iPad.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/GesturesCompact.imageset/GesturesCompact@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/GesturesCompact.imageset/GesturesCompact@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/GesturesRegular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "ipad",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "ipad",
9 | "filename" : "GesturesRegular@2x~iPad.png",
10 | "scale" : "2x"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/GesturesRegular.imageset/GesturesRegular@2x~iPad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/GesturesRegular.imageset/GesturesRegular@2x~iPad.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/OrigamiCompact.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "iphone",
9 | "filename" : "OrigamiCompact@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "iphone",
14 | "filename" : "OrigamiCompact@3x.png",
15 | "scale" : "3x"
16 | },
17 | {
18 | "idiom" : "ipad",
19 | "scale" : "1x"
20 | },
21 | {
22 | "idiom" : "ipad",
23 | "filename" : "OrigamiCompact@2x~iPad.png",
24 | "scale" : "2x"
25 | }
26 | ],
27 | "info" : {
28 | "version" : 1,
29 | "author" : "xcode"
30 | }
31 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/OrigamiCompact.imageset/OrigamiCompact@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/OrigamiCompact.imageset/OrigamiCompact@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/OrigamiCompact.imageset/OrigamiCompact@2x~iPad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/OrigamiCompact.imageset/OrigamiCompact@2x~iPad.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/OrigamiCompact.imageset/OrigamiCompact@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/OrigamiCompact.imageset/OrigamiCompact@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/OrigamiRegular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "ipad",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "ipad",
9 | "filename" : "OrigamiRegular@2x~iPad.png",
10 | "scale" : "2x"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/OrigamiRegular.imageset/OrigamiRegular@2x~iPad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/OrigamiRegular.imageset/OrigamiRegular@2x~iPad.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/ShareCompact.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "iphone",
9 | "filename" : "ShareCompact@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "iphone",
14 | "filename" : "ShareCompact@3x.png",
15 | "scale" : "3x"
16 | },
17 | {
18 | "idiom" : "ipad",
19 | "scale" : "1x"
20 | },
21 | {
22 | "idiom" : "ipad",
23 | "filename" : "ShareCompact@2x~iPad.png",
24 | "scale" : "2x"
25 | }
26 | ],
27 | "info" : {
28 | "version" : 1,
29 | "author" : "xcode"
30 | }
31 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/ShareCompact.imageset/ShareCompact@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/ShareCompact.imageset/ShareCompact@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/ShareCompact.imageset/ShareCompact@2x~iPad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/ShareCompact.imageset/ShareCompact@2x~iPad.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/ShareCompact.imageset/ShareCompact@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/ShareCompact.imageset/ShareCompact@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/ShareRegular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "ipad",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "ipad",
9 | "filename" : "ShareRegular@2x~iPad.png",
10 | "scale" : "2x"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/ShareRegular.imageset/ShareRegular@2x~iPad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/ShareRegular.imageset/ShareRegular@2x~iPad.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/WelcomeCompact.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "iphone",
9 | "filename" : "WelcomeCompact@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "iphone",
14 | "filename" : "WelcomeCompact@3x.png",
15 | "scale" : "3x"
16 | },
17 | {
18 | "idiom" : "ipad",
19 | "scale" : "1x"
20 | },
21 | {
22 | "idiom" : "ipad",
23 | "filename" : "WelcomeCompact@2x~iPad.png",
24 | "scale" : "2x"
25 | }
26 | ],
27 | "info" : {
28 | "version" : 1,
29 | "author" : "xcode"
30 | }
31 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/WelcomeCompact.imageset/WelcomeCompact@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/WelcomeCompact.imageset/WelcomeCompact@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/WelcomeCompact.imageset/WelcomeCompact@2x~iPad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/WelcomeCompact.imageset/WelcomeCompact@2x~iPad.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/WelcomeCompact.imageset/WelcomeCompact@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/WelcomeCompact.imageset/WelcomeCompact@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/WelcomeRegular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "ipad",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "ipad",
9 | "filename" : "WelcomeRegular@2x~iPad.png",
10 | "scale" : "2x"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Onboarding/WelcomeRegular.imageset/WelcomeRegular@2x~iPad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Onboarding/WelcomeRegular.imageset/WelcomeRegular@2x~iPad.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/ChevronLeft.imageset/ChevronLeft.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/ChevronLeft.imageset/ChevronLeft.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/ChevronLeft.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "ChevronLeft.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/ChevronRightSmall.imageset/ChevronRightSmall.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/ChevronRightSmall.imageset/ChevronRightSmall.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/ChevronRightSmall.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "ChevronRightSmall.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Close.imageset/Close.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/Close.imageset/Close.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Close.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Close.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Compose.imageset/Compose.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/Compose.imageset/Compose.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Compose.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Compose.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Gear.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Gear.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Gear.imageset/Gear.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/Gear.imageset/Gear.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Help.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "Help@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "Help@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | },
22 | "properties" : {
23 | "template-rendering-intent" : "template"
24 | }
25 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Help.imageset/Help@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/Help.imageset/Help@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Help.imageset/Help@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/Help.imageset/Help@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Lock.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Lock.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Lock.imageset/Lock.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/Lock.imageset/Lock.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Moon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "Moon@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "Moon@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | },
22 | "properties" : {
23 | "template-rendering-intent" : "template"
24 | }
25 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Moon.imageset/Moon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/Moon.imageset/Moon@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Moon.imageset/Moon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/Moon.imageset/Moon@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/More.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "More.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/More.imageset/More.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/More.imageset/More.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/SearchSmall.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "SearchSmall.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/SearchSmall.imageset/SearchSmall.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/SearchSmall.imageset/SearchSmall.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/SidebarLeft.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "SidebarLeft.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/SidebarLeft.imageset/SidebarLeft.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/SidebarLeft.imageset/SidebarLeft.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/SignOut.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "SignOut@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "SignOut@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | },
22 | "properties" : {
23 | "template-rendering-intent" : "template"
24 | }
25 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/SignOut.imageset/SignOut@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/SignOut.imageset/SignOut@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/SignOut.imageset/SignOut@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/SignOut.imageset/SignOut@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/User.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "User@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "User@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | },
22 | "properties" : {
23 | "template-rendering-intent" : "template"
24 | }
25 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/User.imageset/User@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/User.imageset/User@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/User.imageset/User@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/User.imageset/User@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Username.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "Username@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "Username@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | },
22 | "properties" : {
23 | "template-rendering-intent" : "template"
24 | }
25 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Username.imageset/Username@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/Username.imageset/Username@2x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Primaries/Username.imageset/Username@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Primaries/Username.imageset/Username@3x.png
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Pull To Refresh/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Pull To Refresh/RefreshViewBackground.imageset/Background.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Pull To Refresh/RefreshViewBackground.imageset/Background.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Pull To Refresh/RefreshViewBackground.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Background.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "original"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Pull To Refresh/RefreshViewGradient.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Gradient 2.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "original"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Pull To Refresh/RefreshViewGradient.imageset/Gradient 2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Pull To Refresh/RefreshViewGradient.imageset/Gradient 2.pdf
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Pull To Refresh/RefreshViewOutline.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Outline.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | },
12 | "properties" : {
13 | "template-rendering-intent" : "template"
14 | }
15 | }
--------------------------------------------------------------------------------
/Support/Assets.xcassets/Pull To Refresh/RefreshViewOutline.imageset/Outline.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Assets.xcassets/Pull To Refresh/RefreshViewOutline.imageset/Outline.pdf
--------------------------------------------------------------------------------
/Support/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Support/Canvas Dev.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.application-groups
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Support/Canvas.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.associated-domains
6 |
7 | webcredentials:usecanvas.com
8 | applinks:usecanvas.com
9 |
10 | com.apple.security.application-groups
11 |
12 | group.com.usecanvas.canvas
13 |
14 | keychain-access-groups
15 |
16 | $(AppIdentifierPrefix)com.usecanvas.canvas
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Support/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | $(BUNDLE_DISPLAY_NAME)
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0.1
21 | CFBundleSignature
22 | ????
23 | CFBundleURLTypes
24 |
25 |
26 | CFBundleTypeRole
27 | Editor
28 | CFBundleURLName
29 | canvas
30 | CFBundleURLSchemes
31 |
32 | canvas
33 |
34 |
35 |
36 | CFBundleVersion
37 | 0
38 | ITSAppUsesNonExemptEncryption
39 |
40 | LSApplicationQueriesSchemes
41 |
42 | googlechrome
43 | googlechromes
44 | org-appextension-feature-password-management
45 |
46 | LSRequiresIPhoneOS
47 |
48 | UILaunchStoryboardName
49 | LaunchScreen
50 | UIMainStoryboardFile
51 | Main
52 | UIRequiredDeviceCapabilities
53 |
54 | armv7
55 |
56 | UIRequiresFullScreen
57 |
58 | UIStatusBarStyle
59 | UIStatusBarStyleDefault
60 | UISupportedInterfaceOrientations
61 |
62 | UIInterfaceOrientationLandscapeRight
63 | UIInterfaceOrientationLandscapeLeft
64 | UIInterfaceOrientationPortrait
65 |
66 | UISupportedInterfaceOrientations~ipad
67 |
68 | UIInterfaceOrientationPortrait
69 | UIInterfaceOrientationPortraitUpsideDown
70 | UIInterfaceOrientationLandscapeLeft
71 | UIInterfaceOrientationLandscapeRight
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/Support/Settings.bundle/Root.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | Title
9 | ABOUT
10 | Type
11 | PSGroupSpecifier
12 |
13 |
14 | Type
15 | PSTitleValueSpecifier
16 | Title
17 | VERSION
18 | DefaultValue
19 |
20 | Key
21 | HumanReadableVersion
22 |
23 |
24 | StringsTable
25 | Root
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Support/Settings.bundle/en.lproj/Root.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/Support/Settings.bundle/en.lproj/Root.strings
--------------------------------------------------------------------------------
/Support/UITests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Support/apple-app-site-association.json:
--------------------------------------------------------------------------------
1 | {
2 | "activitycontinuation": {
3 | "apps": [
4 | "676PZY29MZ.com.usecanvas.canvas"
5 | ]
6 | },
7 | "webcredentials": {
8 | "apps": [
9 | "676PZY29MZ.com.usecanvas.canvas"
10 | ]
11 | },
12 | "applinks": {
13 | "apps": [],
14 | "details": [
15 | {
16 | "appID": "676PZY29MZ.com.usecanvas.canvas",
17 | "paths": [
18 | "NOT /*/*/*/*",
19 | "/*/*/*"
20 | ]
21 | }
22 | ]
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/UITests/Snapshots.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CanvasUITests.swift
3 | // CanvasUITests
4 | //
5 | // Created by Sam Soffes on 7/18/16.
6 | // Copyright © 2016 Canvas Labs, Inc. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class Snapshots: XCTestCase {
12 | override func setUp() {
13 | super.setUp()
14 | continueAfterFailure = false
15 |
16 | let app = XCUIApplication()
17 | app.launchArguments.append("-snapshot")
18 |
19 | setupSnapshot(app)
20 |
21 | app.launch()
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/fastlane/Appfile:
--------------------------------------------------------------------------------
1 | app_identifier 'com.usecanvas.canvas'
2 | apple_id 'sam@usecanvas.com'
3 | team_id '676PZY29MZ'
4 |
--------------------------------------------------------------------------------
/fastlane/Deliverfile:
--------------------------------------------------------------------------------
1 | app_identifier 'com.usecanvas.canvas'
2 | username 'sam@usecanvas.com'
3 |
--------------------------------------------------------------------------------
/fastlane/Fastfile:
--------------------------------------------------------------------------------
1 | fastlane_version '1.97.2'
2 |
3 | default_platform :ios
4 |
5 | platform :ios do
6 | # before_all do
7 | # carthage
8 | # end
9 |
10 | desc 'Submit a new Beta Build to Apple TestFlight'
11 | desc 'This will also make sure the profile is up to date'
12 | lane :beta do
13 | gym(scheme: 'Canvas')
14 | pilot
15 | end
16 |
17 | desc 'Deploy a new version to the App Store'
18 | lane :appstore do
19 | gym(scheme: 'Canvas')
20 | deliver(force: true)
21 | end
22 |
23 | after_all do |lane|
24 | # slack(
25 | # message: 'Successfully deployed new App Update.'
26 | # )
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/fastlane/README.md:
--------------------------------------------------------------------------------
1 | fastlane documentation
2 | ================
3 | # Installation
4 | ```
5 | sudo gem install fastlane
6 | ```
7 | # Available Actions
8 | ## iOS
9 | ### ios beta
10 | ```
11 | fastlane ios beta
12 | ```
13 | Submit a new Beta Build to Apple TestFlight
14 |
15 | This will also make sure the profile is up to date
16 | ### ios appstore
17 | ```
18 | fastlane ios appstore
19 | ```
20 | Deploy a new version to the App Store
21 |
22 | ----
23 |
24 | This README.md is auto-generated and will be re-generated every time to run [fastlane](https://fastlane.tools).
25 | More information about fastlane can be found on [https://fastlane.tools](https://fastlane.tools).
26 | The documentation of fastlane can be found on [GitHub](https://github.com/fastlane/fastlane/tree/master/fastlane).
--------------------------------------------------------------------------------
/fastlane/metadata/copyright.txt:
--------------------------------------------------------------------------------
1 | 2015–2016 Canvas Labs, Inc.
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/en-US/description.txt:
--------------------------------------------------------------------------------
1 | Write with your team, in realtime, using markdown with Canvas. Canvas is the best way to take meeting notes, work on product features, or keep track of those personal notes.
2 |
3 | ## Realtime Collaboration
4 |
5 | Canvas makes it easy to collaborate with anyone in the blink of an eye. Share the link to a canvas with your co-workers and see them show up. Then it’s just a matter of typing.
6 |
7 | ## Swipe to Format
8 |
9 | Use easy swipe gestures to make a checklist, headers and more. Prefer to type? No one likes preview panes. Canvas lets you write Markdown and elegantly folds away the markup when it’s superfluous.
10 |
11 | ## Find What You’re Looking For
12 |
13 | Use blazing fast search to find what you’re looking for without digging through folders.
14 |
--------------------------------------------------------------------------------
/fastlane/metadata/en-US/keywords.txt:
--------------------------------------------------------------------------------
1 | notes,writing,markdown,realtime,collaboration,team,meeting,work,sync
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/en-US/marketing_url.txt:
--------------------------------------------------------------------------------
1 | https://usecanvas.com/ios
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/en-US/name.txt:
--------------------------------------------------------------------------------
1 | Canvas — Collaborative Notes
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/en-US/privacy_url.txt:
--------------------------------------------------------------------------------
1 | https://usecanvas.com/privacy
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/en-US/release_notes.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/metadata/en-US/release_notes.txt
--------------------------------------------------------------------------------
/fastlane/metadata/en-US/support_url.txt:
--------------------------------------------------------------------------------
1 | https://usecanvas.com/support
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/primary_category.txt:
--------------------------------------------------------------------------------
1 | Productivity
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/secondary_category.txt:
--------------------------------------------------------------------------------
1 | Business
2 |
--------------------------------------------------------------------------------
/fastlane/screenshots/README.txt:
--------------------------------------------------------------------------------
1 | Put all screenshots you want to use inside the folder of its language (e.g. en-US).
2 | The device type will automatically be recognized using the image resolution. Apple TV screenshots
3 | should be stored in a subdirectory named appleTV with language folders inside of it.
4 |
5 | The screenshots can be named whatever you want, but keep in mind they are sorted alphabetically.
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/ipadPro_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/ipadPro_1.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/ipadPro_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/ipadPro_2.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/ipadPro_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/ipadPro_3.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/ipad_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/ipad_1.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/ipad_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/ipad_2.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/ipad_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/ipad_3.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone35_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone35_1.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone35_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone35_2.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone35_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone35_3.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone35_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone35_4.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone35_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone35_5.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone4_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone4_1.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone4_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone4_2.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone4_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone4_3.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone4_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone4_4.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone4_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone4_5.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone6Plus_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone6Plus_1.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone6Plus_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone6Plus_2.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone6Plus_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone6Plus_3.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone6Plus_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone6Plus_4.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone6Plus_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone6Plus_5.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone6_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone6_1.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone6_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone6_2.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone6_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone6_3.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone6_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone6_4.png
--------------------------------------------------------------------------------
/fastlane/screenshots/en-US/iphone6_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/usecanvas/ios-v1/c740206a294c775ebc48894b8b36ce477c5cec82/fastlane/screenshots/en-US/iphone6_5.png
--------------------------------------------------------------------------------