├── Resources
└── example1.gif
├── TTFortuneWheelSample
├── Assets.xcassets
│ ├── Contents.json
│ ├── spin.imageset
│ │ ├── spin@2x.png
│ │ ├── spin@3x.png
│ │ └── Contents.json
│ ├── wheelFrame.imageset
│ │ ├── frame@2x.png
│ │ ├── frame@3x.png
│ │ └── Contents.json
│ ├── nidleImage.imageset
│ │ ├── nidleImage@2x.png
│ │ ├── nidleImage@3x.png
│ │ └── Contents.json
│ ├── spinningWhelAxel.imageset
│ │ ├── axel@2x.png
│ │ ├── axel@3x.png
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Resources
│ ├── BEBAS___.ttf
│ ├── Chunkfive.otf
│ ├── Phosphate.ttc
│ └── Lobster_1.3.otf
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
├── CarnivalWheelSlice.swift
├── ViewController.swift
└── AppDelegate.swift
├── TTFortuneWheel
├── Resources
│ └── Assets.xcassets
│ │ ├── Contents.json
│ │ └── niddleImage.imageset
│ │ ├── point@2x.png
│ │ ├── point@3x.png
│ │ └── Contents.json
├── TTFortuneWheel.h
├── Info.plist
├── SpinningWheelSliceImpl.swift
├── SpinningWheelSlice .swift
├── TTFortuneWheel.swift
├── SpinningWheelAnimator.swift
├── Utils.swift
└── FortuneWheelLayer.swift
├── TTFortuneWheel.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcshareddata
│ └── xcschemes
│ │ └── TTFortuneWheel.xcscheme
└── project.pbxproj
├── .gitignore
├── TTFortuneWheel.podspec
├── LICENSE
└── README.md
/Resources/example1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/Resources/example1.gif
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/TTFortuneWheel/Resources/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Resources/BEBAS___.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/TTFortuneWheelSample/Resources/BEBAS___.ttf
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Resources/Chunkfive.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/TTFortuneWheelSample/Resources/Chunkfive.otf
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Resources/Phosphate.ttc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/TTFortuneWheelSample/Resources/Phosphate.ttc
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Resources/Lobster_1.3.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/TTFortuneWheelSample/Resources/Lobster_1.3.otf
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Assets.xcassets/spin.imageset/spin@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/TTFortuneWheelSample/Assets.xcassets/spin.imageset/spin@2x.png
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Assets.xcassets/spin.imageset/spin@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/TTFortuneWheelSample/Assets.xcassets/spin.imageset/spin@3x.png
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Assets.xcassets/wheelFrame.imageset/frame@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/TTFortuneWheelSample/Assets.xcassets/wheelFrame.imageset/frame@2x.png
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Assets.xcassets/wheelFrame.imageset/frame@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/TTFortuneWheelSample/Assets.xcassets/wheelFrame.imageset/frame@3x.png
--------------------------------------------------------------------------------
/TTFortuneWheel/Resources/Assets.xcassets/niddleImage.imageset/point@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/TTFortuneWheel/Resources/Assets.xcassets/niddleImage.imageset/point@2x.png
--------------------------------------------------------------------------------
/TTFortuneWheel/Resources/Assets.xcassets/niddleImage.imageset/point@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/TTFortuneWheel/Resources/Assets.xcassets/niddleImage.imageset/point@3x.png
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Assets.xcassets/nidleImage.imageset/nidleImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/TTFortuneWheelSample/Assets.xcassets/nidleImage.imageset/nidleImage@2x.png
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Assets.xcassets/nidleImage.imageset/nidleImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/TTFortuneWheelSample/Assets.xcassets/nidleImage.imageset/nidleImage@3x.png
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Assets.xcassets/spinningWhelAxel.imageset/axel@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/TTFortuneWheelSample/Assets.xcassets/spinningWhelAxel.imageset/axel@2x.png
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Assets.xcassets/spinningWhelAxel.imageset/axel@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tapptitude/TTFortuneWheel-iOS/HEAD/TTFortuneWheelSample/Assets.xcassets/spinningWhelAxel.imageset/axel@3x.png
--------------------------------------------------------------------------------
/TTFortuneWheel.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TTFortuneWheel.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io
2 |
3 | # mac
4 | .DS_Store
5 |
6 | ### Swift ###
7 | # Xcode
8 | #
9 | build/
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata
19 | *.xccheckout
20 | *.moved-aside
21 | DerivedData
22 | *.hmap
23 | *.ipa
24 | *.xcuserstate
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Assets.xcassets/spin.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "spin@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "spin@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Assets.xcassets/wheelFrame.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "frame@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "frame@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/TTFortuneWheel/Resources/Assets.xcassets/niddleImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "point@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "point@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Assets.xcassets/spinningWhelAxel.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "axel@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "axel@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Assets.xcassets/nidleImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "nidleImage@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "nidleImage@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/TTFortuneWheel/TTFortuneWheel.h:
--------------------------------------------------------------------------------
1 | //
2 | // TTFortuneWheel.h
3 | // TTFortuneWheel
4 | //
5 | // Created by Efraim Budusan on 10/31/17.
6 | // Copyright © 2017 Tapptitude. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for TTFortuneWheel.
12 | FOUNDATION_EXPORT double TTFortuneWheelVersionNumber;
13 |
14 | //! Project version string for TTFortuneWheel.
15 | FOUNDATION_EXPORT const unsigned char TTFortuneWheelVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/TTFortuneWheel.podspec:
--------------------------------------------------------------------------------
1 |
2 | #
3 |
4 | Pod::Spec.new do |s|
5 | s.name = 'TTFortuneWheel'
6 | s.version = '0.1.8'
7 | s.summary = 'Fortune spinning wheel that supports custom drawing.'
8 | s.homepage = 'https://tapptitude.com/'
9 | s.license = { :type => 'MIT', :file => 'LICENSE' }
10 | s.author = { 'Efraim Budusan' => 'efraim.budusan@tapptitude.com' }
11 | s.source = { :git => 'https://github.com/tapptitude/TTFortuneWheel-iOS.git', :tag => s.version.to_s }
12 | s.ios.deployment_target = '9.0'
13 | s.requires_arc = true
14 | s.source_files = 'TTFortuneWheel/*.{swift}'
15 | s.resource_bundles = {
16 | 'TTFortuneWheel' => ['TTFortuneWheel/Resources/**/*']
17 | }
18 | s.swift_version = '5.0'
19 | end
20 |
--------------------------------------------------------------------------------
/TTFortuneWheel/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Tapptitude
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Base.lproj/LaunchScreen.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 |
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | UIAppFonts
45 |
46 | BEBAS___.ttf
47 | Phosphate.ttc
48 | Lobster_1.3.otf
49 | Chunkfive.otf
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/TTFortuneWheelSample/CarnivalWheelSlice.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CarnivalWheelSlice.swift
3 | // TTFortuneWheelSample
4 | //
5 | // Created by Efraim Budusan on 11/1/17.
6 | // Copyright © 2017 Tapptitude. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import TTFortuneWheel
11 |
12 | public class CarnivalWheelSlice: FortuneWheelSliceProtocol {
13 |
14 | public enum Style {
15 | case brickRed
16 | case sandYellow
17 | case babyBlue
18 | case deepBlue
19 | }
20 |
21 | public var title: String
22 | public var degree: CGFloat = 0.0
23 |
24 | public var backgroundColor: UIColor? {
25 | switch style {
26 | case .brickRed: return TTUtils.uiColor(from:0xE27230)
27 | case .sandYellow: return TTUtils.uiColor(from:0xF7D565)
28 | case .babyBlue: return TTUtils.uiColor(from:0x93D0C4)
29 | case .deepBlue: return TTUtils.uiColor(from:0x2A7F7F)
30 | }
31 | }
32 |
33 | public var fontColor: UIColor {
34 | return UIColor.white
35 | }
36 |
37 | public var offsetFromExterior:CGFloat {
38 | return 10.0
39 | }
40 |
41 | public var font: UIFont {
42 | switch style {
43 | case .brickRed: return UIFont(name: "ChunkFive", size: 22.0)!
44 | case .sandYellow: return UIFont(name: "Lobster 1.3", size: 22.0)!
45 | case .babyBlue: return UIFont(name: "Phosphate", size: 22.0)!
46 | case .deepBlue: return UIFont(name: "Bebas", size: 22.0)!
47 | }
48 | }
49 |
50 | public var stroke: StrokeInfo? {
51 | return StrokeInfo(color: UIColor.white, width: 1.0)
52 | }
53 |
54 | public var style:Style = .brickRed
55 |
56 | public init(title:String) {
57 | self.title = title
58 | }
59 |
60 | public convenience init(title:String, degree:CGFloat) {
61 | self.init(title:title)
62 | self.degree = degree
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/TTFortuneWheelSample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/TTFortuneWheel/SpinningWheelSliceImpl.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SpinningWheelSliceImpl.swift
3 | // TTFortuneWheel
4 | //
5 | // Created by Efraim Budusan on 10/2/17.
6 | // Copyright © 2017 Efraim Budusn. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | //Just a basic implementation of spinning wheel slice
13 | public class FortuneWheelSlice: FortuneWheelSliceProtocol {
14 |
15 | public enum Style {
16 | case dark
17 | case light
18 | }
19 |
20 | public var title: String
21 | public var degree: CGFloat = 0.0
22 |
23 | public var backgroundColor: UIColor? {
24 | switch style {
25 | case .dark: return TTUtils.uiColor(from: 0x320A51)
26 | case .light: return UIColor.white
27 | }
28 | }
29 |
30 | public var fontColor: UIColor {
31 | switch style {
32 | case .dark: return UIColor.white
33 | case .light: return TTUtils.uiColor(from: 0x320A51)
34 | }
35 | }
36 |
37 | public var font: UIFont {
38 | return UIFont.systemFont(ofSize: fontSize, weight: .bold)
39 | }
40 |
41 | public var style:Style = .dark
42 |
43 | public init(title:String) {
44 | self.title = title
45 | }
46 |
47 | public convenience init(title:String, degree:CGFloat) {
48 | self.init(title:title)
49 | self.degree = degree
50 | }
51 |
52 | public func drawAdditionalGraphics(in context:CGContext, circularSegmentHeight:CGFloat,radius:CGFloat,sliceDegree:CGFloat) {
53 | let image = UIImage(named: "niddleImage", in: Bundle.sw_frameworkBundle(), compatibleWith: nil)!
54 | let centerOffset = CGPoint(x: -64, y: 17)
55 | let additionalGraphicRect = CGRect(x: centerOffset.x, y: centerOffset.y, width: 12, height: 12)
56 | let additionalGraphicPath = UIBezierPath(rect: additionalGraphicRect)
57 | context.saveGState()
58 | additionalGraphicPath.addClip()
59 | context.scaleBy(x: 1, y: -1)
60 | context.draw(image.cgImage!, in: CGRect(x: additionalGraphicRect.minX, y: -additionalGraphicRect.minY, width: image.size.width, height: image.size.height), byTiling: true)
61 | context.restoreGState()
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/TTFortuneWheelSample/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // TTFortuneWheelSample
4 | //
5 | // Created by Efraim Budusan on 10/31/17.
6 | // Copyright © 2017 Tapptitude. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import TTFortuneWheel
11 |
12 | class ViewController: UIViewController {
13 |
14 | @IBOutlet weak var spinningWheel: TTFortuneWheel!
15 | override func viewDidLoad() {
16 | super.viewDidLoad()
17 | let slices = [ CarnivalWheelSlice.init(title: "Roller Coaster"),
18 | CarnivalWheelSlice.init(title: "Try again"),
19 | CarnivalWheelSlice.init(title: "Free\nticket"),
20 | CarnivalWheelSlice.init(title: "Teddy\nbear"),
21 | CarnivalWheelSlice.init(title: "Large popcorn"),
22 | CarnivalWheelSlice.init(title: "Balloon figures"),
23 | CarnivalWheelSlice.init(title: "Ferris Wheel"),
24 | CarnivalWheelSlice.init(title: "Pony\nRide")]
25 | spinningWheel.slices = slices
26 | spinningWheel.equalSlices = true
27 | spinningWheel.frameStroke.width = 0
28 | spinningWheel.titleRotation = CGFloat.pi
29 | spinningWheel.slices.enumerated().forEach { (pair) in
30 | let slice = pair.element as! CarnivalWheelSlice
31 | let offset = pair.offset
32 | switch offset % 4 {
33 | case 0: slice.style = .brickRed
34 | case 1: slice.style = .sandYellow
35 | case 2: slice.style = .babyBlue
36 | case 3: slice.style = .deepBlue
37 | default: slice.style = .brickRed
38 | }
39 | }
40 | }
41 |
42 | override func didReceiveMemoryWarning() {
43 | super.didReceiveMemoryWarning()
44 |
45 | // Dispose of any resources that can be recreated.
46 | }
47 |
48 | @IBAction func rotateButton(_ sender: Any) {
49 |
50 | spinningWheel.startAnimating()
51 | DispatchQueue.main.asyncAfter(deadline: .now() + 4.0) {
52 | self.spinningWheel.startAnimating(fininshIndex: 5) { (finished) in
53 | print(finished)
54 | }
55 | }
56 | }
57 | }
58 |
59 |
--------------------------------------------------------------------------------
/TTFortuneWheelSample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // TTFortuneWheelSample
4 | //
5 | // Created by Efraim Budusan on 10/31/17.
6 | // Copyright © 2017 Tapptitude. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/TTFortuneWheel/SpinningWheelSlice .swift:
--------------------------------------------------------------------------------
1 | //
2 | // FortuneWheelSlice.swift
3 | // TTFortuneWheel
4 | //
5 | // Created by Efraim Budusan on 10/2/17.
6 | // Copyright © 2017 Efraim Budusn. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 |
13 | public struct StrokeInfo {
14 | public var color:UIColor
15 | public var width:CGFloat
16 |
17 | public init(color:UIColor, width:CGFloat) {
18 | self.color = color
19 | self.width = width
20 | }
21 | }
22 |
23 | public protocol FortuneWheelSliceProtocol {
24 |
25 | //// Properties
26 | var title:String { get }
27 | var backgroundColor:UIColor? { get }
28 | var degree:CGFloat { get }
29 | var stroke:StrokeInfo? { get }
30 | var offsetFromExterior:CGFloat { get }
31 |
32 | //// Can provide any text attributes except NSMutableParagraphStyle which will allways be centered
33 | var textAttributes: [NSAttributedString.Key:Any] { get }
34 |
35 | //// Can be overriten individualy. textAttributes is used if set.
36 | var fontSize:CGFloat { get }
37 | var fontColor:UIColor { get }
38 | var font:UIFont { get }
39 |
40 | /// Implement if you want to add additional graphic to a slice.
41 | /// Note the origin of coordinate system is at the center of the main circle.
42 | /// You will have to dinamically compute the positon of your elements using the circularSegmentHeight and the radius
43 | func drawAdditionalGraphics(in context:CGContext, circularSegmentHeight:CGFloat,radius:CGFloat,sliceDegree:CGFloat)
44 | }
45 |
46 | extension FortuneWheelSliceProtocol {
47 |
48 | public func drawAdditionalGraphics(in context:CGContext, circularSegmentHeight:CGFloat,radius:CGFloat,sliceDegree:CGFloat) { }
49 |
50 | public var fontSize:CGFloat { return 18.0 }
51 | public var fontColor:UIColor { return UIColor.black }
52 | public var font:UIFont { return UIFont.systemFont(ofSize: fontSize, weight: .regular) }
53 |
54 | public var textAttributes:[NSAttributedString.Key:Any] {
55 | let textStyle = NSMutableParagraphStyle()
56 | textStyle.alignment = .left
57 | let deafultAttributes:[NSAttributedString.Key: Any] =
58 | [.font: self.font,
59 | .foregroundColor: self.fontColor,
60 | .paragraphStyle: textStyle ]
61 | return deafultAttributes
62 | }
63 |
64 | public var offsetFromExterior:CGFloat { return 10.0 }
65 |
66 | public var stroke:StrokeInfo? { return nil }
67 |
68 | public var backgroundColor:UIColor? { return UIColor.lightGray }
69 | }
70 |
71 |
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TTFortuneWheel-iOS
2 |
3 | 
4 | [](https://cocoapods.org/pods/TTFortuneWheel)
5 | [](https://cocoapods.org/pods/TTFortuneWheel)
6 | [](http://cocoapods.org/pods/TTFortuneWheel)
7 | [](http://twitter.com/Tapptitude)
8 |
9 | ## About
10 | Fortune spinning wheel that supports custom drawing and dynamic content.
11 |
12 | This project is maintained by Tapptitude, a mobile app development agency specialized in building high-quality iOS and Android mobile apps, for startups and brands alike. A lively team of skilled app developers and app designers based in Europe, we provide full-stack mobile app development services to entrepreneurs looking to innovate on mobile.
13 |
14 | 
15 |
16 | ## Features:
17 | - Dynamic content
18 | - Each slice can have it's own style and angle
19 | - Drawn and animated using CoreGraphics
20 | - Customize(Font, Slice Color, Stroke, Frame color, width and shadow)
21 | - Predictible rotation to any slice
22 | - Exposes methods for custom Core Graphics drawings for each slice
23 | - Dynamic size
24 |
25 | ## Requirements
26 |
27 | - iOS 9.0+
28 | - Xcode 8.2+
29 |
30 | ## Installation
31 |
32 | _CocoaPods_
33 |
34 | _Swift 5.0_
35 |
36 | ```ruby
37 | pod 'TTFortuneWheel'
38 | ```
39 |
40 | _Swift 4.2_
41 |
42 | ```ruby
43 | pod 'TTFortuneWheel', '~>0.1.6'
44 | ```
45 |
46 | _Swift 4.0_
47 |
48 | ```ruby
49 | pod 'TTFortuneWheel', '~>0.1.5'
50 | ```
51 |
52 | _Carthage_
53 |
54 | ```
55 | github "tapptitude/TTFortuneWheel-iOS"
56 | ```
57 |
58 | _Manually_
59 |
60 | Add contents of TTFortuneWheel folder to your project.
61 |
62 | ## Usage
63 |
64 | You can place the FortuneWheel in your storyboard or add it as sa subview programatically.
65 |
66 | ```swift
67 |
68 | override func viewDidLoad() {
69 | super.viewDidLoad()
70 |
71 | let slices = [ FortuneWheelSlice(title: "Slice 1"),
72 | FortuneWheelSlice(title: "Slice 2"),
73 | FortuneWheelSlice(title: "Slice 3")]
74 |
75 | let fortuneWheel = TTFortuneWheel(frame: frame, slices:slices)
76 | spinningWheel.equalSlices = true
77 | self.view.addSubview(fortuneWheel)
78 | }
79 | ```
80 | ## How to customize?
81 |
82 | In order to provide custom drawing for slices you have to implement `FortuneWheelSliceProtocol`.
83 | or can use the preconfiugred `FortuneWheelSliceImpl` class.
84 |
85 | ## Contribution
86 |
87 | Feel free to Fork, submit Pull Requests or send us your feedback and suggestions!
88 |
89 |
90 | ## License
91 |
92 | TTFortuneWheel is available under the MIT license. See the LICENSE file for more info.
93 |
--------------------------------------------------------------------------------
/TTFortuneWheel.xcodeproj/xcshareddata/xcschemes/TTFortuneWheel.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
52 |
53 |
59 |
60 |
66 |
67 |
68 |
69 |
71 |
72 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/TTFortuneWheel/TTFortuneWheel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TTFortuneWheel.swift
3 | // TTFortuneWheel
4 | //
5 | // Created by Efraim Budusan on 9/29/17.
6 | // Copyright © 2017 Efraim Budusn. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public class TTFortuneWheel: UIControl, CAAnimationDelegate, SpinningAnimatorProtocol {
12 |
13 | /// Set to true if you want all slices to be disributed evenly
14 | open var equalSlices:Bool = false
15 |
16 | open var slices:[FortuneWheelSliceProtocol]!
17 |
18 | /// UIConfiguration of the main frame
19 | open var frameStroke:StrokeInfo = StrokeInfo(color: TTUtils.uiColor(from: 0x6E17B3), width: 8)
20 | open var shadow:NSShadow?
21 |
22 |
23 | /// Set this to start drawing from that offset
24 | /// The sliced centerd to this offset will be 0 indexed one
25 | open var initialDrawingOffset:CGFloat = 0.0
26 |
27 | open var titleRotation:CGFloat = 0.0
28 |
29 | lazy private var animator:SpinningWheelAnimator = SpinningWheelAnimator(withObjectToAnimate: self)
30 | private(set) var sliceDegree:CGFloat?
31 | private(set) var wheelLayer:FortuneWheelLayer!
32 |
33 | public init(frame: CGRect, slices:[FortuneWheelSliceProtocol]) {
34 | super.init(frame: frame)
35 | self.slices = slices
36 | self.shadow = defaultShadow
37 | addWheelLayer()
38 | }
39 |
40 | override public func layoutSubviews() {
41 | super.layoutSubviews()
42 | self.layer.needsDisplayOnBoundsChange = true
43 | }
44 |
45 | public required init?(coder aDecoder: NSCoder) {
46 | super.init(coder: aDecoder)
47 | self.shadow = defaultShadow
48 | }
49 |
50 | func sliceInfoIsValid() -> Bool {
51 | if equalSlices{ return true }
52 | return slices.reduce(0, {$0 + $1.degree}) == 360
53 | }
54 |
55 | override public func draw(_ rect: CGRect) {
56 | super.draw(rect)
57 | if let existing = wheelLayer {
58 | existing.removeFromSuperlayer()
59 | }
60 | addWheelLayer()
61 | assert(sliceInfoIsValid(), "All slices must have a 360 degree combined. Set equalSlices true if you want to distribute them evenly.")
62 | if equalSlices {
63 | sliceDegree = 360.0 / CGFloat(slices.count)
64 | }
65 | }
66 |
67 | private func addWheelLayer() {
68 | wheelLayer = FortuneWheelLayer(frame:self.bounds,parent:self,initialOffset:initialDrawingOffset)
69 | self.layer.addSublayer(wheelLayer)
70 | wheelLayer.setNeedsDisplay()
71 | }
72 |
73 | internal var defaultShadow:NSShadow {
74 | let shadow = NSShadow()
75 | shadow.shadowColor = UIColor.black.withAlphaComponent(0.5)
76 | shadow.shadowOffset = CGSize(width: 0, height: 0)
77 | shadow.shadowBlurRadius = 14
78 | return shadow
79 | }
80 |
81 | //// Animation conformance
82 | internal var layerToAnimate: CALayer {
83 | return self.wheelLayer
84 | }
85 |
86 | open func startAnimating(rotationCompletionOffset:CGFloat = 0.0, _ completion:((Bool) -> Void)?) {
87 | self.stopAnimating()
88 | self.animator.addRotationAnimation(completionBlock: completion,rotationOffset:rotationCompletionOffset)
89 | }
90 |
91 | open func startAnimating(fininshIndex:Int = 0, _ completion:((Bool) -> Void)?) {
92 | let rotation = 360.0 - computeRadian(from: fininshIndex)
93 | self.startAnimating(rotationCompletionOffset: rotation, completion)
94 | }
95 |
96 | open func startAnimating() {
97 | self.animator.addIndefiniteRotationAnimation()
98 | }
99 |
100 | open func stopAnimating() {
101 | self.animator.removeAllAnimations()
102 | }
103 |
104 | open func startAnimating(fininshIndex:Int = 0, offset:CGFloat, _ completion:((Bool) -> Void)?) {
105 | let rotation = 360.0 - computeRadian(from: fininshIndex) + offset
106 | self.startAnimating(rotationCompletionOffset: rotation, completion)
107 | }
108 |
109 | private func computeRadian(from finishIndex:Int) -> CGFloat {
110 | if equalSlices {
111 | return CGFloat(finishIndex) * sliceDegree!
112 | }
113 | return slices.enumerated().filter({ $0.offset < finishIndex}).reduce(0.0, { $0 + $1.element.degree })
114 | }
115 | }
116 |
117 |
118 |
--------------------------------------------------------------------------------
/TTFortuneWheel/SpinningWheelAnimator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SpinningWheelAnimator.swift
3 | // TTFortuneWheel
4 | //
5 | // Created by Efraim Budusan on 10/3/17.
6 | // Copyright © 2017 Efraim Budusn. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import CoreGraphics
12 |
13 | protocol SpinningAnimatorProtocol: class {
14 | var layerToAnimate:CALayer { get }
15 | }
16 |
17 |
18 | class SpinningWheelAnimator : NSObject, CAAnimationDelegate {
19 |
20 |
21 | weak var animationObject:SpinningAnimatorProtocol!
22 |
23 | internal var completionBlocks = [CAAnimation: (Bool) -> Void]()
24 | internal var updateLayerValueForCompletedAnimation : Bool = false
25 |
26 | //Configuration properties
27 | var fullRotationsUntilFinish:Int = 13
28 | var rotationTime: CFTimeInterval = 5.000
29 |
30 | init(withObjectToAnimate animationObject:SpinningAnimatorProtocol) {
31 | self.animationObject = animationObject
32 | }
33 |
34 |
35 | func addIndefiniteRotationAnimation() {
36 |
37 | let fillMode : String = CAMediaTimingFillMode.forwards.rawValue
38 | let starTransformAnim = CAKeyframeAnimation(keyPath:"transform.rotation.z")
39 | starTransformAnim.values = [0, 7000 * CGFloat.pi/180]
40 | starTransformAnim.keyTimes = [0, 1]
41 | starTransformAnim.duration = rotationTime
42 |
43 | let starRotationAnim : CAAnimationGroup = TTUtils.group(animations: [starTransformAnim], fillMode:fillMode)
44 | starRotationAnim.repeatCount = Float.infinity
45 | animationObject.layerToAnimate.add(starRotationAnim, forKey:"starRotationIndefiniteAnim")
46 |
47 | }
48 |
49 | func addRotationAnimation(completionBlock: ((_ finished: Bool) -> Void)? = nil, rotationOffset:CGFloat = 0.0){
50 | if completionBlock != nil{
51 | let completionAnim = CABasicAnimation(keyPath:"completionAnim")
52 | completionAnim.duration = rotationTime
53 | completionAnim.delegate = self
54 | completionAnim.setValue("rotation", forKey:"animId")
55 | completionAnim.setValue(false, forKey:"needEndAnim")
56 | let layer = animationObject.layerToAnimate
57 | layer.add(completionAnim, forKey:"rotation")
58 | if let anim = layer.animation(forKey: "rotation"){
59 | completionBlocks[anim] = completionBlock
60 | }
61 | }
62 |
63 | let fillMode : String = CAMediaTimingFillMode.forwards.rawValue
64 |
65 | let rotation:CGFloat = CGFloat(fullRotationsUntilFinish) * 360.0 + rotationOffset
66 |
67 | ////Star animation
68 | let starTransformAnim = CAKeyframeAnimation(keyPath:"transform.rotation.z")
69 | starTransformAnim.values = [0, rotation * CGFloat.pi/180]
70 | starTransformAnim.keyTimes = [0, 1]
71 | starTransformAnim.duration = 5
72 | starTransformAnim.timingFunction = CAMediaTimingFunction(controlPoints: 0.0256, 0.874, 0.675, 1)
73 |
74 | let starRotationAnim : CAAnimationGroup = TTUtils.group(animations: [starTransformAnim], fillMode:fillMode)
75 | animationObject.layerToAnimate.add(starRotationAnim, forKey:"starRotationAnim")
76 | }
77 |
78 | //MARK: - Animation Cleanup
79 |
80 | func animationDidStop(_ anim: CAAnimation, finished flag: Bool){
81 | if let completionBlock = completionBlocks[anim]{
82 | completionBlocks.removeValue(forKey: anim)
83 | if (flag && updateLayerValueForCompletedAnimation) || anim.value(forKey: "needEndAnim") as! Bool{
84 | updateLayerValues(forAnimationId: anim.value(forKey: "animId") as! String)
85 | removeAnimations(forAnimationId: anim.value(forKey: "animId") as! String)
86 | }
87 | completionBlock(flag)
88 | }
89 | }
90 |
91 | func updateLayerValues(forAnimationId identifier: String){
92 | if identifier == "rotation"{
93 | TTUtils.updateValueFromPresentationLayer(forAnimation: animationObject.layerToAnimate.animation(forKey: "starRotationAnim"), theLayer:animationObject.layerToAnimate)
94 | }
95 | }
96 |
97 | func removeAnimations(forAnimationId identifier: String){
98 | if identifier == "rotation"{
99 | animationObject.layerToAnimate.removeAnimation(forKey: "starRotationAnim")
100 | }
101 | }
102 |
103 | func removeIndefiniteAnimation() {
104 | animationObject.layerToAnimate.removeAnimation(forKey: "starRotationIndefiniteAnim")
105 | }
106 |
107 | func removeAllAnimations(){
108 | animationObject.layerToAnimate.removeAllAnimations()
109 | }
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/TTFortuneWheel/Utils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Helpers.swift
3 | // TTFortuneWheel
4 | //
5 | // Created by Efraim Budusan on 10/2/17.
6 | // Copyright © 2017 Efraim Budusn. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | #if os(iOS)
11 | import UIKit
12 | #else
13 | import Cocoa
14 | #endif
15 |
16 | public class TTUtils {
17 |
18 | public class func uiColor(from rgbValue: UInt, alpha: CGFloat = 1.0) -> UIColor {
19 | return UIColor(
20 | red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
21 | green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
22 | blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
23 | alpha: CGFloat(alpha)
24 | )
25 | }
26 |
27 | //QuartzCode methods utils
28 |
29 | class func group(animations : [CAAnimation], fillMode : String!, forEffectLayer : Bool = false, sublayersCount : NSInteger = 0) -> CAAnimationGroup!{
30 | let groupAnimation = CAAnimationGroup()
31 | groupAnimation.animations = animations
32 |
33 | if (fillMode != nil){
34 | if let animations = groupAnimation.animations {
35 | for anim in animations {
36 | anim.fillMode = CAMediaTimingFillMode(rawValue: fillMode!)
37 | }
38 | }
39 | groupAnimation.fillMode = CAMediaTimingFillMode(rawValue: fillMode!)
40 | groupAnimation.isRemovedOnCompletion = false
41 | }
42 |
43 | if forEffectLayer{
44 | groupAnimation.duration = TTUtils.maxDuration(ofEffectAnimation: groupAnimation, sublayersCount: sublayersCount)
45 | }else{
46 | groupAnimation.duration = TTUtils.maxDuration(ofAnimations: animations)
47 | }
48 |
49 | return groupAnimation
50 | }
51 |
52 | class func maxDuration(ofAnimations anims: [CAAnimation]) -> CFTimeInterval{
53 | var maxDuration: CGFloat = 0;
54 | for anim in anims {
55 | maxDuration = max(CGFloat(anim.beginTime + anim.duration) * CGFloat(anim.repeatCount == 0 ? 1.0 : anim.repeatCount) * (anim.autoreverses ? 2.0 : 1.0), maxDuration);
56 | }
57 |
58 | if maxDuration.isInfinite {
59 | return TimeInterval(NSIntegerMax)
60 | }
61 |
62 | return CFTimeInterval(maxDuration);
63 | }
64 |
65 | class func maxDuration(ofEffectAnimation anim: CAAnimation, sublayersCount : NSInteger) -> CFTimeInterval{
66 | var maxDuration : CGFloat = 0
67 | if let groupAnim = anim as? CAAnimationGroup{
68 | for subAnim in groupAnim.animations! as [CAAnimation]{
69 |
70 | var delay : CGFloat = 0
71 | if let instDelay = (subAnim.value(forKey: "instanceDelay") as? NSNumber)?.floatValue{
72 | delay = CGFloat(instDelay) * CGFloat(sublayersCount - 1);
73 | }
74 | var repeatCountDuration : CGFloat = 0;
75 | if subAnim.repeatCount > 1 {
76 | repeatCountDuration = CGFloat(subAnim.duration) * CGFloat(subAnim.repeatCount-1);
77 | }
78 | var duration : CGFloat = 0;
79 |
80 | duration = CGFloat(subAnim.beginTime) + (subAnim.autoreverses ? CGFloat(subAnim.duration) : CGFloat(0)) + delay + CGFloat(subAnim.duration) + CGFloat(repeatCountDuration);
81 | maxDuration = max(duration, maxDuration);
82 | }
83 | }
84 |
85 | if maxDuration.isInfinite {
86 | maxDuration = 1000
87 | }
88 |
89 | return CFTimeInterval(maxDuration);
90 | }
91 |
92 | class func updateValueFromAnimations(forLayers layers: [CALayer]){
93 | CATransaction.begin()
94 | CATransaction.setDisableActions(true)
95 |
96 | for aLayer in layers{
97 | if let keys = aLayer.animationKeys() as [String]?{
98 | for animKey in keys{
99 | let anim = aLayer.animation(forKey: animKey)
100 | updateValue(forAnimation: anim!, theLayer: aLayer);
101 | }
102 | }
103 |
104 | }
105 |
106 | CATransaction.commit()
107 | }
108 |
109 | class func updateValue(forAnimation anim: CAAnimation, theLayer : CALayer){
110 | if let basicAnim = anim as? CABasicAnimation{
111 | if (!basicAnim.autoreverses) {
112 | theLayer.setValue(basicAnim.toValue, forKeyPath: basicAnim.keyPath!)
113 | }
114 | }else if let keyAnim = anim as? CAKeyframeAnimation{
115 | if (!keyAnim.autoreverses) {
116 | theLayer.setValue(keyAnim.values?.last, forKeyPath: keyAnim.keyPath!)
117 | }
118 | }else if let groupAnim = anim as? CAAnimationGroup{
119 | for subAnim in groupAnim.animations! as [CAAnimation]{
120 | updateValue(forAnimation: subAnim, theLayer: theLayer);
121 |
122 | }
123 | }
124 | }
125 |
126 | class func updateValueFromPresentationLayer(forAnimation anim: CAAnimation!, theLayer : CALayer){
127 | if let basicAnim = anim as? CABasicAnimation{
128 | theLayer.setValue(theLayer.presentation()?.value(forKeyPath: basicAnim.keyPath!), forKeyPath: basicAnim.keyPath!)
129 | }else if let keyAnim = anim as? CAKeyframeAnimation{
130 | theLayer.setValue(theLayer.presentation()?.value(forKeyPath: keyAnim.keyPath!), forKeyPath: keyAnim.keyPath!)
131 | }else if let groupAnim = anim as? CAAnimationGroup{
132 | for subAnim in groupAnim.animations! as [CAAnimation]{
133 | updateValueFromPresentationLayer(forAnimation: subAnim, theLayer: theLayer)
134 | }
135 | }
136 | }
137 | }
138 |
139 | extension Collection where Indices.Iterator.Element == Index {
140 |
141 | /// Returns the element at the specified index iff it is within bounds, otherwise nil.
142 | subscript (safe index: Index) -> Iterator.Element? {
143 | return indices.contains(index) ? self[index] : nil
144 | }
145 | }
146 |
147 | extension Bundle {
148 | public static func sw_frameworkBundle() -> Bundle {
149 | let bundle = Bundle(for: TTUtils.self)
150 | if let path = bundle.path(forResource: "TTFortuneWheel", ofType: "bundle") {
151 | return Bundle(path: path)!
152 | }
153 | else {
154 | return bundle
155 | }
156 | }
157 | }
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
--------------------------------------------------------------------------------
/TTFortuneWheelSample/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 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/TTFortuneWheel/FortuneWheelLayer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WheelSpinnerDrawer.swift
3 | // TTFortuneWheel
4 | //
5 | // Created by Efraim Budusan on 9/29/17.
6 | // Copyright © 2017 Efraim Budusn. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import CoreGraphics
12 |
13 |
14 | open class FortuneWheelLayer: CALayer {
15 |
16 | /// Used to center the drawing such that offseted graphics(e.g Shadows, Outer Glows) are not clipped.
17 | /// Can be increased to any size if needed.
18 | open var layerInsets:UIEdgeInsets = UIEdgeInsets(top: -50, left: -50, bottom: -50, right: -50)
19 |
20 | var mainFrame:CGRect!
21 | weak var parent:TTFortuneWheel!
22 | private var initialOffset:CGFloat!
23 |
24 | public init(frame:CGRect, parent:TTFortuneWheel,initialOffset:CGFloat = 0.0) {
25 | super.init()
26 | mainFrame = CGRect(origin: CGPoint(x: abs(layerInsets.left), y: abs(layerInsets.top)), size: frame.size)
27 | self.frame = frame.inset(by: layerInsets)
28 | self.parent = parent
29 | self.initialOffset = initialOffset
30 | self.backgroundColor = UIColor.clear.cgColor
31 | self.contentsScale = UIScreen.main.scale
32 | }
33 |
34 | public required init?(coder aDecoder: NSCoder) {
35 | super.init(coder: aDecoder)
36 | }
37 |
38 | open override func draw(in ctx: CGContext) {
39 | super.draw(in: ctx)
40 |
41 | guard parent.slices != nil else {
42 | assert(false, "Slices parameter not set.")
43 | return
44 | }
45 | UIGraphicsPushContext(ctx)
46 | drawCanvas(mainFrame: mainFrame)
47 | UIGraphicsPopContext()
48 | }
49 |
50 | open func drawCanvas(mainFrame: CGRect) {
51 | //// General Declarations
52 | let context = UIGraphicsGetCurrentContext()!
53 |
54 | //// Main Group
55 | context.saveGState()
56 | if let shadow = parent.shadow {
57 | context.setShadow(offset: shadow.shadowOffset, blur: shadow.shadowBlurRadius, color: (shadow.shadowColor as! UIColor).cgColor)
58 | }
59 | context.beginTransparencyLayer(auxiliaryInfo: nil)
60 |
61 | //// Slice drawings
62 | var rotation:CGFloat = initialOffset
63 | parent.slices.enumerated().forEach { (index,element) in
64 | if let previousSlice = parent.slices[safe:(index - 1)] {
65 | rotation += (degree(of:previousSlice) + degree(of:element)) / 2
66 | }
67 | self.drawSlice(withIndex: index, in: context, forSlice: element,rotation:rotation)
68 |
69 | }
70 |
71 | //// Aditional graphics drwings
72 | parent.slices.enumerated().forEach { (index,element) in
73 | self.drawAdditionalGraphics(in: context, rotation: rotation, for: element)
74 | let previousSlice:FortuneWheelSliceProtocol = parent.slices[safe:(index - 1)] ?? element
75 | rotation += degree(of:previousSlice)
76 | }
77 |
78 | //// Frame drawing
79 | let circleFrame = UIBezierPath(ovalIn: mainFrame)
80 | parent.frameStroke.color.setStroke()
81 | circleFrame.lineWidth = parent.frameStroke.width
82 | circleFrame.stroke()
83 |
84 | context.endTransparencyLayer()
85 | context.restoreGState()
86 | }
87 |
88 | //MARK:- Computed values and expressions
89 | private var radius:CGFloat { return mainFrame.height / 2.0 }
90 | private var rotationOffset:CGFloat { return (mainFrame.width) / 2 + abs(layerInsets.top) }
91 | private func circularSegmentHeight(from degree:CGFloat) -> CGFloat { return 2 * radius * sin(degree / 2.0 * CGFloat.pi/180) }
92 |
93 | private func degree(of slice:FortuneWheelSliceProtocol) -> CGFloat {
94 | return parent.sliceDegree ?? slice.degree
95 | }
96 |
97 | //MARK:- Graphics drawings
98 |
99 | open func drawSlice(withIndex index:Int, in context:CGContext, forSlice slice:FortuneWheelSliceProtocol, rotation:CGFloat) {
100 |
101 | ///// Constats declarations
102 | let sectionWidthDegrees = degree(of: slice)
103 | let kTitleOffset: CGFloat = slice.offsetFromExterior
104 | let titleXValue: CGFloat = mainFrame.minX + kTitleOffset
105 | let kTitleWidth: CGFloat = 0.6
106 | let titleWidthCoeficient: CGFloat = sin(sectionWidthDegrees / 2.0 * CGFloat.pi/180)
107 | let titleWidthValue: CGFloat = (kTitleWidth + titleWidthCoeficient * 0.2) * radius
108 | let startAngle: CGFloat = 180 + sectionWidthDegrees / 2.0
109 | let endAngle: CGFloat = 180 - sectionWidthDegrees / 2.0
110 | let circularSegmentHeight: CGFloat = self.circularSegmentHeight(from:sectionWidthDegrees)
111 | let titleHeightValue: CGFloat = circularSegmentHeight * 1
112 | let titleYPosition: CGFloat = mainFrame.minY + mainFrame.height / 2.0 - titleHeightValue / 2.0
113 |
114 | //// Context setup
115 | context.saveGState()
116 | context.translateBy(x: rotationOffset, y: rotationOffset)
117 | context.rotate(by: rotation * CGFloat.pi/180)
118 |
119 | //// Slice drawing
120 | let sliceRect = CGRect(x: (mainFrame.minX - rotationOffset), y: (mainFrame.minY - rotationOffset), width: mainFrame.width, height: mainFrame.height)
121 | let slicePath = UIBezierPath()
122 | slicePath.addArc(withCenter: CGPoint(x: sliceRect.midX, y: sliceRect.midY), radius: sliceRect.width / 2, startAngle: -startAngle * CGFloat.pi/180, endAngle: -endAngle * CGFloat.pi/180, clockwise: true)
123 | slicePath.addLine(to: CGPoint(x: sliceRect.midX, y: sliceRect.midY))
124 | slicePath.close()
125 | slice.backgroundColor?.setFill()
126 | slicePath.fill()
127 |
128 | //// Strike drawing
129 | if let stroke = slice.stroke {
130 | stroke.color.setStroke()
131 | slicePath.lineWidth = stroke.width
132 | slicePath.stroke()
133 | }
134 |
135 | //// Title Drawing
136 | let textRect = CGRect(x: (titleXValue - rotationOffset), y: (titleYPosition - rotationOffset), width: titleWidthValue, height: titleHeightValue)
137 | let textTextContent = slice.title
138 |
139 | //// Set title attributes
140 | let textStyle = NSMutableParagraphStyle()
141 | textStyle.alignment = .left
142 | var textFontAttributes = slice.textAttributes
143 | textFontAttributes[.paragraphStyle] = textStyle
144 |
145 | let textBoundingRect = textTextContent.boundingRect(with: CGSize(width: textRect.width, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: textFontAttributes, context: nil)
146 | let textTextHeight: CGFloat = textBoundingRect.height
147 | context.saveGState()
148 |
149 | context.translateBy(x: textRect.minX, y: textRect.minY + (textRect.height - textTextHeight) / 2)
150 | context.translateBy(x: textBoundingRect.width / 2, y: textBoundingRect.height / 2)
151 | context.rotate(by: self.parent.titleRotation)
152 | context.translateBy(x: -(textBoundingRect.width / 2), y: -(textBoundingRect.height / 2))
153 | context.clip(to: CGRect(x: 0, y: 0, width: textRect.width, height: textRect.height))
154 | textTextContent.draw(in: CGRect(x: 0, y: 0, width: textRect.width, height: textTextHeight), withAttributes: textFontAttributes)
155 | context.restoreGState()
156 |
157 | context.restoreGState()
158 | }
159 |
160 | private func drawAdditionalGraphics(in context:CGContext, rotation:CGFloat, for slice:FortuneWheelSliceProtocol) {
161 |
162 | let sectionWidthDegrees:CGFloat = degree(of: slice)
163 | let circularSegmentHeight: CGFloat = self.circularSegmentHeight(from:sectionWidthDegrees)
164 | context.saveGState()
165 | context.translateBy(x: rotationOffset, y: rotationOffset)
166 | context.rotate(by: rotation * CGFloat.pi/180)
167 | slice.drawAdditionalGraphics(in: context,circularSegmentHeight:circularSegmentHeight, radius: radius,sliceDegree:sectionWidthDegrees)
168 | context.restoreGState()
169 |
170 | }
171 |
172 |
173 |
174 | }
175 |
--------------------------------------------------------------------------------
/TTFortuneWheel.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 48;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | D7043A2D1FE29CBB0064F43D /* TTFortuneWheel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D74F36A91FA86966003D0416 /* TTFortuneWheel.framework */; };
11 | D7043A2E1FE29D310064F43D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D7D7F0451FA88B3B0042B5C6 /* Assets.xcassets */; };
12 | D7043A301FE29DAD0064F43D /* TTFortuneWheel.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D74F36A91FA86966003D0416 /* TTFortuneWheel.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
13 | D70B495D1FA86B9100231E07 /* SpinningWheelAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70B49571FA86B9100231E07 /* SpinningWheelAnimator.swift */; };
14 | D70B495F1FA86B9100231E07 /* FortuneWheelLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70B49581FA86B9100231E07 /* FortuneWheelLayer.swift */; };
15 | D70B49611FA86B9100231E07 /* SpinningWheelSlice .swift in Sources */ = {isa = PBXBuildFile; fileRef = D70B49591FA86B9100231E07 /* SpinningWheelSlice .swift */; };
16 | D70B49631FA86B9100231E07 /* SpinningWheelSliceImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70B495A1FA86B9100231E07 /* SpinningWheelSliceImpl.swift */; };
17 | D70B49651FA86B9100231E07 /* TTFortuneWheel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70B495B1FA86B9100231E07 /* TTFortuneWheel.swift */; };
18 | D70B49671FA86B9100231E07 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70B495C1FA86B9100231E07 /* Utils.swift */; };
19 | D74F36AE1FA86966003D0416 /* TTFortuneWheel.h in Headers */ = {isa = PBXBuildFile; fileRef = D74F36AC1FA86966003D0416 /* TTFortuneWheel.h */; settings = {ATTRIBUTES = (Public, ); }; };
20 | D74F36BB1FA86AD7003D0416 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74F36BA1FA86AD7003D0416 /* AppDelegate.swift */; };
21 | D74F36BD1FA86AD7003D0416 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74F36BC1FA86AD7003D0416 /* ViewController.swift */; };
22 | D74F36C01FA86AD7003D0416 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D74F36BE1FA86AD7003D0416 /* Main.storyboard */; };
23 | D74F36C21FA86AD7003D0416 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D74F36C11FA86AD7003D0416 /* Assets.xcassets */; };
24 | D74F36C51FA86AD7003D0416 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D74F36C31FA86AD7003D0416 /* LaunchScreen.storyboard */; };
25 | D7E515CE1FA9C3C900218F8A /* CarnivalWheelSlice.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E515CD1FA9C3C900218F8A /* CarnivalWheelSlice.swift */; };
26 | D7E515D81FA9C63C00218F8A /* BEBAS___.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D7E515D31FA9C61600218F8A /* BEBAS___.ttf */; };
27 | D7E515D91FA9C63C00218F8A /* Phosphate.ttc in Resources */ = {isa = PBXBuildFile; fileRef = D7E515D21FA9C60900218F8A /* Phosphate.ttc */; };
28 | D7E515DA1FA9C63C00218F8A /* Lobster_1.3.otf in Resources */ = {isa = PBXBuildFile; fileRef = D7E515D11FA9C5E800218F8A /* Lobster_1.3.otf */; };
29 | D7E515DB1FA9C63C00218F8A /* Chunkfive.otf in Resources */ = {isa = PBXBuildFile; fileRef = D7E515D01FA9C5D800218F8A /* Chunkfive.otf */; };
30 | /* End PBXBuildFile section */
31 |
32 | /* Begin PBXContainerItemProxy section */
33 | D7043A311FE29DAD0064F43D /* PBXContainerItemProxy */ = {
34 | isa = PBXContainerItemProxy;
35 | containerPortal = D74F36A01FA86966003D0416 /* Project object */;
36 | proxyType = 1;
37 | remoteGlobalIDString = D74F36A81FA86966003D0416;
38 | remoteInfo = TTFortuneWheel;
39 | };
40 | /* End PBXContainerItemProxy section */
41 |
42 | /* Begin PBXCopyFilesBuildPhase section */
43 | D7043A331FE29DAD0064F43D /* Embed Frameworks */ = {
44 | isa = PBXCopyFilesBuildPhase;
45 | buildActionMask = 2147483647;
46 | dstPath = "";
47 | dstSubfolderSpec = 10;
48 | files = (
49 | D7043A301FE29DAD0064F43D /* TTFortuneWheel.framework in Embed Frameworks */,
50 | );
51 | name = "Embed Frameworks";
52 | runOnlyForDeploymentPostprocessing = 0;
53 | };
54 | /* End PBXCopyFilesBuildPhase section */
55 |
56 | /* Begin PBXFileReference section */
57 | D70B49571FA86B9100231E07 /* SpinningWheelAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpinningWheelAnimator.swift; sourceTree = ""; };
58 | D70B49581FA86B9100231E07 /* FortuneWheelLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FortuneWheelLayer.swift; sourceTree = ""; };
59 | D70B49591FA86B9100231E07 /* SpinningWheelSlice .swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SpinningWheelSlice .swift"; sourceTree = ""; };
60 | D70B495A1FA86B9100231E07 /* SpinningWheelSliceImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpinningWheelSliceImpl.swift; sourceTree = ""; };
61 | D70B495B1FA86B9100231E07 /* TTFortuneWheel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TTFortuneWheel.swift; sourceTree = ""; };
62 | D70B495C1FA86B9100231E07 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; };
63 | D74F36A91FA86966003D0416 /* TTFortuneWheel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TTFortuneWheel.framework; sourceTree = BUILT_PRODUCTS_DIR; };
64 | D74F36AC1FA86966003D0416 /* TTFortuneWheel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TTFortuneWheel.h; sourceTree = ""; };
65 | D74F36AD1FA86966003D0416 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
66 | D74F36B81FA86AD7003D0416 /* TTFortuneWheelSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TTFortuneWheelSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
67 | D74F36BA1FA86AD7003D0416 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
68 | D74F36BC1FA86AD7003D0416 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
69 | D74F36BF1FA86AD7003D0416 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
70 | D74F36C11FA86AD7003D0416 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
71 | D74F36C41FA86AD7003D0416 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
72 | D74F36C61FA86AD7003D0416 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
73 | D7D7F0451FA88B3B0042B5C6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
74 | D7E515CD1FA9C3C900218F8A /* CarnivalWheelSlice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarnivalWheelSlice.swift; sourceTree = ""; };
75 | D7E515D01FA9C5D800218F8A /* Chunkfive.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Chunkfive.otf; sourceTree = ""; };
76 | D7E515D11FA9C5E800218F8A /* Lobster_1.3.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Lobster_1.3.otf; sourceTree = ""; };
77 | D7E515D21FA9C60900218F8A /* Phosphate.ttc */ = {isa = PBXFileReference; lastKnownFileType = file; path = Phosphate.ttc; sourceTree = ""; };
78 | D7E515D31FA9C61600218F8A /* BEBAS___.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "BEBAS___.ttf"; sourceTree = ""; };
79 | /* End PBXFileReference section */
80 |
81 | /* Begin PBXFrameworksBuildPhase section */
82 | D74F36A51FA86966003D0416 /* Frameworks */ = {
83 | isa = PBXFrameworksBuildPhase;
84 | buildActionMask = 2147483647;
85 | files = (
86 | );
87 | runOnlyForDeploymentPostprocessing = 0;
88 | };
89 | D74F36B51FA86AD7003D0416 /* Frameworks */ = {
90 | isa = PBXFrameworksBuildPhase;
91 | buildActionMask = 2147483647;
92 | files = (
93 | D7043A2D1FE29CBB0064F43D /* TTFortuneWheel.framework in Frameworks */,
94 | );
95 | runOnlyForDeploymentPostprocessing = 0;
96 | };
97 | /* End PBXFrameworksBuildPhase section */
98 |
99 | /* Begin PBXGroup section */
100 | D74F369F1FA86966003D0416 = {
101 | isa = PBXGroup;
102 | children = (
103 | D74F36AB1FA86966003D0416 /* TTFortuneWheel */,
104 | D74F36B91FA86AD7003D0416 /* TTFortuneWheelSample */,
105 | D74F36AA1FA86966003D0416 /* Products */,
106 | D798CC7C1FA86FA200FE2880 /* Frameworks */,
107 | );
108 | sourceTree = "";
109 | };
110 | D74F36AA1FA86966003D0416 /* Products */ = {
111 | isa = PBXGroup;
112 | children = (
113 | D74F36A91FA86966003D0416 /* TTFortuneWheel.framework */,
114 | D74F36B81FA86AD7003D0416 /* TTFortuneWheelSample.app */,
115 | );
116 | name = Products;
117 | sourceTree = "";
118 | };
119 | D74F36AB1FA86966003D0416 /* TTFortuneWheel */ = {
120 | isa = PBXGroup;
121 | children = (
122 | D74F36AC1FA86966003D0416 /* TTFortuneWheel.h */,
123 | D70B49571FA86B9100231E07 /* SpinningWheelAnimator.swift */,
124 | D70B49581FA86B9100231E07 /* FortuneWheelLayer.swift */,
125 | D70B49591FA86B9100231E07 /* SpinningWheelSlice .swift */,
126 | D70B495A1FA86B9100231E07 /* SpinningWheelSliceImpl.swift */,
127 | D70B495B1FA86B9100231E07 /* TTFortuneWheel.swift */,
128 | D70B495C1FA86B9100231E07 /* Utils.swift */,
129 | D74F36AD1FA86966003D0416 /* Info.plist */,
130 | D7D7F0461FA88B420042B5C6 /* Resources */,
131 | );
132 | path = TTFortuneWheel;
133 | sourceTree = "";
134 | };
135 | D74F36B91FA86AD7003D0416 /* TTFortuneWheelSample */ = {
136 | isa = PBXGroup;
137 | children = (
138 | D74F36BA1FA86AD7003D0416 /* AppDelegate.swift */,
139 | D74F36BC1FA86AD7003D0416 /* ViewController.swift */,
140 | D74F36BE1FA86AD7003D0416 /* Main.storyboard */,
141 | D74F36C11FA86AD7003D0416 /* Assets.xcassets */,
142 | D74F36C31FA86AD7003D0416 /* LaunchScreen.storyboard */,
143 | D74F36C61FA86AD7003D0416 /* Info.plist */,
144 | D7E515CD1FA9C3C900218F8A /* CarnivalWheelSlice.swift */,
145 | D7E515CF1FA9C5CE00218F8A /* Resources */,
146 | );
147 | path = TTFortuneWheelSample;
148 | sourceTree = "";
149 | };
150 | D798CC7C1FA86FA200FE2880 /* Frameworks */ = {
151 | isa = PBXGroup;
152 | children = (
153 | );
154 | name = Frameworks;
155 | sourceTree = "";
156 | };
157 | D7D7F0461FA88B420042B5C6 /* Resources */ = {
158 | isa = PBXGroup;
159 | children = (
160 | D7D7F0451FA88B3B0042B5C6 /* Assets.xcassets */,
161 | );
162 | path = Resources;
163 | sourceTree = "";
164 | };
165 | D7E515CF1FA9C5CE00218F8A /* Resources */ = {
166 | isa = PBXGroup;
167 | children = (
168 | D7E515D31FA9C61600218F8A /* BEBAS___.ttf */,
169 | D7E515D21FA9C60900218F8A /* Phosphate.ttc */,
170 | D7E515D11FA9C5E800218F8A /* Lobster_1.3.otf */,
171 | D7E515D01FA9C5D800218F8A /* Chunkfive.otf */,
172 | );
173 | path = Resources;
174 | sourceTree = "";
175 | };
176 | /* End PBXGroup section */
177 |
178 | /* Begin PBXHeadersBuildPhase section */
179 | D74F36A61FA86966003D0416 /* Headers */ = {
180 | isa = PBXHeadersBuildPhase;
181 | buildActionMask = 2147483647;
182 | files = (
183 | D74F36AE1FA86966003D0416 /* TTFortuneWheel.h in Headers */,
184 | );
185 | runOnlyForDeploymentPostprocessing = 0;
186 | };
187 | /* End PBXHeadersBuildPhase section */
188 |
189 | /* Begin PBXNativeTarget section */
190 | D74F36A81FA86966003D0416 /* TTFortuneWheel */ = {
191 | isa = PBXNativeTarget;
192 | buildConfigurationList = D74F36B11FA86966003D0416 /* Build configuration list for PBXNativeTarget "TTFortuneWheel" */;
193 | buildPhases = (
194 | D74F36A41FA86966003D0416 /* Sources */,
195 | D74F36A51FA86966003D0416 /* Frameworks */,
196 | D74F36A61FA86966003D0416 /* Headers */,
197 | D74F36A71FA86966003D0416 /* Resources */,
198 | );
199 | buildRules = (
200 | );
201 | dependencies = (
202 | );
203 | name = TTFortuneWheel;
204 | productName = TTFortuneWheel;
205 | productReference = D74F36A91FA86966003D0416 /* TTFortuneWheel.framework */;
206 | productType = "com.apple.product-type.framework";
207 | };
208 | D74F36B71FA86AD7003D0416 /* TTFortuneWheelSample */ = {
209 | isa = PBXNativeTarget;
210 | buildConfigurationList = D74F36C71FA86AD7003D0416 /* Build configuration list for PBXNativeTarget "TTFortuneWheelSample" */;
211 | buildPhases = (
212 | D74F36B41FA86AD7003D0416 /* Sources */,
213 | D74F36B51FA86AD7003D0416 /* Frameworks */,
214 | D74F36B61FA86AD7003D0416 /* Resources */,
215 | D7043A331FE29DAD0064F43D /* Embed Frameworks */,
216 | );
217 | buildRules = (
218 | );
219 | dependencies = (
220 | D7043A321FE29DAD0064F43D /* PBXTargetDependency */,
221 | );
222 | name = TTFortuneWheelSample;
223 | productName = TTFortuneWheelSample;
224 | productReference = D74F36B81FA86AD7003D0416 /* TTFortuneWheelSample.app */;
225 | productType = "com.apple.product-type.application";
226 | };
227 | /* End PBXNativeTarget section */
228 |
229 | /* Begin PBXProject section */
230 | D74F36A01FA86966003D0416 /* Project object */ = {
231 | isa = PBXProject;
232 | attributes = {
233 | LastSwiftUpdateCheck = 0900;
234 | LastUpgradeCheck = 1110;
235 | ORGANIZATIONNAME = Tapptitude;
236 | TargetAttributes = {
237 | D74F36A81FA86966003D0416 = {
238 | CreatedOnToolsVersion = 9.0;
239 | LastSwiftMigration = 0820;
240 | ProvisioningStyle = Automatic;
241 | };
242 | D74F36B71FA86AD7003D0416 = {
243 | CreatedOnToolsVersion = 9.0;
244 | ProvisioningStyle = Automatic;
245 | };
246 | };
247 | };
248 | buildConfigurationList = D74F36A31FA86966003D0416 /* Build configuration list for PBXProject "TTFortuneWheel" */;
249 | compatibilityVersion = "Xcode 8.0";
250 | developmentRegion = en;
251 | hasScannedForEncodings = 0;
252 | knownRegions = (
253 | en,
254 | Base,
255 | );
256 | mainGroup = D74F369F1FA86966003D0416;
257 | productRefGroup = D74F36AA1FA86966003D0416 /* Products */;
258 | projectDirPath = "";
259 | projectRoot = "";
260 | targets = (
261 | D74F36A81FA86966003D0416 /* TTFortuneWheel */,
262 | D74F36B71FA86AD7003D0416 /* TTFortuneWheelSample */,
263 | );
264 | };
265 | /* End PBXProject section */
266 |
267 | /* Begin PBXResourcesBuildPhase section */
268 | D74F36A71FA86966003D0416 /* Resources */ = {
269 | isa = PBXResourcesBuildPhase;
270 | buildActionMask = 2147483647;
271 | files = (
272 | D7043A2E1FE29D310064F43D /* Assets.xcassets in Resources */,
273 | );
274 | runOnlyForDeploymentPostprocessing = 0;
275 | };
276 | D74F36B61FA86AD7003D0416 /* Resources */ = {
277 | isa = PBXResourcesBuildPhase;
278 | buildActionMask = 2147483647;
279 | files = (
280 | D7E515D81FA9C63C00218F8A /* BEBAS___.ttf in Resources */,
281 | D7E515D91FA9C63C00218F8A /* Phosphate.ttc in Resources */,
282 | D7E515DA1FA9C63C00218F8A /* Lobster_1.3.otf in Resources */,
283 | D7E515DB1FA9C63C00218F8A /* Chunkfive.otf in Resources */,
284 | D74F36C51FA86AD7003D0416 /* LaunchScreen.storyboard in Resources */,
285 | D74F36C21FA86AD7003D0416 /* Assets.xcassets in Resources */,
286 | D74F36C01FA86AD7003D0416 /* Main.storyboard in Resources */,
287 | );
288 | runOnlyForDeploymentPostprocessing = 0;
289 | };
290 | /* End PBXResourcesBuildPhase section */
291 |
292 | /* Begin PBXSourcesBuildPhase section */
293 | D74F36A41FA86966003D0416 /* Sources */ = {
294 | isa = PBXSourcesBuildPhase;
295 | buildActionMask = 2147483647;
296 | files = (
297 | D70B49631FA86B9100231E07 /* SpinningWheelSliceImpl.swift in Sources */,
298 | D70B495D1FA86B9100231E07 /* SpinningWheelAnimator.swift in Sources */,
299 | D70B495F1FA86B9100231E07 /* FortuneWheelLayer.swift in Sources */,
300 | D70B49651FA86B9100231E07 /* TTFortuneWheel.swift in Sources */,
301 | D70B49611FA86B9100231E07 /* SpinningWheelSlice .swift in Sources */,
302 | D70B49671FA86B9100231E07 /* Utils.swift in Sources */,
303 | );
304 | runOnlyForDeploymentPostprocessing = 0;
305 | };
306 | D74F36B41FA86AD7003D0416 /* Sources */ = {
307 | isa = PBXSourcesBuildPhase;
308 | buildActionMask = 2147483647;
309 | files = (
310 | D74F36BD1FA86AD7003D0416 /* ViewController.swift in Sources */,
311 | D74F36BB1FA86AD7003D0416 /* AppDelegate.swift in Sources */,
312 | D7E515CE1FA9C3C900218F8A /* CarnivalWheelSlice.swift in Sources */,
313 | );
314 | runOnlyForDeploymentPostprocessing = 0;
315 | };
316 | /* End PBXSourcesBuildPhase section */
317 |
318 | /* Begin PBXTargetDependency section */
319 | D7043A321FE29DAD0064F43D /* PBXTargetDependency */ = {
320 | isa = PBXTargetDependency;
321 | target = D74F36A81FA86966003D0416 /* TTFortuneWheel */;
322 | targetProxy = D7043A311FE29DAD0064F43D /* PBXContainerItemProxy */;
323 | };
324 | /* End PBXTargetDependency section */
325 |
326 | /* Begin PBXVariantGroup section */
327 | D74F36BE1FA86AD7003D0416 /* Main.storyboard */ = {
328 | isa = PBXVariantGroup;
329 | children = (
330 | D74F36BF1FA86AD7003D0416 /* Base */,
331 | );
332 | name = Main.storyboard;
333 | sourceTree = "";
334 | };
335 | D74F36C31FA86AD7003D0416 /* LaunchScreen.storyboard */ = {
336 | isa = PBXVariantGroup;
337 | children = (
338 | D74F36C41FA86AD7003D0416 /* Base */,
339 | );
340 | name = LaunchScreen.storyboard;
341 | sourceTree = "";
342 | };
343 | /* End PBXVariantGroup section */
344 |
345 | /* Begin XCBuildConfiguration section */
346 | D74F36AF1FA86966003D0416 /* Debug */ = {
347 | isa = XCBuildConfiguration;
348 | buildSettings = {
349 | ALWAYS_SEARCH_USER_PATHS = NO;
350 | CLANG_ANALYZER_NONNULL = YES;
351 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
352 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
353 | CLANG_CXX_LIBRARY = "libc++";
354 | CLANG_ENABLE_MODULES = YES;
355 | CLANG_ENABLE_OBJC_ARC = YES;
356 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
357 | CLANG_WARN_BOOL_CONVERSION = YES;
358 | CLANG_WARN_COMMA = YES;
359 | CLANG_WARN_CONSTANT_CONVERSION = YES;
360 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
361 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
362 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
363 | CLANG_WARN_EMPTY_BODY = YES;
364 | CLANG_WARN_ENUM_CONVERSION = YES;
365 | CLANG_WARN_INFINITE_RECURSION = YES;
366 | CLANG_WARN_INT_CONVERSION = YES;
367 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
368 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
369 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
370 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
371 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
372 | CLANG_WARN_STRICT_PROTOTYPES = YES;
373 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
374 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
375 | CLANG_WARN_UNREACHABLE_CODE = YES;
376 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
377 | CODE_SIGN_IDENTITY = "iPhone Developer";
378 | COPY_PHASE_STRIP = NO;
379 | CURRENT_PROJECT_VERSION = 1;
380 | DEBUG_INFORMATION_FORMAT = dwarf;
381 | ENABLE_STRICT_OBJC_MSGSEND = YES;
382 | ENABLE_TESTABILITY = YES;
383 | GCC_C_LANGUAGE_STANDARD = gnu11;
384 | GCC_DYNAMIC_NO_PIC = NO;
385 | GCC_NO_COMMON_BLOCKS = YES;
386 | GCC_OPTIMIZATION_LEVEL = 0;
387 | GCC_PREPROCESSOR_DEFINITIONS = (
388 | "DEBUG=1",
389 | "$(inherited)",
390 | );
391 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
392 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
393 | GCC_WARN_UNDECLARED_SELECTOR = YES;
394 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
395 | GCC_WARN_UNUSED_FUNCTION = YES;
396 | GCC_WARN_UNUSED_VARIABLE = YES;
397 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
398 | MTL_ENABLE_DEBUG_INFO = YES;
399 | ONLY_ACTIVE_ARCH = YES;
400 | SDKROOT = iphoneos;
401 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
402 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
403 | SWIFT_VERSION = 4.2;
404 | VERSIONING_SYSTEM = "apple-generic";
405 | VERSION_INFO_PREFIX = "";
406 | };
407 | name = Debug;
408 | };
409 | D74F36B01FA86966003D0416 /* Release */ = {
410 | isa = XCBuildConfiguration;
411 | buildSettings = {
412 | ALWAYS_SEARCH_USER_PATHS = NO;
413 | CLANG_ANALYZER_NONNULL = YES;
414 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
415 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
416 | CLANG_CXX_LIBRARY = "libc++";
417 | CLANG_ENABLE_MODULES = YES;
418 | CLANG_ENABLE_OBJC_ARC = YES;
419 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
420 | CLANG_WARN_BOOL_CONVERSION = YES;
421 | CLANG_WARN_COMMA = YES;
422 | CLANG_WARN_CONSTANT_CONVERSION = YES;
423 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
424 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
425 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
426 | CLANG_WARN_EMPTY_BODY = YES;
427 | CLANG_WARN_ENUM_CONVERSION = YES;
428 | CLANG_WARN_INFINITE_RECURSION = YES;
429 | CLANG_WARN_INT_CONVERSION = YES;
430 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
431 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
432 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
433 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
434 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
435 | CLANG_WARN_STRICT_PROTOTYPES = YES;
436 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
437 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
438 | CLANG_WARN_UNREACHABLE_CODE = YES;
439 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
440 | CODE_SIGN_IDENTITY = "iPhone Developer";
441 | COPY_PHASE_STRIP = NO;
442 | CURRENT_PROJECT_VERSION = 1;
443 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
444 | ENABLE_NS_ASSERTIONS = NO;
445 | ENABLE_STRICT_OBJC_MSGSEND = YES;
446 | GCC_C_LANGUAGE_STANDARD = gnu11;
447 | GCC_NO_COMMON_BLOCKS = YES;
448 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
449 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
450 | GCC_WARN_UNDECLARED_SELECTOR = YES;
451 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
452 | GCC_WARN_UNUSED_FUNCTION = YES;
453 | GCC_WARN_UNUSED_VARIABLE = YES;
454 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
455 | MTL_ENABLE_DEBUG_INFO = NO;
456 | SDKROOT = iphoneos;
457 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
458 | SWIFT_VERSION = 4.2;
459 | VALIDATE_PRODUCT = YES;
460 | VERSIONING_SYSTEM = "apple-generic";
461 | VERSION_INFO_PREFIX = "";
462 | };
463 | name = Release;
464 | };
465 | D74F36B21FA86966003D0416 /* Debug */ = {
466 | isa = XCBuildConfiguration;
467 | buildSettings = {
468 | APPLICATION_EXTENSION_API_ONLY = NO;
469 | CLANG_ENABLE_MODULES = YES;
470 | CODE_SIGN_IDENTITY = "";
471 | CODE_SIGN_STYLE = Automatic;
472 | DEFINES_MODULE = YES;
473 | DEVELOPMENT_TEAM = G7T599BH7B;
474 | DYLIB_COMPATIBILITY_VERSION = 1;
475 | DYLIB_CURRENT_VERSION = 1;
476 | DYLIB_INSTALL_NAME_BASE = "@rpath";
477 | INFOPLIST_FILE = TTFortuneWheel/Info.plist;
478 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
479 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
480 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
481 | PRODUCT_BUNDLE_IDENTIFIER = com.tapptitude.TTFortuneWheel;
482 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
483 | SKIP_INSTALL = YES;
484 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
485 | SWIFT_VERSION = 5.0;
486 | TARGETED_DEVICE_FAMILY = "1,2";
487 | };
488 | name = Debug;
489 | };
490 | D74F36B31FA86966003D0416 /* Release */ = {
491 | isa = XCBuildConfiguration;
492 | buildSettings = {
493 | APPLICATION_EXTENSION_API_ONLY = NO;
494 | CLANG_ENABLE_MODULES = YES;
495 | CODE_SIGN_IDENTITY = "";
496 | CODE_SIGN_STYLE = Automatic;
497 | DEFINES_MODULE = YES;
498 | DEVELOPMENT_TEAM = G7T599BH7B;
499 | DYLIB_COMPATIBILITY_VERSION = 1;
500 | DYLIB_CURRENT_VERSION = 1;
501 | DYLIB_INSTALL_NAME_BASE = "@rpath";
502 | INFOPLIST_FILE = TTFortuneWheel/Info.plist;
503 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
504 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
505 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
506 | PRODUCT_BUNDLE_IDENTIFIER = com.tapptitude.TTFortuneWheel;
507 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
508 | SKIP_INSTALL = YES;
509 | SWIFT_VERSION = 5.0;
510 | TARGETED_DEVICE_FAMILY = "1,2";
511 | };
512 | name = Release;
513 | };
514 | D74F36C81FA86AD7003D0416 /* Debug */ = {
515 | isa = XCBuildConfiguration;
516 | buildSettings = {
517 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
518 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
519 | CODE_SIGN_STYLE = Automatic;
520 | DEVELOPMENT_TEAM = G7T599BH7B;
521 | INFOPLIST_FILE = TTFortuneWheelSample/Info.plist;
522 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
523 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
524 | PRODUCT_BUNDLE_IDENTIFIER = com.tapptitude.TTFortuneWheelSample;
525 | PRODUCT_NAME = "$(TARGET_NAME)";
526 | SWIFT_VERSION = 5.0;
527 | TARGETED_DEVICE_FAMILY = "1,2";
528 | };
529 | name = Debug;
530 | };
531 | D74F36C91FA86AD7003D0416 /* Release */ = {
532 | isa = XCBuildConfiguration;
533 | buildSettings = {
534 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
535 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
536 | CODE_SIGN_STYLE = Automatic;
537 | DEVELOPMENT_TEAM = G7T599BH7B;
538 | INFOPLIST_FILE = TTFortuneWheelSample/Info.plist;
539 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
540 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
541 | PRODUCT_BUNDLE_IDENTIFIER = com.tapptitude.TTFortuneWheelSample;
542 | PRODUCT_NAME = "$(TARGET_NAME)";
543 | SWIFT_VERSION = 5.0;
544 | TARGETED_DEVICE_FAMILY = "1,2";
545 | };
546 | name = Release;
547 | };
548 | /* End XCBuildConfiguration section */
549 |
550 | /* Begin XCConfigurationList section */
551 | D74F36A31FA86966003D0416 /* Build configuration list for PBXProject "TTFortuneWheel" */ = {
552 | isa = XCConfigurationList;
553 | buildConfigurations = (
554 | D74F36AF1FA86966003D0416 /* Debug */,
555 | D74F36B01FA86966003D0416 /* Release */,
556 | );
557 | defaultConfigurationIsVisible = 0;
558 | defaultConfigurationName = Release;
559 | };
560 | D74F36B11FA86966003D0416 /* Build configuration list for PBXNativeTarget "TTFortuneWheel" */ = {
561 | isa = XCConfigurationList;
562 | buildConfigurations = (
563 | D74F36B21FA86966003D0416 /* Debug */,
564 | D74F36B31FA86966003D0416 /* Release */,
565 | );
566 | defaultConfigurationIsVisible = 0;
567 | defaultConfigurationName = Release;
568 | };
569 | D74F36C71FA86AD7003D0416 /* Build configuration list for PBXNativeTarget "TTFortuneWheelSample" */ = {
570 | isa = XCConfigurationList;
571 | buildConfigurations = (
572 | D74F36C81FA86AD7003D0416 /* Debug */,
573 | D74F36C91FA86AD7003D0416 /* Release */,
574 | );
575 | defaultConfigurationIsVisible = 0;
576 | defaultConfigurationName = Release;
577 | };
578 | /* End XCConfigurationList section */
579 | };
580 | rootObject = D74F36A01FA86966003D0416 /* Project object */;
581 | }
582 |
--------------------------------------------------------------------------------