Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryan Nystrom committed Mar 10, 2018
0 parents commit 1f97693
Show file tree
Hide file tree
Showing 53 changed files with 3,131 additions and 0 deletions.
84 changes: 84 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

## OSX
.DS_Store

## Build generated
build/
DerivedData/

## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/

## Other
*.moved-aside
*.xccheckout
*.xcscmblueprint

## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM

## Playgrounds
timeline.xctimeline
playground.xcworkspace

# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
.build/

# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/

# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts

Carthage/Build

# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control

fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
node_modules

# Jekyll
_site/
.sass-cache/
.jekyll-metadata

# secrets
Resources/*.xcconfig
*Secrets.swift*


# FBSnapshotTestCase Failure Diffs
FailureDiffs/
10 changes: 10 additions & 0 deletions ContextMenu.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Pod::Spec.new do |spec|
spec.name = 'ContextMenu'
spec.version = '0.1.0'
spec.license = { :type => 'MIT' }
spec.homepage = 'https://github.com/GitHawkApp/ContextMenu'
spec.authors = { 'Ryan Nystrom' => '[email protected]' }
spec.summary = 'Context menu inspired by Things 3.'
spec.source = { :git => 'https://github.com/GitHawkApp/ContextMenu.git', :tag => '#{s.version}' }
spec.source_files = 'ContextMenu/*.swift'
end
379 changes: 379 additions & 0 deletions ContextMenu.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions ContextMenu/CGRect+Area.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// CGRect+Area.swift
// ThingsUI
//
// Created by Ryan Nystrom on 3/10/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//

import UIKit

extension CGRect {

internal func rect(point: CGPoint, xRemainder: Bool, yRemainder: Bool) -> CGRect {
let xDiv = divided(atDistance: point.x, from: .minXEdge)
let x = xRemainder ? xDiv.remainder : xDiv.slice
let yDiv = x.divided(atDistance: point.y, from: .minYEdge)
return yRemainder ? yDiv.remainder : yDiv.slice
}

internal func area(corner: SourceViewCorner) -> CGFloat {
let frame: CGRect
switch corner.position {
case .topLeft:
frame = rect(point: corner.point, xRemainder: false, yRemainder: false)
case .topRight:
frame = rect(point: corner.point, xRemainder: true, yRemainder: false)
case .bottomLeft:
frame = rect(point: corner.point, xRemainder: false, yRemainder: true)
case .bottomRight:
frame = rect(point: corner.point, xRemainder: true, yRemainder: true)
}
return frame.width * frame.height
}

}
67 changes: 67 additions & 0 deletions ContextMenu/ClippedContainerViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// ClippedContainerViewController.swift
// ThingsUI
//
// Created by Ryan Nystrom on 3/10/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//

import UIKit

internal class ClippedContainerViewController: UIViewController {

private let options: ContextMenu.Options
private let containedViewController: UINavigationController

init(options: ContextMenu.Options, viewController: UIViewController) {
self.options = options
self.containedViewController = UINavigationController(rootViewController: viewController)
super.init(nibName: nil, bundle: nil)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
super.viewDidLoad()
view.layer.cornerRadius = options.containerStyle.cornerRadius
view.layer.shadowRadius = options.containerStyle.shadowRadius
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOpacity = 0.2

containedViewController.view.layer.cornerRadius = view.layer.cornerRadius
containedViewController.view.clipsToBounds = true
containedViewController.setNavigationBarHidden(options.menuStyle == .minimal, animated: false)

let size = CGSize(width: 1, height: 1)
UIGraphicsBeginImageContext(size)
defer { UIGraphicsEndImageContext() }

options.containerStyle.backgroundColor.setFill()
UIBezierPath(rect: CGRect(origin: .zero, size: size)).fill()

let image = UIGraphicsGetImageFromCurrentImageContext()
let navigationBar = containedViewController.navigationBar
navigationBar.isTranslucent = false
navigationBar.setBackgroundImage(image, for: .any, barMetrics: .default)
navigationBar.shadowImage = image

addChildViewController(containedViewController)
view.addSubview(containedViewController.view)
containedViewController.didMove(toParentViewController: self)

preferredContentSize = containedViewController.preferredContentSize
}

override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
containedViewController.view.frame = view.bounds
}

override func preferredContentSizeDidChange(forChildContentContainer container: UIContentContainer) {
super.preferredContentSizeDidChange(forChildContentContainer: container)
preferredContentSize = container.preferredContentSize
}

}
39 changes: 39 additions & 0 deletions ContextMenu/ContextMenu+Animations.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// ContextMenu+Animations.swift
// ThingsUI
//
// Created by Ryan Nystrom on 3/10/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//

import UIKit

extension ContextMenu {

public struct AnimationDurations {

public let present: TimeInterval
public let springPresent: TimeInterval
public let springDamping: CGFloat
public let springVelocity: CGFloat
public let dismiss: TimeInterval
public let resize: TimeInterval

public init(
present: TimeInterval = 0.3,
springPresent: TimeInterval = 0.5,
springDamping: CGFloat = 0.8,
springVelocity: CGFloat = 0.5,
dismiss: TimeInterval = 0.15,
resize: TimeInterval = 0.3
) {
self.present = present
self.springPresent = springPresent
self.springDamping = springDamping
self.springVelocity = springVelocity
self.dismiss = dismiss
self.resize = resize
}
}

}
43 changes: 43 additions & 0 deletions ContextMenu/ContextMenu+ContainerStyle.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// ContextMenu+ContainerStyle.swift
// ThingsUI
//
// Created by Ryan Nystrom on 3/10/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//

import UIKit

extension ContextMenu {

public struct ContainerStyle {

public let cornerRadius: CGFloat
public let shadowRadius: CGFloat
public let xPadding: CGFloat
public let yPadding: CGFloat
public let edgePadding: CGFloat
public let backgroundColor: UIColor
public let overlayColor: UIColor

public init(
cornerRadius: CGFloat = 8,
shadowRadius: CGFloat = 15,
xPadding: CGFloat = 8,
yPadding: CGFloat = 8,
edgePadding: CGFloat = 15,
backgroundColor: UIColor = .white,
overlayColor: UIColor = UIColor(white: 0, alpha: 0.3)
) {
self.cornerRadius = cornerRadius
self.shadowRadius = shadowRadius
self.xPadding = xPadding
self.yPadding = yPadding
self.edgePadding = edgePadding
self.backgroundColor = backgroundColor
self.overlayColor = overlayColor
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// ContextMenu+ContextMenuPresentationControllerDelegate.swift
// ThingsUI
//
// Created by Ryan Nystrom on 3/10/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//

import UIKit

extension ContextMenu: ContextMenuPresentationControllerDelegate {

internal func willDismiss(presentationController: ContextMenuPresentationController) {
guard item?.viewController === presentationController.presentedViewController else { return }
item = nil
}

}
31 changes: 31 additions & 0 deletions ContextMenu/ContextMenu+Item.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// File.swift
// ThingsUI
//
// Created by Ryan Nystrom on 3/10/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//

import UIKit

extension ContextMenu {

internal class Item {

let options: Options
let viewController: ClippedContainerViewController

weak var sourceView: UIView?

init(
viewController: UIViewController,
options: Options,
sourceView: UIView?
) {
self.viewController = ClippedContainerViewController(options: options, viewController: viewController)
self.options = options
self.sourceView = sourceView
}
}

}
18 changes: 18 additions & 0 deletions ContextMenu/ContextMenu+MenuStyle.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// ContextMenu+Style.swift
// ThingsUI
//
// Created by Ryan Nystrom on 3/10/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//

import UIKit

extension ContextMenu {

public enum MenuStyle: Int {
case `default`
case minimal
}

}
30 changes: 30 additions & 0 deletions ContextMenu/ContextMenu+Options.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// ContextMenuOptions.swift
// ThingsUI
//
// Created by Ryan Nystrom on 3/10/18.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//

import UIKit

extension ContextMenu {

public struct Options {

let durations: AnimationDurations
let containerStyle: ContainerStyle
let menuStyle: MenuStyle

public init(
durations: AnimationDurations = AnimationDurations(),
containerStyle: ContainerStyle = ContainerStyle(),
menuStyle: MenuStyle = .default
) {
self.durations = durations
self.containerStyle = containerStyle
self.menuStyle = menuStyle
}
}

}
Loading

0 comments on commit 1f97693

Please sign in to comment.