├── CircularTimer.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── swiftpm │ │ └── Package.resolved └── xcuserdata │ └── harfyzz.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist └── CircularTimer ├── Assets.xcassets ├── AccentColor.colorset │ └── Contents.json ├── AppIcon.appiconset │ └── Contents.json ├── Contents.json ├── SpaceGrotesk.dataset │ ├── Contents.json │ └── SpaceGrotesk-VariableFont_wght.ttf └── bg.colorset │ └── Contents.json ├── CircularTimerApp.swift ├── ContentView.swift ├── Preview Content └── Preview Assets.xcassets │ └── Contents.json └── timer.riv /CircularTimer.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 77; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 346B268A2D4A62750001E485 /* RiveRuntime in Frameworks */ = {isa = PBXBuildFile; productRef = 346B26892D4A62750001E485 /* RiveRuntime */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXFileReference section */ 14 | 346B26772D4A3A480001E485 /* CircularTimer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CircularTimer.app; sourceTree = BUILT_PRODUCTS_DIR; }; 15 | /* End PBXFileReference section */ 16 | 17 | /* Begin PBXFileSystemSynchronizedRootGroup section */ 18 | 346B26792D4A3A480001E485 /* CircularTimer */ = { 19 | isa = PBXFileSystemSynchronizedRootGroup; 20 | path = CircularTimer; 21 | sourceTree = ""; 22 | }; 23 | /* End PBXFileSystemSynchronizedRootGroup section */ 24 | 25 | /* Begin PBXFrameworksBuildPhase section */ 26 | 346B26742D4A3A480001E485 /* Frameworks */ = { 27 | isa = PBXFrameworksBuildPhase; 28 | buildActionMask = 2147483647; 29 | files = ( 30 | 346B268A2D4A62750001E485 /* RiveRuntime in Frameworks */, 31 | ); 32 | runOnlyForDeploymentPostprocessing = 0; 33 | }; 34 | /* End PBXFrameworksBuildPhase section */ 35 | 36 | /* Begin PBXGroup section */ 37 | 346B266E2D4A3A480001E485 = { 38 | isa = PBXGroup; 39 | children = ( 40 | 346B26792D4A3A480001E485 /* CircularTimer */, 41 | 346B26782D4A3A480001E485 /* Products */, 42 | ); 43 | sourceTree = ""; 44 | }; 45 | 346B26782D4A3A480001E485 /* Products */ = { 46 | isa = PBXGroup; 47 | children = ( 48 | 346B26772D4A3A480001E485 /* CircularTimer.app */, 49 | ); 50 | name = Products; 51 | sourceTree = ""; 52 | }; 53 | /* End PBXGroup section */ 54 | 55 | /* Begin PBXNativeTarget section */ 56 | 346B26762D4A3A480001E485 /* CircularTimer */ = { 57 | isa = PBXNativeTarget; 58 | buildConfigurationList = 346B26852D4A3A4A0001E485 /* Build configuration list for PBXNativeTarget "CircularTimer" */; 59 | buildPhases = ( 60 | 346B26732D4A3A480001E485 /* Sources */, 61 | 346B26742D4A3A480001E485 /* Frameworks */, 62 | 346B26752D4A3A480001E485 /* Resources */, 63 | ); 64 | buildRules = ( 65 | ); 66 | dependencies = ( 67 | ); 68 | fileSystemSynchronizedGroups = ( 69 | 346B26792D4A3A480001E485 /* CircularTimer */, 70 | ); 71 | name = CircularTimer; 72 | packageProductDependencies = ( 73 | 346B26892D4A62750001E485 /* RiveRuntime */, 74 | ); 75 | productName = CircularTimer; 76 | productReference = 346B26772D4A3A480001E485 /* CircularTimer.app */; 77 | productType = "com.apple.product-type.application"; 78 | }; 79 | /* End PBXNativeTarget section */ 80 | 81 | /* Begin PBXProject section */ 82 | 346B266F2D4A3A480001E485 /* Project object */ = { 83 | isa = PBXProject; 84 | attributes = { 85 | BuildIndependentTargetsInParallel = 1; 86 | LastSwiftUpdateCheck = 1620; 87 | LastUpgradeCheck = 1620; 88 | TargetAttributes = { 89 | 346B26762D4A3A480001E485 = { 90 | CreatedOnToolsVersion = 16.2; 91 | }; 92 | }; 93 | }; 94 | buildConfigurationList = 346B26722D4A3A480001E485 /* Build configuration list for PBXProject "CircularTimer" */; 95 | developmentRegion = en; 96 | hasScannedForEncodings = 0; 97 | knownRegions = ( 98 | en, 99 | Base, 100 | ); 101 | mainGroup = 346B266E2D4A3A480001E485; 102 | minimizedProjectReferenceProxies = 1; 103 | packageReferences = ( 104 | 346B26882D4A62750001E485 /* XCRemoteSwiftPackageReference "rive-ios" */, 105 | ); 106 | preferredProjectObjectVersion = 77; 107 | productRefGroup = 346B26782D4A3A480001E485 /* Products */; 108 | projectDirPath = ""; 109 | projectRoot = ""; 110 | targets = ( 111 | 346B26762D4A3A480001E485 /* CircularTimer */, 112 | ); 113 | }; 114 | /* End PBXProject section */ 115 | 116 | /* Begin PBXResourcesBuildPhase section */ 117 | 346B26752D4A3A480001E485 /* Resources */ = { 118 | isa = PBXResourcesBuildPhase; 119 | buildActionMask = 2147483647; 120 | files = ( 121 | ); 122 | runOnlyForDeploymentPostprocessing = 0; 123 | }; 124 | /* End PBXResourcesBuildPhase section */ 125 | 126 | /* Begin PBXSourcesBuildPhase section */ 127 | 346B26732D4A3A480001E485 /* Sources */ = { 128 | isa = PBXSourcesBuildPhase; 129 | buildActionMask = 2147483647; 130 | files = ( 131 | ); 132 | runOnlyForDeploymentPostprocessing = 0; 133 | }; 134 | /* End PBXSourcesBuildPhase section */ 135 | 136 | /* Begin XCBuildConfiguration section */ 137 | 346B26832D4A3A4A0001E485 /* Debug */ = { 138 | isa = XCBuildConfiguration; 139 | buildSettings = { 140 | ALWAYS_SEARCH_USER_PATHS = NO; 141 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 142 | CLANG_ANALYZER_NONNULL = YES; 143 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 144 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 145 | CLANG_ENABLE_MODULES = YES; 146 | CLANG_ENABLE_OBJC_ARC = YES; 147 | CLANG_ENABLE_OBJC_WEAK = YES; 148 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 149 | CLANG_WARN_BOOL_CONVERSION = YES; 150 | CLANG_WARN_COMMA = YES; 151 | CLANG_WARN_CONSTANT_CONVERSION = YES; 152 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 153 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 154 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 155 | CLANG_WARN_EMPTY_BODY = YES; 156 | CLANG_WARN_ENUM_CONVERSION = YES; 157 | CLANG_WARN_INFINITE_RECURSION = YES; 158 | CLANG_WARN_INT_CONVERSION = YES; 159 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 160 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 161 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 162 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 163 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 164 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 165 | CLANG_WARN_STRICT_PROTOTYPES = YES; 166 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 167 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 168 | CLANG_WARN_UNREACHABLE_CODE = YES; 169 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 170 | COPY_PHASE_STRIP = NO; 171 | DEBUG_INFORMATION_FORMAT = dwarf; 172 | ENABLE_STRICT_OBJC_MSGSEND = YES; 173 | ENABLE_TESTABILITY = YES; 174 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 175 | GCC_C_LANGUAGE_STANDARD = gnu17; 176 | GCC_DYNAMIC_NO_PIC = NO; 177 | GCC_NO_COMMON_BLOCKS = YES; 178 | GCC_OPTIMIZATION_LEVEL = 0; 179 | GCC_PREPROCESSOR_DEFINITIONS = ( 180 | "DEBUG=1", 181 | "$(inherited)", 182 | ); 183 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 184 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 185 | GCC_WARN_UNDECLARED_SELECTOR = YES; 186 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 187 | GCC_WARN_UNUSED_FUNCTION = YES; 188 | GCC_WARN_UNUSED_VARIABLE = YES; 189 | IPHONEOS_DEPLOYMENT_TARGET = 18.2; 190 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 191 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 192 | MTL_FAST_MATH = YES; 193 | ONLY_ACTIVE_ARCH = YES; 194 | SDKROOT = iphoneos; 195 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; 196 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 197 | }; 198 | name = Debug; 199 | }; 200 | 346B26842D4A3A4A0001E485 /* Release */ = { 201 | isa = XCBuildConfiguration; 202 | buildSettings = { 203 | ALWAYS_SEARCH_USER_PATHS = NO; 204 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 205 | CLANG_ANALYZER_NONNULL = YES; 206 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 207 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 208 | CLANG_ENABLE_MODULES = YES; 209 | CLANG_ENABLE_OBJC_ARC = YES; 210 | CLANG_ENABLE_OBJC_WEAK = YES; 211 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 212 | CLANG_WARN_BOOL_CONVERSION = YES; 213 | CLANG_WARN_COMMA = YES; 214 | CLANG_WARN_CONSTANT_CONVERSION = YES; 215 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 216 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 217 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 218 | CLANG_WARN_EMPTY_BODY = YES; 219 | CLANG_WARN_ENUM_CONVERSION = YES; 220 | CLANG_WARN_INFINITE_RECURSION = YES; 221 | CLANG_WARN_INT_CONVERSION = YES; 222 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 223 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 224 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 225 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 226 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 227 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 228 | CLANG_WARN_STRICT_PROTOTYPES = YES; 229 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 230 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 231 | CLANG_WARN_UNREACHABLE_CODE = YES; 232 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 233 | COPY_PHASE_STRIP = NO; 234 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 235 | ENABLE_NS_ASSERTIONS = NO; 236 | ENABLE_STRICT_OBJC_MSGSEND = YES; 237 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 238 | GCC_C_LANGUAGE_STANDARD = gnu17; 239 | GCC_NO_COMMON_BLOCKS = YES; 240 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 241 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 242 | GCC_WARN_UNDECLARED_SELECTOR = YES; 243 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 244 | GCC_WARN_UNUSED_FUNCTION = YES; 245 | GCC_WARN_UNUSED_VARIABLE = YES; 246 | IPHONEOS_DEPLOYMENT_TARGET = 18.2; 247 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 248 | MTL_ENABLE_DEBUG_INFO = NO; 249 | MTL_FAST_MATH = YES; 250 | SDKROOT = iphoneos; 251 | SWIFT_COMPILATION_MODE = wholemodule; 252 | VALIDATE_PRODUCT = YES; 253 | }; 254 | name = Release; 255 | }; 256 | 346B26862D4A3A4A0001E485 /* Debug */ = { 257 | isa = XCBuildConfiguration; 258 | buildSettings = { 259 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 260 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 261 | CODE_SIGN_STYLE = Automatic; 262 | CURRENT_PROJECT_VERSION = 1; 263 | DEVELOPMENT_ASSET_PATHS = "\"CircularTimer/Preview Content\""; 264 | DEVELOPMENT_TEAM = A8NJ3HM4B4; 265 | ENABLE_PREVIEWS = YES; 266 | GENERATE_INFOPLIST_FILE = YES; 267 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 268 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 269 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 270 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 271 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 272 | LD_RUNPATH_SEARCH_PATHS = ( 273 | "$(inherited)", 274 | "@executable_path/Frameworks", 275 | ); 276 | MARKETING_VERSION = 1.0; 277 | PRODUCT_BUNDLE_IDENTIFIER = bisoladev.CircularTimer; 278 | PRODUCT_NAME = "$(TARGET_NAME)"; 279 | SWIFT_EMIT_LOC_STRINGS = YES; 280 | SWIFT_VERSION = 5.0; 281 | TARGETED_DEVICE_FAMILY = "1,2"; 282 | }; 283 | name = Debug; 284 | }; 285 | 346B26872D4A3A4A0001E485 /* Release */ = { 286 | isa = XCBuildConfiguration; 287 | buildSettings = { 288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 289 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 290 | CODE_SIGN_STYLE = Automatic; 291 | CURRENT_PROJECT_VERSION = 1; 292 | DEVELOPMENT_ASSET_PATHS = "\"CircularTimer/Preview Content\""; 293 | DEVELOPMENT_TEAM = A8NJ3HM4B4; 294 | ENABLE_PREVIEWS = YES; 295 | GENERATE_INFOPLIST_FILE = YES; 296 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 297 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 298 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 299 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 300 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 301 | LD_RUNPATH_SEARCH_PATHS = ( 302 | "$(inherited)", 303 | "@executable_path/Frameworks", 304 | ); 305 | MARKETING_VERSION = 1.0; 306 | PRODUCT_BUNDLE_IDENTIFIER = bisoladev.CircularTimer; 307 | PRODUCT_NAME = "$(TARGET_NAME)"; 308 | SWIFT_EMIT_LOC_STRINGS = YES; 309 | SWIFT_VERSION = 5.0; 310 | TARGETED_DEVICE_FAMILY = "1,2"; 311 | }; 312 | name = Release; 313 | }; 314 | /* End XCBuildConfiguration section */ 315 | 316 | /* Begin XCConfigurationList section */ 317 | 346B26722D4A3A480001E485 /* Build configuration list for PBXProject "CircularTimer" */ = { 318 | isa = XCConfigurationList; 319 | buildConfigurations = ( 320 | 346B26832D4A3A4A0001E485 /* Debug */, 321 | 346B26842D4A3A4A0001E485 /* Release */, 322 | ); 323 | defaultConfigurationIsVisible = 0; 324 | defaultConfigurationName = Release; 325 | }; 326 | 346B26852D4A3A4A0001E485 /* Build configuration list for PBXNativeTarget "CircularTimer" */ = { 327 | isa = XCConfigurationList; 328 | buildConfigurations = ( 329 | 346B26862D4A3A4A0001E485 /* Debug */, 330 | 346B26872D4A3A4A0001E485 /* Release */, 331 | ); 332 | defaultConfigurationIsVisible = 0; 333 | defaultConfigurationName = Release; 334 | }; 335 | /* End XCConfigurationList section */ 336 | 337 | /* Begin XCRemoteSwiftPackageReference section */ 338 | 346B26882D4A62750001E485 /* XCRemoteSwiftPackageReference "rive-ios" */ = { 339 | isa = XCRemoteSwiftPackageReference; 340 | repositoryURL = "https://github.com/rive-app/rive-ios.git"; 341 | requirement = { 342 | kind = upToNextMajorVersion; 343 | minimumVersion = 6.5.10; 344 | }; 345 | }; 346 | /* End XCRemoteSwiftPackageReference section */ 347 | 348 | /* Begin XCSwiftPackageProductDependency section */ 349 | 346B26892D4A62750001E485 /* RiveRuntime */ = { 350 | isa = XCSwiftPackageProductDependency; 351 | package = 346B26882D4A62750001E485 /* XCRemoteSwiftPackageReference "rive-ios" */; 352 | productName = RiveRuntime; 353 | }; 354 | /* End XCSwiftPackageProductDependency section */ 355 | }; 356 | rootObject = 346B266F2D4A3A480001E485 /* Project object */; 357 | } 358 | -------------------------------------------------------------------------------- /CircularTimer.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CircularTimer.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "originHash" : "fe80d800fd3546609c8e9654610353e79fda7758e5303f523f9d300219eddff7", 3 | "pins" : [ 4 | { 5 | "identity" : "rive-ios", 6 | "kind" : "remoteSourceControl", 7 | "location" : "https://github.com/rive-app/rive-ios.git", 8 | "state" : { 9 | "revision" : "00901142e93cc0ce4f54bca2b0f90eabc5ace682", 10 | "version" : "6.5.10" 11 | } 12 | } 13 | ], 14 | "version" : 3 15 | } 16 | -------------------------------------------------------------------------------- /CircularTimer.xcodeproj/xcuserdata/harfyzz.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CircularTimer.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /CircularTimer/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /CircularTimer/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | }, 8 | { 9 | "appearances" : [ 10 | { 11 | "appearance" : "luminosity", 12 | "value" : "dark" 13 | } 14 | ], 15 | "idiom" : "universal", 16 | "platform" : "ios", 17 | "size" : "1024x1024" 18 | }, 19 | { 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "tinted" 24 | } 25 | ], 26 | "idiom" : "universal", 27 | "platform" : "ios", 28 | "size" : "1024x1024" 29 | } 30 | ], 31 | "info" : { 32 | "author" : "xcode", 33 | "version" : 1 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CircularTimer/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /CircularTimer/Assets.xcassets/SpaceGrotesk.dataset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "data" : [ 3 | { 4 | "filename" : "SpaceGrotesk-VariableFont_wght.ttf", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /CircularTimer/Assets.xcassets/SpaceGrotesk.dataset/SpaceGrotesk-VariableFont_wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harfyzz/CircularTimer/270889d2efd15f45a89a4e5cb552087da2db4d03/CircularTimer/Assets.xcassets/SpaceGrotesk.dataset/SpaceGrotesk-VariableFont_wght.ttf -------------------------------------------------------------------------------- /CircularTimer/Assets.xcassets/bg.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.922", 9 | "green" : "0.890", 10 | "red" : "0.855" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "1.000", 27 | "green" : "1.000", 28 | "red" : "1.000" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /CircularTimer/CircularTimerApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CircularTimerApp.swift 3 | // CircularTimer 4 | // 5 | // Created by Afeez Yunus on 29/01/2025. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct CircularTimerApp: App { 12 | var body: some Scene { 13 | WindowGroup { 14 | ContentView() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /CircularTimer/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // CircularTimer 4 | // 5 | // Created by Afeez Yunus on 29/01/2025. 6 | // 7 | 8 | import SwiftUI 9 | import RiveRuntime 10 | 11 | struct ContentView: View { 12 | var riveTimer = Rivetimer() 13 | @State private var currentValue: Double = 0 14 | @State private var previousAngle: Double? = nil 15 | @State var isTimerRunning: Bool = false 16 | @State private var timer: Timer? = nil 17 | var body: some View { 18 | VStack { 19 | Spacer() 20 | HStack{ 21 | Spacer() 22 | VStack{ 23 | Text(String(Int(currentValue * 60))) 24 | Text("MIN") 25 | Text("SETUP TIME") 26 | .font(.headline) 27 | .fontDesign(.monospaced) 28 | } 29 | .font(.system(size: 64, weight: .medium, design: .monospaced)) 30 | .padding(.bottom, 64) 31 | .onChange(of: currentValue) { oldValue, newValue in 32 | // Convert to the 0-60 scale and check whole numbers 33 | if Int(oldValue * 60) != Int(newValue * 60) { 34 | let generator = UIImpactFeedbackGenerator(style: .light) 35 | generator.impactOccurred() 36 | } 37 | } 38 | Spacer() 39 | } 40 | VStack{ 41 | riveTimer.view() 42 | } 43 | .frame(height: 350) 44 | .onChange(of: isTimerRunning, { oldValue, newValue in 45 | riveTimer.setInput("isPlaying?", value: isTimerRunning) 46 | }) 47 | .gesture( 48 | DragGesture(minimumDistance: 1) 49 | .onChanged { gesture in 50 | if !isTimerRunning { 51 | let center = CGPoint(x: 150, y: 150) 52 | let vector = CGVector( 53 | dx: gesture.location.x - center.x, 54 | dy: gesture.location.y - center.y 55 | ) 56 | 57 | let angleInRadians = atan2(vector.dy, vector.dx) 58 | var degrees = (angleInRadians * 180 / .pi + 90) 59 | if degrees < 0 { degrees += 360 } 60 | 61 | // Handle direction and constraints 62 | if let previousAngle = previousAngle { 63 | var angleDelta = degrees - previousAngle 64 | 65 | // Handle crossing the 0/360 boundary 66 | if angleDelta > 180 { 67 | angleDelta -= 360 68 | } else if angleDelta < -180 { 69 | angleDelta += 360 70 | } 71 | 72 | angleDelta = -angleDelta 73 | 74 | // Scale down the sensitivity of the gesture 75 | let newValue = currentValue + (angleDelta / 540) // Changed from 360 to 720 for less sensitivity 76 | currentValue = max(0, min(1, newValue)) 77 | 78 | // Ensure the Rive input gets the full range 79 | let riveValue = min(60, currentValue * 60) 80 | riveTimer.setInput("duration", value: riveValue) 81 | } 82 | 83 | previousAngle = degrees 84 | } 85 | } 86 | .onEnded { _ in 87 | previousAngle = nil 88 | } 89 | ) 90 | .onTapGesture { 91 | if !isTimerRunning { 92 | // Start the timer 93 | isTimerRunning = true 94 | timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { _ in 95 | if currentValue > 0 { 96 | currentValue -= (0.1 / 60) // Decrease by 0.1 seconds converted to minutes 97 | riveTimer.setInput("duration", value: Double(currentValue * 60)) 98 | } else { 99 | // Timer finished 100 | isTimerRunning = false 101 | currentValue = 0 102 | riveTimer.setInput("duration", value: Double(0)) 103 | timer?.invalidate() 104 | timer = nil 105 | } 106 | } 107 | } else { 108 | // Stop the timer 109 | isTimerRunning = false 110 | timer?.invalidate() 111 | timer = nil 112 | } 113 | } 114 | 115 | } 116 | .padding() 117 | 118 | .background(Color("bg")) 119 | .preferredColorScheme(.light) 120 | } 121 | } 122 | 123 | #Preview { 124 | ContentView() 125 | } 126 | 127 | 128 | class Rivetimer: RiveViewModel { 129 | @Published var duration: Bool = true 130 | 131 | init() { 132 | super.init(fileName: "timer", stateMachineName: "main") 133 | } 134 | 135 | func view() -> some View { 136 | super.view() 137 | 138 | } 139 | // Subscribe to Rive events 140 | @objc func onRiveEventReceived(onRiveEvent riveEvent: RiveEvent) { 141 | if let generalEvent = riveEvent as? RiveGeneralEvent { 142 | let eventProperties = generalEvent.properties() 143 | 144 | if let timerStage = eventProperties["isPlaying?"] as? Bool { 145 | duration = timerStage 146 | } 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /CircularTimer/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /CircularTimer/timer.riv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harfyzz/CircularTimer/270889d2efd15f45a89a4e5cb552087da2db4d03/CircularTimer/timer.riv --------------------------------------------------------------------------------