├── GeometryPractical ├── Assets.xcassets │ ├── Contents.json │ ├── geometry.imageset │ │ ├── geometry.png │ │ └── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── geometry.png ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── ContentView.swift ├── AppDelegate.swift ├── Base.lproj │ └── LaunchScreen.storyboard ├── Polygon.swift ├── Info.plist ├── CircleLabel.swift ├── SceneDelegate.swift └── Watch.swift ├── GeometryPractical.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ └── trungphan.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ └── xcschememanagement.plist └── project.pbxproj ├── README.md ├── GeometryPracticalTests ├── Info.plist └── GeometryPracticalTests.swift ├── GeometryPracticalUITests ├── Info.plist └── GeometryPracticalUITests.swift └── LICENSE /GeometryPractical/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /GeometryPractical/geometry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/viettrungphan/SwiftUIGeometryPractice/HEAD/GeometryPractical/geometry.png -------------------------------------------------------------------------------- /GeometryPractical/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /GeometryPractical/Assets.xcassets/geometry.imageset/geometry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/viettrungphan/SwiftUIGeometryPractice/HEAD/GeometryPractical/Assets.xcassets/geometry.imageset/geometry.png -------------------------------------------------------------------------------- /GeometryPractical.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /GeometryPractical.xcodeproj/xcuserdata/trungphan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /GeometryPractical.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftUIGeometryPractice 2 | Build Watch face, Circle Text using SwiftUI 3 | 4 | For explanation please read my Medium articles: 5 | https://medium.com/@phanviettrung/create-circular-text-using-swiftui-32cd7e5b6414 6 | 7 | https://medium.com/@phanviettrung/draw-watch-face-using-swiftui-a863ad347b2c 8 | 9 | ![Image Watch](https://i.imgur.com/hdVMpkN.png) 10 | -------------------------------------------------------------------------------- /GeometryPractical/Assets.xcassets/geometry.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "geometry.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /GeometryPractical.xcodeproj/xcuserdata/trungphan.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | GeometryPractical.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /GeometryPracticalTests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /GeometryPracticalUITests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /GeometryPractical/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // GeometryPractical 4 | // 5 | // Created by TrungPhan on 3/5/20. 6 | // Copyright © 2020 TrungPhan. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct ContentView: View { 12 | var body: some View { 13 | VStack { 14 | Watch() 15 | .frame(width: 200, height: 200, alignment: .center) 16 | 17 | Text("Dwarves Foundation Looking for iOS, Golang, FE candidate.") 18 | CircleText(radius: 100, text: "Dwarves Foundation Looking for iOS, Golang, FE candidate.", kerning: 2) 19 | 20 | // VStack { 21 | // PolygonView(sides: 3) 22 | // Image("geometry") 23 | // .resizable() 24 | // .frame(width: 300, height: 300) 25 | // } 26 | } 27 | 28 | } 29 | } 30 | 31 | struct ContentView_Previews: PreviewProvider { 32 | static var previews: some View { 33 | ContentView() 34 | } 35 | } 36 | 37 | 38 | -------------------------------------------------------------------------------- /GeometryPracticalTests/GeometryPracticalTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GeometryPracticalTests.swift 3 | // GeometryPracticalTests 4 | // 5 | // Created by TrungPhan on 3/5/20. 6 | // Copyright © 2020 TrungPhan. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import GeometryPractical 11 | 12 | class GeometryPracticalTests: XCTestCase { 13 | 14 | override func setUp() { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testExample() { 23 | // This is an example of a functional test case. 24 | // Use XCTAssert and related functions to verify your tests produce the correct results. 25 | } 26 | 27 | func testPerformanceExample() { 28 | // This is an example of a performance test case. 29 | self.measure { 30 | // Put the code you want to measure the time of here. 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Trung Phan 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 | -------------------------------------------------------------------------------- /GeometryPractical/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // GeometryPractical 4 | // 5 | // Created by TrungPhan on 3/5/20. 6 | // Copyright © 2020 TrungPhan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | return true 19 | } 20 | 21 | // MARK: UISceneSession Lifecycle 22 | 23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 24 | // Called when a new scene session is being created. 25 | // Use this method to select a configuration to create the new scene with. 26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 27 | } 28 | 29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 30 | // Called when the user discards a scene session. 31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 33 | } 34 | 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /GeometryPracticalUITests/GeometryPracticalUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GeometryPracticalUITests.swift 3 | // GeometryPracticalUITests 4 | // 5 | // Created by TrungPhan on 3/5/20. 6 | // Copyright © 2020 TrungPhan. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class GeometryPracticalUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | 16 | // In UI tests it is usually best to stop immediately when a failure occurs. 17 | continueAfterFailure = false 18 | 19 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 20 | } 21 | 22 | override func tearDown() { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | } 25 | 26 | func testExample() { 27 | // UI tests must launch the application that they test. 28 | let app = XCUIApplication() 29 | app.launch() 30 | 31 | // Use recording to get started writing UI tests. 32 | // Use XCTAssert and related functions to verify your tests produce the correct results. 33 | } 34 | 35 | func testLaunchPerformance() { 36 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { 37 | // This measures how long it takes to launch your application. 38 | measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) { 39 | XCUIApplication().launch() 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /GeometryPractical/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 | -------------------------------------------------------------------------------- /GeometryPractical/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 | } -------------------------------------------------------------------------------- /GeometryPractical/Polygon.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Polygon.swift 3 | // GeometryPractical 4 | // 5 | // Created by Trung Phan on 3/20/20. 6 | // Copyright © 2020 TrungPhan. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | 12 | struct PolygonView_Previews: PreviewProvider { 13 | static var previews: some View { 14 | PolygonView(sides: 8) 15 | } 16 | } 17 | 18 | 19 | //MARK: - Polygon 20 | 21 | struct PolygonView: View { 22 | @State var sides: CGFloat 23 | 24 | var body: some View { 25 | VStack { 26 | ZStack { 27 | Circle() 28 | VStack { 29 | Polygon(sides: sides) 30 | .stroke(lineWidth: 2) 31 | .foregroundColor(Color.blue) 32 | .animation(.easeIn(duration: 3)) 33 | } 34 | } 35 | .frame(width: 200, height: 200, alignment: .center) 36 | Text("Tham khảo https://swiftui-lab.com/swiftui-animations-part1") 37 | Stepper("Change to", value: $sides, in: 0...100) 38 | .padding() 39 | } 40 | 41 | } 42 | } 43 | 44 | 45 | struct Polygon: Shape { 46 | var sides: CGFloat 47 | var animatableData: CGFloat { 48 | get { return sides } 49 | set { sides = newValue } 50 | } 51 | func path(in rect: CGRect) -> Path { 52 | 53 | var path = Path() 54 | let center = CGPoint(x: rect.midX, y: rect.midY) 55 | let height = min(rect.width, rect.height) / 2 56 | let extra: Int = Double(sides) != Double(Int(sides)) ? 1 : 0 57 | for i in 0.. 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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | 37 | 38 | 39 | 40 | UILaunchStoryboardName 41 | LaunchScreen 42 | UIRequiredDeviceCapabilities 43 | 44 | armv7 45 | 46 | UISupportedInterfaceOrientations 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | UISupportedInterfaceOrientations~ipad 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationPortraitUpsideDown 56 | UIInterfaceOrientationLandscapeLeft 57 | UIInterfaceOrientationLandscapeRight 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /GeometryPractical/CircleLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CircleLabel.swift 3 | // GeometryPractical 4 | // 5 | // Created by Trung Phan on 3/18/20. 6 | // Copyright © 2020 TrungPhan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftUI 11 | struct CircleText_Preview: PreviewProvider { 12 | static var previews: some View { 13 | CircleText(radius: 200, text: "Dwarves Foundation Looking for Golang, FE candidates") 14 | } 15 | } 16 | 17 | //MARK: - CircleLabel 18 | 19 | struct CircleText: View { 20 | var radius: Double 21 | var text: String 22 | var kerning: CGFloat = 5.0 23 | 24 | private var texts: [(offset: Int, element:Character)] { 25 | return Array(text.enumerated()) 26 | } 27 | 28 | @State var textSizes: [Int:Double] = [:] 29 | 30 | var body: some View { 31 | ZStack { 32 | ForEach(self.texts, id: \.self.offset) { (offset, element) in 33 | VStack { 34 | Text(String(element)) 35 | .kerning(self.kerning) 36 | .background(Sizeable()) 37 | .onPreferenceChange(WidthPreferenceKey.self, perform: { size in 38 | self.textSizes[offset] = Double(size) 39 | }) 40 | Spacer() 41 | } 42 | .rotationEffect(self.angle(at: offset)) 43 | 44 | } 45 | }.rotationEffect(-self.angle(at: self.texts.count-1)/2) 46 | 47 | .frame(width: 300, height: 300, alignment: .center) 48 | } 49 | 50 | private func angle(at index: Int) -> Angle { 51 | guard let labelSize = textSizes[index] else {return .radians(0)} 52 | let percentOfLabelInCircle = labelSize / radius.perimeter 53 | let labelAngle = 2 * Double.pi * percentOfLabelInCircle 54 | 55 | 56 | let totalSizeOfPreChars = textSizes.filter{$0.key < index}.map{$0.value}.reduce(0,+) 57 | let percenOfPreCharInCircle = totalSizeOfPreChars / radius.perimeter 58 | let angleForPreChars = 2 * Double.pi * percenOfPreCharInCircle 59 | 60 | return .radians(angleForPreChars + labelAngle) 61 | } 62 | 63 | } 64 | 65 | 66 | 67 | extension Double { 68 | var perimeter: Double { 69 | return self * 2 * .pi 70 | } 71 | } 72 | 73 | 74 | //Get size for label helper 75 | struct WidthPreferenceKey: PreferenceKey { 76 | typealias Value = CGFloat 77 | static var defaultValue = CGFloat(0) 78 | static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { 79 | value = nextValue() 80 | } 81 | } 82 | struct Sizeable: View { 83 | var body: some View { 84 | GeometryReader { geometry in 85 | Color.clear 86 | .preference(key: WidthPreferenceKey.self, value: geometry.size.width) 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /GeometryPractical/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // GeometryPractical 4 | // 5 | // Created by TrungPhan on 3/5/20. 6 | // Copyright © 2020 TrungPhan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SwiftUI 11 | 12 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 18 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 19 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 20 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 21 | 22 | // Create the SwiftUI view that provides the window contents. 23 | let contentView = ContentView() 24 | 25 | // Use a UIHostingController as window root view controller. 26 | if let windowScene = scene as? UIWindowScene { 27 | let window = UIWindow(windowScene: windowScene) 28 | window.rootViewController = UIHostingController(rootView: contentView) 29 | self.window = window 30 | window.makeKeyAndVisible() 31 | } 32 | } 33 | 34 | func sceneDidDisconnect(_ scene: UIScene) { 35 | // Called as the scene is being released by the system. 36 | // This occurs shortly after the scene enters the background, or when its session is discarded. 37 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 38 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). 39 | } 40 | 41 | func sceneDidBecomeActive(_ scene: UIScene) { 42 | // Called when the scene has moved from an inactive state to an active state. 43 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 44 | } 45 | 46 | func sceneWillResignActive(_ scene: UIScene) { 47 | // Called when the scene will move from an active state to an inactive state. 48 | // This may occur due to temporary interruptions (ex. an incoming phone call). 49 | } 50 | 51 | func sceneWillEnterForeground(_ scene: UIScene) { 52 | // Called as the scene transitions from the background to the foreground. 53 | // Use this method to undo the changes made on entering the background. 54 | } 55 | 56 | func sceneDidEnterBackground(_ scene: UIScene) { 57 | // Called as the scene transitions from the foreground to the background. 58 | // Use this method to save data, release shared resources, and store enough scene-specific state information 59 | // to restore the scene back to its current state. 60 | } 61 | 62 | 63 | } 64 | 65 | -------------------------------------------------------------------------------- /GeometryPractical/Watch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Watch.swift 3 | // GeometryPractical 4 | // 5 | // Created by Trung Phan on 3/18/20. 6 | // Copyright © 2020 TrungPhan. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftUI 11 | 12 | 13 | //MARK: - Watch 14 | 15 | struct Watch_Preview: PreviewProvider { 16 | static var previews: Watch { 17 | Watch() 18 | } 19 | } 20 | 21 | struct Watch: View { 22 | @State var date:Date = Date() 23 | 24 | var body: some View { 25 | let calendar = Calendar.current 26 | let dateComponents = calendar.dateComponents([.hour, .minute, .second], from: date) 27 | 28 | //Convert Date to angle 29 | var minuteAngle:Double = 0 30 | var hourAngle:Double = 0 31 | var secondAngle: Double = 0 32 | 33 | 34 | if let hour = dateComponents.hour, 35 | let minute = dateComponents.minute, 36 | let second = dateComponents.second { 37 | 38 | let radianInOneHour = 2 * Double.pi / 12 39 | let radianInOneMinute = 2 * Double.pi / 60 40 | 41 | minuteAngle = Double(minute) * radianInOneMinute 42 | 43 | let actualHour = Double(hour) + (Double(minute)/60) 44 | 45 | hourAngle = actualHour * radianInOneHour 46 | 47 | secondAngle = Double(second) * radianInOneMinute 48 | } 49 | 50 | return ZStack{ 51 | // Circle().fill(Color.green) 52 | Arc() 53 | .stroke(lineWidth: 3) 54 | 55 | Ticks() 56 | Numbers() 57 | Circle() 58 | .fill() 59 | .frame(width: 15, height: 15, alignment: .center) 60 | //Hour hand 61 | Hand(offSet: 40) 62 | .fill() 63 | .frame(width: 4, alignment: .center) 64 | .rotationEffect(.radians(hourAngle)) 65 | 66 | //Minute hand 67 | Hand(offSet: 10) 68 | .fill() 69 | .frame(width: 3, alignment: .center) 70 | .rotationEffect(.radians(minuteAngle)) 71 | 72 | //Second hand 73 | Hand(offSet: 5) 74 | .fill() 75 | .foregroundColor(.red) 76 | .frame(width: 2, alignment: .center) 77 | .rotationEffect(.radians(secondAngle)) 78 | 79 | Circle() 80 | .fill() 81 | .foregroundColor(.red) 82 | .frame(width: 7, height: 7, alignment: .center) 83 | } 84 | .frame(width: 200, height: 200, alignment: .center) 85 | .onAppear(perform: start) 86 | } 87 | 88 | func start() { 89 | Timer.scheduledTimer(withTimeInterval: 1 /*3*/, repeats: true) { _ in 90 | self.date = Date() 91 | /* 92 | withAnimation(.spring()) { 93 | self.date = Date() 94 | } 95 | */ 96 | } 97 | } 98 | } 99 | 100 | struct Arc: Shape { 101 | 102 | var startAngle: Angle = .radians(0) 103 | var endAngle: Angle = .radians(Double.pi * 2) 104 | var clockWise: Bool = true 105 | func path(in rect: CGRect) -> Path { 106 | var path = Path() 107 | 108 | let center = CGPoint(x: rect.midX, y: rect.midY) 109 | let radius = min(rect.width/2, rect.height/2) 110 | 111 | path.addArc(center: center, radius: radius , startAngle: startAngle, endAngle: endAngle, clockwise: clockWise) 112 | return path 113 | } 114 | } 115 | 116 | struct Circle: Shape { 117 | func path(in rect: CGRect) -> Path { 118 | var path = Path() 119 | path.addEllipse(in: rect) 120 | return path 121 | } 122 | } 123 | 124 | struct Hand: Shape { 125 | var offSet: CGFloat = 0 126 | func path(in rect: CGRect) -> Path { 127 | var path = Path() 128 | path.addRoundedRect(in: CGRect(origin: CGPoint(x: rect.origin.x, y: rect.origin.y + offSet), size: CGSize(width: rect.width, height: rect.height/2 - offSet)), cornerSize: CGSize(width: rect.width/2, height: rect.width/2)) 129 | return path 130 | } 131 | } 132 | 133 | struct Ticks: View { 134 | var body: some View { 135 | ZStack { 136 | ForEach(0..<60) { position in 137 | Tick(isLong: position % 5 == 0 ) 138 | .stroke(lineWidth: 2) 139 | .rotationEffect(.radians(Double.pi*2 / 60 * Double(position))) 140 | 141 | } 142 | } 143 | } 144 | } 145 | 146 | struct Tick: Shape { 147 | var isLong: Bool = false 148 | func path(in rect: CGRect) -> Path { 149 | var path = Path() 150 | path.move(to: CGPoint(x:rect.midX, y: rect.minY)) 151 | path.addLine(to: CGPoint(x:rect.midX, y: rect.minY + 5 + (isLong ? 5 : 0) )) 152 | return path 153 | } 154 | } 155 | 156 | struct Numbers: View { 157 | var body: some View { 158 | ZStack{ 159 | ForEach(1..<13) { hour in 160 | Number(hour: hour) 161 | } 162 | 163 | } 164 | } 165 | } 166 | 167 | struct Number: View { 168 | var hour: Int 169 | var body: some View { 170 | VStack { 171 | Text("\(hour)").fontWeight(.bold) 172 | .rotationEffect(.radians(-(Double.pi*2 / 12 * Double(hour)))) 173 | Spacer() 174 | } 175 | .padding() 176 | .rotationEffect(.radians( (Double.pi*2 / 12 * Double(hour)))) 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /GeometryPractical.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 553C695C2424BCD10028826C /* geometry.png in Resources */ = {isa = PBXBuildFile; fileRef = 553C695B2424BCD10028826C /* geometry.png */; }; 11 | 555582AE2424737B001E74D7 /* Polygon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 555582AD2424737B001E74D7 /* Polygon.swift */; }; 12 | 557903762421FCC900FEECA3 /* Watch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557903752421FCC900FEECA3 /* Watch.swift */; }; 13 | 557903782421FCF200FEECA3 /* CircleLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557903772421FCF200FEECA3 /* CircleLabel.swift */; }; 14 | 558B14A62410AD2700CE973E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558B14A52410AD2700CE973E /* AppDelegate.swift */; }; 15 | 558B14A82410AD2700CE973E /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558B14A72410AD2700CE973E /* SceneDelegate.swift */; }; 16 | 558B14AA2410AD2700CE973E /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558B14A92410AD2700CE973E /* ContentView.swift */; }; 17 | 558B14AC2410AD2A00CE973E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 558B14AB2410AD2A00CE973E /* Assets.xcassets */; }; 18 | 558B14AF2410AD2A00CE973E /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 558B14AE2410AD2A00CE973E /* Preview Assets.xcassets */; }; 19 | 558B14B22410AD2A00CE973E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 558B14B02410AD2A00CE973E /* LaunchScreen.storyboard */; }; 20 | 558B14BD2410AD2A00CE973E /* GeometryPracticalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558B14BC2410AD2A00CE973E /* GeometryPracticalTests.swift */; }; 21 | 558B14C82410AD2A00CE973E /* GeometryPracticalUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 558B14C72410AD2A00CE973E /* GeometryPracticalUITests.swift */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXContainerItemProxy section */ 25 | 558B14B92410AD2A00CE973E /* PBXContainerItemProxy */ = { 26 | isa = PBXContainerItemProxy; 27 | containerPortal = 558B149A2410AD2600CE973E /* Project object */; 28 | proxyType = 1; 29 | remoteGlobalIDString = 558B14A12410AD2700CE973E; 30 | remoteInfo = GeometryPractical; 31 | }; 32 | 558B14C42410AD2A00CE973E /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 558B149A2410AD2600CE973E /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = 558B14A12410AD2700CE973E; 37 | remoteInfo = GeometryPractical; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | 553C695B2424BCD10028826C /* geometry.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = geometry.png; sourceTree = ""; }; 43 | 555582AD2424737B001E74D7 /* Polygon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Polygon.swift; sourceTree = ""; }; 44 | 557903752421FCC900FEECA3 /* Watch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Watch.swift; sourceTree = ""; }; 45 | 557903772421FCF200FEECA3 /* CircleLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircleLabel.swift; sourceTree = ""; }; 46 | 558B14A22410AD2700CE973E /* GeometryPractical.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GeometryPractical.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 558B14A52410AD2700CE973E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 48 | 558B14A72410AD2700CE973E /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 49 | 558B14A92410AD2700CE973E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 50 | 558B14AB2410AD2A00CE973E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 51 | 558B14AE2410AD2A00CE973E /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 52 | 558B14B12410AD2A00CE973E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 53 | 558B14B32410AD2A00CE973E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 54 | 558B14B82410AD2A00CE973E /* GeometryPracticalTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GeometryPracticalTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | 558B14BC2410AD2A00CE973E /* GeometryPracticalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeometryPracticalTests.swift; sourceTree = ""; }; 56 | 558B14BE2410AD2A00CE973E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57 | 558B14C32410AD2A00CE973E /* GeometryPracticalUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GeometryPracticalUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 558B14C72410AD2A00CE973E /* GeometryPracticalUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeometryPracticalUITests.swift; sourceTree = ""; }; 59 | 558B14C92410AD2A00CE973E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 60 | /* End PBXFileReference section */ 61 | 62 | /* Begin PBXFrameworksBuildPhase section */ 63 | 558B149F2410AD2700CE973E /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | 558B14B52410AD2A00CE973E /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | ); 75 | runOnlyForDeploymentPostprocessing = 0; 76 | }; 77 | 558B14C02410AD2A00CE973E /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | /* End PBXFrameworksBuildPhase section */ 85 | 86 | /* Begin PBXGroup section */ 87 | 558B14992410AD2600CE973E = { 88 | isa = PBXGroup; 89 | children = ( 90 | 558B14A42410AD2700CE973E /* GeometryPractical */, 91 | 558B14BB2410AD2A00CE973E /* GeometryPracticalTests */, 92 | 558B14C62410AD2A00CE973E /* GeometryPracticalUITests */, 93 | 558B14A32410AD2700CE973E /* Products */, 94 | ); 95 | sourceTree = ""; 96 | }; 97 | 558B14A32410AD2700CE973E /* Products */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 558B14A22410AD2700CE973E /* GeometryPractical.app */, 101 | 558B14B82410AD2A00CE973E /* GeometryPracticalTests.xctest */, 102 | 558B14C32410AD2A00CE973E /* GeometryPracticalUITests.xctest */, 103 | ); 104 | name = Products; 105 | sourceTree = ""; 106 | }; 107 | 558B14A42410AD2700CE973E /* GeometryPractical */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | 558B14A52410AD2700CE973E /* AppDelegate.swift */, 111 | 558B14A72410AD2700CE973E /* SceneDelegate.swift */, 112 | 558B14A92410AD2700CE973E /* ContentView.swift */, 113 | 557903752421FCC900FEECA3 /* Watch.swift */, 114 | 557903772421FCF200FEECA3 /* CircleLabel.swift */, 115 | 555582AD2424737B001E74D7 /* Polygon.swift */, 116 | 553C695B2424BCD10028826C /* geometry.png */, 117 | 558B14AB2410AD2A00CE973E /* Assets.xcassets */, 118 | 558B14B02410AD2A00CE973E /* LaunchScreen.storyboard */, 119 | 558B14B32410AD2A00CE973E /* Info.plist */, 120 | 558B14AD2410AD2A00CE973E /* Preview Content */, 121 | ); 122 | path = GeometryPractical; 123 | sourceTree = ""; 124 | }; 125 | 558B14AD2410AD2A00CE973E /* Preview Content */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 558B14AE2410AD2A00CE973E /* Preview Assets.xcassets */, 129 | ); 130 | path = "Preview Content"; 131 | sourceTree = ""; 132 | }; 133 | 558B14BB2410AD2A00CE973E /* GeometryPracticalTests */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 558B14BC2410AD2A00CE973E /* GeometryPracticalTests.swift */, 137 | 558B14BE2410AD2A00CE973E /* Info.plist */, 138 | ); 139 | path = GeometryPracticalTests; 140 | sourceTree = ""; 141 | }; 142 | 558B14C62410AD2A00CE973E /* GeometryPracticalUITests */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | 558B14C72410AD2A00CE973E /* GeometryPracticalUITests.swift */, 146 | 558B14C92410AD2A00CE973E /* Info.plist */, 147 | ); 148 | path = GeometryPracticalUITests; 149 | sourceTree = ""; 150 | }; 151 | /* End PBXGroup section */ 152 | 153 | /* Begin PBXNativeTarget section */ 154 | 558B14A12410AD2700CE973E /* GeometryPractical */ = { 155 | isa = PBXNativeTarget; 156 | buildConfigurationList = 558B14CC2410AD2B00CE973E /* Build configuration list for PBXNativeTarget "GeometryPractical" */; 157 | buildPhases = ( 158 | 558B149E2410AD2700CE973E /* Sources */, 159 | 558B149F2410AD2700CE973E /* Frameworks */, 160 | 558B14A02410AD2700CE973E /* Resources */, 161 | ); 162 | buildRules = ( 163 | ); 164 | dependencies = ( 165 | ); 166 | name = GeometryPractical; 167 | productName = GeometryPractical; 168 | productReference = 558B14A22410AD2700CE973E /* GeometryPractical.app */; 169 | productType = "com.apple.product-type.application"; 170 | }; 171 | 558B14B72410AD2A00CE973E /* GeometryPracticalTests */ = { 172 | isa = PBXNativeTarget; 173 | buildConfigurationList = 558B14CF2410AD2B00CE973E /* Build configuration list for PBXNativeTarget "GeometryPracticalTests" */; 174 | buildPhases = ( 175 | 558B14B42410AD2A00CE973E /* Sources */, 176 | 558B14B52410AD2A00CE973E /* Frameworks */, 177 | 558B14B62410AD2A00CE973E /* Resources */, 178 | ); 179 | buildRules = ( 180 | ); 181 | dependencies = ( 182 | 558B14BA2410AD2A00CE973E /* PBXTargetDependency */, 183 | ); 184 | name = GeometryPracticalTests; 185 | productName = GeometryPracticalTests; 186 | productReference = 558B14B82410AD2A00CE973E /* GeometryPracticalTests.xctest */; 187 | productType = "com.apple.product-type.bundle.unit-test"; 188 | }; 189 | 558B14C22410AD2A00CE973E /* GeometryPracticalUITests */ = { 190 | isa = PBXNativeTarget; 191 | buildConfigurationList = 558B14D22410AD2B00CE973E /* Build configuration list for PBXNativeTarget "GeometryPracticalUITests" */; 192 | buildPhases = ( 193 | 558B14BF2410AD2A00CE973E /* Sources */, 194 | 558B14C02410AD2A00CE973E /* Frameworks */, 195 | 558B14C12410AD2A00CE973E /* Resources */, 196 | ); 197 | buildRules = ( 198 | ); 199 | dependencies = ( 200 | 558B14C52410AD2A00CE973E /* PBXTargetDependency */, 201 | ); 202 | name = GeometryPracticalUITests; 203 | productName = GeometryPracticalUITests; 204 | productReference = 558B14C32410AD2A00CE973E /* GeometryPracticalUITests.xctest */; 205 | productType = "com.apple.product-type.bundle.ui-testing"; 206 | }; 207 | /* End PBXNativeTarget section */ 208 | 209 | /* Begin PBXProject section */ 210 | 558B149A2410AD2600CE973E /* Project object */ = { 211 | isa = PBXProject; 212 | attributes = { 213 | LastSwiftUpdateCheck = 1130; 214 | LastUpgradeCheck = 1130; 215 | ORGANIZATIONNAME = TrungPhan; 216 | TargetAttributes = { 217 | 558B14A12410AD2700CE973E = { 218 | CreatedOnToolsVersion = 11.3.1; 219 | }; 220 | 558B14B72410AD2A00CE973E = { 221 | CreatedOnToolsVersion = 11.3.1; 222 | TestTargetID = 558B14A12410AD2700CE973E; 223 | }; 224 | 558B14C22410AD2A00CE973E = { 225 | CreatedOnToolsVersion = 11.3.1; 226 | TestTargetID = 558B14A12410AD2700CE973E; 227 | }; 228 | }; 229 | }; 230 | buildConfigurationList = 558B149D2410AD2600CE973E /* Build configuration list for PBXProject "GeometryPractical" */; 231 | compatibilityVersion = "Xcode 9.3"; 232 | developmentRegion = en; 233 | hasScannedForEncodings = 0; 234 | knownRegions = ( 235 | en, 236 | Base, 237 | ); 238 | mainGroup = 558B14992410AD2600CE973E; 239 | productRefGroup = 558B14A32410AD2700CE973E /* Products */; 240 | projectDirPath = ""; 241 | projectRoot = ""; 242 | targets = ( 243 | 558B14A12410AD2700CE973E /* GeometryPractical */, 244 | 558B14B72410AD2A00CE973E /* GeometryPracticalTests */, 245 | 558B14C22410AD2A00CE973E /* GeometryPracticalUITests */, 246 | ); 247 | }; 248 | /* End PBXProject section */ 249 | 250 | /* Begin PBXResourcesBuildPhase section */ 251 | 558B14A02410AD2700CE973E /* Resources */ = { 252 | isa = PBXResourcesBuildPhase; 253 | buildActionMask = 2147483647; 254 | files = ( 255 | 558B14B22410AD2A00CE973E /* LaunchScreen.storyboard in Resources */, 256 | 558B14AF2410AD2A00CE973E /* Preview Assets.xcassets in Resources */, 257 | 553C695C2424BCD10028826C /* geometry.png in Resources */, 258 | 558B14AC2410AD2A00CE973E /* Assets.xcassets in Resources */, 259 | ); 260 | runOnlyForDeploymentPostprocessing = 0; 261 | }; 262 | 558B14B62410AD2A00CE973E /* Resources */ = { 263 | isa = PBXResourcesBuildPhase; 264 | buildActionMask = 2147483647; 265 | files = ( 266 | ); 267 | runOnlyForDeploymentPostprocessing = 0; 268 | }; 269 | 558B14C12410AD2A00CE973E /* Resources */ = { 270 | isa = PBXResourcesBuildPhase; 271 | buildActionMask = 2147483647; 272 | files = ( 273 | ); 274 | runOnlyForDeploymentPostprocessing = 0; 275 | }; 276 | /* End PBXResourcesBuildPhase section */ 277 | 278 | /* Begin PBXSourcesBuildPhase section */ 279 | 558B149E2410AD2700CE973E /* Sources */ = { 280 | isa = PBXSourcesBuildPhase; 281 | buildActionMask = 2147483647; 282 | files = ( 283 | 558B14A62410AD2700CE973E /* AppDelegate.swift in Sources */, 284 | 557903762421FCC900FEECA3 /* Watch.swift in Sources */, 285 | 555582AE2424737B001E74D7 /* Polygon.swift in Sources */, 286 | 558B14A82410AD2700CE973E /* SceneDelegate.swift in Sources */, 287 | 558B14AA2410AD2700CE973E /* ContentView.swift in Sources */, 288 | 557903782421FCF200FEECA3 /* CircleLabel.swift in Sources */, 289 | ); 290 | runOnlyForDeploymentPostprocessing = 0; 291 | }; 292 | 558B14B42410AD2A00CE973E /* Sources */ = { 293 | isa = PBXSourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | 558B14BD2410AD2A00CE973E /* GeometryPracticalTests.swift in Sources */, 297 | ); 298 | runOnlyForDeploymentPostprocessing = 0; 299 | }; 300 | 558B14BF2410AD2A00CE973E /* Sources */ = { 301 | isa = PBXSourcesBuildPhase; 302 | buildActionMask = 2147483647; 303 | files = ( 304 | 558B14C82410AD2A00CE973E /* GeometryPracticalUITests.swift in Sources */, 305 | ); 306 | runOnlyForDeploymentPostprocessing = 0; 307 | }; 308 | /* End PBXSourcesBuildPhase section */ 309 | 310 | /* Begin PBXTargetDependency section */ 311 | 558B14BA2410AD2A00CE973E /* PBXTargetDependency */ = { 312 | isa = PBXTargetDependency; 313 | target = 558B14A12410AD2700CE973E /* GeometryPractical */; 314 | targetProxy = 558B14B92410AD2A00CE973E /* PBXContainerItemProxy */; 315 | }; 316 | 558B14C52410AD2A00CE973E /* PBXTargetDependency */ = { 317 | isa = PBXTargetDependency; 318 | target = 558B14A12410AD2700CE973E /* GeometryPractical */; 319 | targetProxy = 558B14C42410AD2A00CE973E /* PBXContainerItemProxy */; 320 | }; 321 | /* End PBXTargetDependency section */ 322 | 323 | /* Begin PBXVariantGroup section */ 324 | 558B14B02410AD2A00CE973E /* LaunchScreen.storyboard */ = { 325 | isa = PBXVariantGroup; 326 | children = ( 327 | 558B14B12410AD2A00CE973E /* Base */, 328 | ); 329 | name = LaunchScreen.storyboard; 330 | sourceTree = ""; 331 | }; 332 | /* End PBXVariantGroup section */ 333 | 334 | /* Begin XCBuildConfiguration section */ 335 | 558B14CA2410AD2B00CE973E /* Debug */ = { 336 | isa = XCBuildConfiguration; 337 | buildSettings = { 338 | ALWAYS_SEARCH_USER_PATHS = NO; 339 | CLANG_ANALYZER_NONNULL = YES; 340 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 341 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 342 | CLANG_CXX_LIBRARY = "libc++"; 343 | CLANG_ENABLE_MODULES = YES; 344 | CLANG_ENABLE_OBJC_ARC = YES; 345 | CLANG_ENABLE_OBJC_WEAK = YES; 346 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 347 | CLANG_WARN_BOOL_CONVERSION = YES; 348 | CLANG_WARN_COMMA = YES; 349 | CLANG_WARN_CONSTANT_CONVERSION = YES; 350 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 351 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 352 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 353 | CLANG_WARN_EMPTY_BODY = YES; 354 | CLANG_WARN_ENUM_CONVERSION = YES; 355 | CLANG_WARN_INFINITE_RECURSION = YES; 356 | CLANG_WARN_INT_CONVERSION = YES; 357 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 358 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 359 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 360 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 361 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 362 | CLANG_WARN_STRICT_PROTOTYPES = YES; 363 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 364 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 365 | CLANG_WARN_UNREACHABLE_CODE = YES; 366 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 367 | COPY_PHASE_STRIP = NO; 368 | DEBUG_INFORMATION_FORMAT = dwarf; 369 | ENABLE_STRICT_OBJC_MSGSEND = YES; 370 | ENABLE_TESTABILITY = YES; 371 | GCC_C_LANGUAGE_STANDARD = gnu11; 372 | GCC_DYNAMIC_NO_PIC = NO; 373 | GCC_NO_COMMON_BLOCKS = YES; 374 | GCC_OPTIMIZATION_LEVEL = 0; 375 | GCC_PREPROCESSOR_DEFINITIONS = ( 376 | "DEBUG=1", 377 | "$(inherited)", 378 | ); 379 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 380 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 381 | GCC_WARN_UNDECLARED_SELECTOR = YES; 382 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 383 | GCC_WARN_UNUSED_FUNCTION = YES; 384 | GCC_WARN_UNUSED_VARIABLE = YES; 385 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 386 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 387 | MTL_FAST_MATH = YES; 388 | ONLY_ACTIVE_ARCH = YES; 389 | SDKROOT = iphoneos; 390 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 391 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 392 | }; 393 | name = Debug; 394 | }; 395 | 558B14CB2410AD2B00CE973E /* Release */ = { 396 | isa = XCBuildConfiguration; 397 | buildSettings = { 398 | ALWAYS_SEARCH_USER_PATHS = NO; 399 | CLANG_ANALYZER_NONNULL = YES; 400 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 401 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 402 | CLANG_CXX_LIBRARY = "libc++"; 403 | CLANG_ENABLE_MODULES = YES; 404 | CLANG_ENABLE_OBJC_ARC = YES; 405 | CLANG_ENABLE_OBJC_WEAK = YES; 406 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 407 | CLANG_WARN_BOOL_CONVERSION = YES; 408 | CLANG_WARN_COMMA = YES; 409 | CLANG_WARN_CONSTANT_CONVERSION = YES; 410 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 411 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 412 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 413 | CLANG_WARN_EMPTY_BODY = YES; 414 | CLANG_WARN_ENUM_CONVERSION = YES; 415 | CLANG_WARN_INFINITE_RECURSION = YES; 416 | CLANG_WARN_INT_CONVERSION = YES; 417 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 418 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 419 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 420 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 421 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 422 | CLANG_WARN_STRICT_PROTOTYPES = YES; 423 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 424 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 425 | CLANG_WARN_UNREACHABLE_CODE = YES; 426 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 427 | COPY_PHASE_STRIP = NO; 428 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 429 | ENABLE_NS_ASSERTIONS = NO; 430 | ENABLE_STRICT_OBJC_MSGSEND = YES; 431 | GCC_C_LANGUAGE_STANDARD = gnu11; 432 | GCC_NO_COMMON_BLOCKS = YES; 433 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 434 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 435 | GCC_WARN_UNDECLARED_SELECTOR = YES; 436 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 437 | GCC_WARN_UNUSED_FUNCTION = YES; 438 | GCC_WARN_UNUSED_VARIABLE = YES; 439 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 440 | MTL_ENABLE_DEBUG_INFO = NO; 441 | MTL_FAST_MATH = YES; 442 | SDKROOT = iphoneos; 443 | SWIFT_COMPILATION_MODE = wholemodule; 444 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 445 | VALIDATE_PRODUCT = YES; 446 | }; 447 | name = Release; 448 | }; 449 | 558B14CD2410AD2B00CE973E /* Debug */ = { 450 | isa = XCBuildConfiguration; 451 | buildSettings = { 452 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 453 | CODE_SIGN_STYLE = Automatic; 454 | DEVELOPMENT_ASSET_PATHS = "\"GeometryPractical/Preview Content\""; 455 | ENABLE_PREVIEWS = YES; 456 | INFOPLIST_FILE = GeometryPractical/Info.plist; 457 | LD_RUNPATH_SEARCH_PATHS = ( 458 | "$(inherited)", 459 | "@executable_path/Frameworks", 460 | ); 461 | PRODUCT_BUNDLE_IDENTIFIER = com.tphan.GeometryPractical; 462 | PRODUCT_NAME = "$(TARGET_NAME)"; 463 | SWIFT_VERSION = 5.0; 464 | TARGETED_DEVICE_FAMILY = "1,2"; 465 | }; 466 | name = Debug; 467 | }; 468 | 558B14CE2410AD2B00CE973E /* Release */ = { 469 | isa = XCBuildConfiguration; 470 | buildSettings = { 471 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 472 | CODE_SIGN_STYLE = Automatic; 473 | DEVELOPMENT_ASSET_PATHS = "\"GeometryPractical/Preview Content\""; 474 | ENABLE_PREVIEWS = YES; 475 | INFOPLIST_FILE = GeometryPractical/Info.plist; 476 | LD_RUNPATH_SEARCH_PATHS = ( 477 | "$(inherited)", 478 | "@executable_path/Frameworks", 479 | ); 480 | PRODUCT_BUNDLE_IDENTIFIER = com.tphan.GeometryPractical; 481 | PRODUCT_NAME = "$(TARGET_NAME)"; 482 | SWIFT_VERSION = 5.0; 483 | TARGETED_DEVICE_FAMILY = "1,2"; 484 | }; 485 | name = Release; 486 | }; 487 | 558B14D02410AD2B00CE973E /* Debug */ = { 488 | isa = XCBuildConfiguration; 489 | buildSettings = { 490 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 491 | BUNDLE_LOADER = "$(TEST_HOST)"; 492 | CODE_SIGN_STYLE = Automatic; 493 | INFOPLIST_FILE = GeometryPracticalTests/Info.plist; 494 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 495 | LD_RUNPATH_SEARCH_PATHS = ( 496 | "$(inherited)", 497 | "@executable_path/Frameworks", 498 | "@loader_path/Frameworks", 499 | ); 500 | PRODUCT_BUNDLE_IDENTIFIER = com.tphan.GeometryPracticalTests; 501 | PRODUCT_NAME = "$(TARGET_NAME)"; 502 | SWIFT_VERSION = 5.0; 503 | TARGETED_DEVICE_FAMILY = "1,2"; 504 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/GeometryPractical.app/GeometryPractical"; 505 | }; 506 | name = Debug; 507 | }; 508 | 558B14D12410AD2B00CE973E /* Release */ = { 509 | isa = XCBuildConfiguration; 510 | buildSettings = { 511 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 512 | BUNDLE_LOADER = "$(TEST_HOST)"; 513 | CODE_SIGN_STYLE = Automatic; 514 | INFOPLIST_FILE = GeometryPracticalTests/Info.plist; 515 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 516 | LD_RUNPATH_SEARCH_PATHS = ( 517 | "$(inherited)", 518 | "@executable_path/Frameworks", 519 | "@loader_path/Frameworks", 520 | ); 521 | PRODUCT_BUNDLE_IDENTIFIER = com.tphan.GeometryPracticalTests; 522 | PRODUCT_NAME = "$(TARGET_NAME)"; 523 | SWIFT_VERSION = 5.0; 524 | TARGETED_DEVICE_FAMILY = "1,2"; 525 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/GeometryPractical.app/GeometryPractical"; 526 | }; 527 | name = Release; 528 | }; 529 | 558B14D32410AD2B00CE973E /* Debug */ = { 530 | isa = XCBuildConfiguration; 531 | buildSettings = { 532 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 533 | CODE_SIGN_STYLE = Automatic; 534 | INFOPLIST_FILE = GeometryPracticalUITests/Info.plist; 535 | LD_RUNPATH_SEARCH_PATHS = ( 536 | "$(inherited)", 537 | "@executable_path/Frameworks", 538 | "@loader_path/Frameworks", 539 | ); 540 | PRODUCT_BUNDLE_IDENTIFIER = com.tphan.GeometryPracticalUITests; 541 | PRODUCT_NAME = "$(TARGET_NAME)"; 542 | SWIFT_VERSION = 5.0; 543 | TARGETED_DEVICE_FAMILY = "1,2"; 544 | TEST_TARGET_NAME = GeometryPractical; 545 | }; 546 | name = Debug; 547 | }; 548 | 558B14D42410AD2B00CE973E /* Release */ = { 549 | isa = XCBuildConfiguration; 550 | buildSettings = { 551 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 552 | CODE_SIGN_STYLE = Automatic; 553 | INFOPLIST_FILE = GeometryPracticalUITests/Info.plist; 554 | LD_RUNPATH_SEARCH_PATHS = ( 555 | "$(inherited)", 556 | "@executable_path/Frameworks", 557 | "@loader_path/Frameworks", 558 | ); 559 | PRODUCT_BUNDLE_IDENTIFIER = com.tphan.GeometryPracticalUITests; 560 | PRODUCT_NAME = "$(TARGET_NAME)"; 561 | SWIFT_VERSION = 5.0; 562 | TARGETED_DEVICE_FAMILY = "1,2"; 563 | TEST_TARGET_NAME = GeometryPractical; 564 | }; 565 | name = Release; 566 | }; 567 | /* End XCBuildConfiguration section */ 568 | 569 | /* Begin XCConfigurationList section */ 570 | 558B149D2410AD2600CE973E /* Build configuration list for PBXProject "GeometryPractical" */ = { 571 | isa = XCConfigurationList; 572 | buildConfigurations = ( 573 | 558B14CA2410AD2B00CE973E /* Debug */, 574 | 558B14CB2410AD2B00CE973E /* Release */, 575 | ); 576 | defaultConfigurationIsVisible = 0; 577 | defaultConfigurationName = Release; 578 | }; 579 | 558B14CC2410AD2B00CE973E /* Build configuration list for PBXNativeTarget "GeometryPractical" */ = { 580 | isa = XCConfigurationList; 581 | buildConfigurations = ( 582 | 558B14CD2410AD2B00CE973E /* Debug */, 583 | 558B14CE2410AD2B00CE973E /* Release */, 584 | ); 585 | defaultConfigurationIsVisible = 0; 586 | defaultConfigurationName = Release; 587 | }; 588 | 558B14CF2410AD2B00CE973E /* Build configuration list for PBXNativeTarget "GeometryPracticalTests" */ = { 589 | isa = XCConfigurationList; 590 | buildConfigurations = ( 591 | 558B14D02410AD2B00CE973E /* Debug */, 592 | 558B14D12410AD2B00CE973E /* Release */, 593 | ); 594 | defaultConfigurationIsVisible = 0; 595 | defaultConfigurationName = Release; 596 | }; 597 | 558B14D22410AD2B00CE973E /* Build configuration list for PBXNativeTarget "GeometryPracticalUITests" */ = { 598 | isa = XCConfigurationList; 599 | buildConfigurations = ( 600 | 558B14D32410AD2B00CE973E /* Debug */, 601 | 558B14D42410AD2B00CE973E /* Release */, 602 | ); 603 | defaultConfigurationIsVisible = 0; 604 | defaultConfigurationName = Release; 605 | }; 606 | /* End XCConfigurationList section */ 607 | }; 608 | rootObject = 558B149A2410AD2600CE973E /* Project object */; 609 | } 610 | --------------------------------------------------------------------------------