├── Push To-Do.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved └── xcuserdata │ └── sahil.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── Push To-Do ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── App_store_1024_1x.png │ │ ├── Contents.json │ │ ├── iPhone_Notifications_20_2x.png │ │ └── iPhone_Notifications_20_3x.png │ └── Contents.json ├── AudioRecorder.swift .swift ├── ContentView.swift ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── Push_To_DoApp.swift ├── Settings.bundle │ ├── Root.plist │ └── en.lproj │ │ └── Root.strings └── WhisperNotionManager.swift .swift └── README.md /Push To-Do.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BA19308529F4847F009EBFFB /* Push_To_DoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA19308429F4847F009EBFFB /* Push_To_DoApp.swift */; }; 11 | BA19308729F4847F009EBFFB /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA19308629F4847F009EBFFB /* ContentView.swift */; }; 12 | BA19308929F48480009EBFFB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BA19308829F48480009EBFFB /* Assets.xcassets */; }; 13 | BA19308C29F48480009EBFFB /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BA19308B29F48480009EBFFB /* Preview Assets.xcassets */; }; 14 | BA19309629F48515009EBFFB /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA19309529F48515009EBFFB /* AVFoundation.framework */; }; 15 | BA19309829F48572009EBFFB /* WhisperNotionManager.swift .swift in Sources */ = {isa = PBXBuildFile; fileRef = BA19309729F48572009EBFFB /* WhisperNotionManager.swift .swift */; }; 16 | BA19309A29F4857A009EBFFB /* AudioRecorder.swift .swift in Sources */ = {isa = PBXBuildFile; fileRef = BA19309929F4857A009EBFFB /* AudioRecorder.swift .swift */; }; 17 | BA19309D29F48695009EBFFB /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = BA19309C29F48695009EBFFB /* Alamofire */; }; 18 | BA1930A029F486A2009EBFFB /* NotionSwift in Frameworks */ = {isa = PBXBuildFile; productRef = BA19309F29F486A2009EBFFB /* NotionSwift */; }; 19 | BAEA506A29F5ECB1000669E9 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = BAEA506929F5ECB1000669E9 /* Settings.bundle */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | BA19308129F4847F009EBFFB /* Push To-Do.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Push To-Do.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | BA19308429F4847F009EBFFB /* Push_To_DoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Push_To_DoApp.swift; sourceTree = ""; }; 25 | BA19308629F4847F009EBFFB /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 26 | BA19308829F48480009EBFFB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 27 | BA19308B29F48480009EBFFB /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 28 | BA19309529F48515009EBFFB /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 29 | BA19309729F48572009EBFFB /* WhisperNotionManager.swift .swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WhisperNotionManager.swift .swift"; sourceTree = ""; }; 30 | BA19309929F4857A009EBFFB /* AudioRecorder.swift .swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AudioRecorder.swift .swift"; sourceTree = ""; }; 31 | BAEA506929F5ECB1000669E9 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; 32 | /* End PBXFileReference section */ 33 | 34 | /* Begin PBXFrameworksBuildPhase section */ 35 | BA19307E29F4847F009EBFFB /* Frameworks */ = { 36 | isa = PBXFrameworksBuildPhase; 37 | buildActionMask = 2147483647; 38 | files = ( 39 | BA19309629F48515009EBFFB /* AVFoundation.framework in Frameworks */, 40 | BA19309D29F48695009EBFFB /* Alamofire in Frameworks */, 41 | BA1930A029F486A2009EBFFB /* NotionSwift in Frameworks */, 42 | ); 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | /* End PBXFrameworksBuildPhase section */ 46 | 47 | /* Begin PBXGroup section */ 48 | BA19307829F4847F009EBFFB = { 49 | isa = PBXGroup; 50 | children = ( 51 | BA19308329F4847F009EBFFB /* Push To-Do */, 52 | BA19308229F4847F009EBFFB /* Products */, 53 | BA19309429F48515009EBFFB /* Frameworks */, 54 | ); 55 | sourceTree = ""; 56 | }; 57 | BA19308229F4847F009EBFFB /* Products */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | BA19308129F4847F009EBFFB /* Push To-Do.app */, 61 | ); 62 | name = Products; 63 | sourceTree = ""; 64 | }; 65 | BA19308329F4847F009EBFFB /* Push To-Do */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | BA19308429F4847F009EBFFB /* Push_To_DoApp.swift */, 69 | BA19309729F48572009EBFFB /* WhisperNotionManager.swift .swift */, 70 | BAEA506929F5ECB1000669E9 /* Settings.bundle */, 71 | BA19309929F4857A009EBFFB /* AudioRecorder.swift .swift */, 72 | BA19308629F4847F009EBFFB /* ContentView.swift */, 73 | BA19308829F48480009EBFFB /* Assets.xcassets */, 74 | BA19308A29F48480009EBFFB /* Preview Content */, 75 | ); 76 | path = "Push To-Do"; 77 | sourceTree = ""; 78 | }; 79 | BA19308A29F48480009EBFFB /* Preview Content */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | BA19308B29F48480009EBFFB /* Preview Assets.xcassets */, 83 | ); 84 | path = "Preview Content"; 85 | sourceTree = ""; 86 | }; 87 | BA19309429F48515009EBFFB /* Frameworks */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | BA19309529F48515009EBFFB /* AVFoundation.framework */, 91 | ); 92 | name = Frameworks; 93 | sourceTree = ""; 94 | }; 95 | /* End PBXGroup section */ 96 | 97 | /* Begin PBXNativeTarget section */ 98 | BA19308029F4847F009EBFFB /* Push To-Do */ = { 99 | isa = PBXNativeTarget; 100 | buildConfigurationList = BA19308F29F48480009EBFFB /* Build configuration list for PBXNativeTarget "Push To-Do" */; 101 | buildPhases = ( 102 | BA19307D29F4847F009EBFFB /* Sources */, 103 | BA19307E29F4847F009EBFFB /* Frameworks */, 104 | BA19307F29F4847F009EBFFB /* Resources */, 105 | ); 106 | buildRules = ( 107 | ); 108 | dependencies = ( 109 | ); 110 | name = "Push To-Do"; 111 | packageProductDependencies = ( 112 | BA19309C29F48695009EBFFB /* Alamofire */, 113 | BA19309F29F486A2009EBFFB /* NotionSwift */, 114 | ); 115 | productName = "Push To-Do"; 116 | productReference = BA19308129F4847F009EBFFB /* Push To-Do.app */; 117 | productType = "com.apple.product-type.application"; 118 | }; 119 | /* End PBXNativeTarget section */ 120 | 121 | /* Begin PBXProject section */ 122 | BA19307929F4847F009EBFFB /* Project object */ = { 123 | isa = PBXProject; 124 | attributes = { 125 | BuildIndependentTargetsInParallel = 1; 126 | LastSwiftUpdateCheck = 1430; 127 | LastUpgradeCheck = 1430; 128 | TargetAttributes = { 129 | BA19308029F4847F009EBFFB = { 130 | CreatedOnToolsVersion = 14.3; 131 | }; 132 | }; 133 | }; 134 | buildConfigurationList = BA19307C29F4847F009EBFFB /* Build configuration list for PBXProject "Push To-Do" */; 135 | compatibilityVersion = "Xcode 14.0"; 136 | developmentRegion = en; 137 | hasScannedForEncodings = 0; 138 | knownRegions = ( 139 | en, 140 | Base, 141 | ); 142 | mainGroup = BA19307829F4847F009EBFFB; 143 | packageReferences = ( 144 | BA19309B29F48695009EBFFB /* XCRemoteSwiftPackageReference "Alamofire" */, 145 | BA19309E29F486A2009EBFFB /* XCRemoteSwiftPackageReference "NotionSwift" */, 146 | ); 147 | productRefGroup = BA19308229F4847F009EBFFB /* Products */; 148 | projectDirPath = ""; 149 | projectRoot = ""; 150 | targets = ( 151 | BA19308029F4847F009EBFFB /* Push To-Do */, 152 | ); 153 | }; 154 | /* End PBXProject section */ 155 | 156 | /* Begin PBXResourcesBuildPhase section */ 157 | BA19307F29F4847F009EBFFB /* Resources */ = { 158 | isa = PBXResourcesBuildPhase; 159 | buildActionMask = 2147483647; 160 | files = ( 161 | BA19308C29F48480009EBFFB /* Preview Assets.xcassets in Resources */, 162 | BAEA506A29F5ECB1000669E9 /* Settings.bundle in Resources */, 163 | BA19308929F48480009EBFFB /* Assets.xcassets in Resources */, 164 | ); 165 | runOnlyForDeploymentPostprocessing = 0; 166 | }; 167 | /* End PBXResourcesBuildPhase section */ 168 | 169 | /* Begin PBXSourcesBuildPhase section */ 170 | BA19307D29F4847F009EBFFB /* Sources */ = { 171 | isa = PBXSourcesBuildPhase; 172 | buildActionMask = 2147483647; 173 | files = ( 174 | BA19309A29F4857A009EBFFB /* AudioRecorder.swift .swift in Sources */, 175 | BA19309829F48572009EBFFB /* WhisperNotionManager.swift .swift in Sources */, 176 | BA19308729F4847F009EBFFB /* ContentView.swift in Sources */, 177 | BA19308529F4847F009EBFFB /* Push_To_DoApp.swift in Sources */, 178 | ); 179 | runOnlyForDeploymentPostprocessing = 0; 180 | }; 181 | /* End PBXSourcesBuildPhase section */ 182 | 183 | /* Begin XCBuildConfiguration section */ 184 | BA19308D29F48480009EBFFB /* Debug */ = { 185 | isa = XCBuildConfiguration; 186 | buildSettings = { 187 | ALWAYS_SEARCH_USER_PATHS = NO; 188 | CLANG_ANALYZER_NONNULL = YES; 189 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 190 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 191 | CLANG_ENABLE_MODULES = YES; 192 | CLANG_ENABLE_OBJC_ARC = YES; 193 | CLANG_ENABLE_OBJC_WEAK = YES; 194 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 195 | CLANG_WARN_BOOL_CONVERSION = YES; 196 | CLANG_WARN_COMMA = YES; 197 | CLANG_WARN_CONSTANT_CONVERSION = YES; 198 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 199 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 200 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 201 | CLANG_WARN_EMPTY_BODY = YES; 202 | CLANG_WARN_ENUM_CONVERSION = YES; 203 | CLANG_WARN_INFINITE_RECURSION = YES; 204 | CLANG_WARN_INT_CONVERSION = YES; 205 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 206 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 207 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 208 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 209 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 210 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 211 | CLANG_WARN_STRICT_PROTOTYPES = YES; 212 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 213 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 214 | CLANG_WARN_UNREACHABLE_CODE = YES; 215 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 216 | COPY_PHASE_STRIP = NO; 217 | DEBUG_INFORMATION_FORMAT = dwarf; 218 | ENABLE_STRICT_OBJC_MSGSEND = YES; 219 | ENABLE_TESTABILITY = YES; 220 | GCC_C_LANGUAGE_STANDARD = gnu11; 221 | GCC_DYNAMIC_NO_PIC = NO; 222 | GCC_NO_COMMON_BLOCKS = YES; 223 | GCC_OPTIMIZATION_LEVEL = 0; 224 | GCC_PREPROCESSOR_DEFINITIONS = ( 225 | "DEBUG=1", 226 | "$(inherited)", 227 | ); 228 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 229 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 230 | GCC_WARN_UNDECLARED_SELECTOR = YES; 231 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 232 | GCC_WARN_UNUSED_FUNCTION = YES; 233 | GCC_WARN_UNUSED_VARIABLE = YES; 234 | IPHONEOS_DEPLOYMENT_TARGET = 16.0; 235 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 236 | MTL_FAST_MATH = YES; 237 | ONLY_ACTIVE_ARCH = YES; 238 | SDKROOT = iphoneos; 239 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 240 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 241 | }; 242 | name = Debug; 243 | }; 244 | BA19308E29F48480009EBFFB /* Release */ = { 245 | isa = XCBuildConfiguration; 246 | buildSettings = { 247 | ALWAYS_SEARCH_USER_PATHS = NO; 248 | CLANG_ANALYZER_NONNULL = YES; 249 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 250 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 251 | CLANG_ENABLE_MODULES = YES; 252 | CLANG_ENABLE_OBJC_ARC = YES; 253 | CLANG_ENABLE_OBJC_WEAK = YES; 254 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 255 | CLANG_WARN_BOOL_CONVERSION = YES; 256 | CLANG_WARN_COMMA = YES; 257 | CLANG_WARN_CONSTANT_CONVERSION = YES; 258 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 259 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 260 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 261 | CLANG_WARN_EMPTY_BODY = YES; 262 | CLANG_WARN_ENUM_CONVERSION = YES; 263 | CLANG_WARN_INFINITE_RECURSION = YES; 264 | CLANG_WARN_INT_CONVERSION = YES; 265 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 266 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 267 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 268 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 269 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 270 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 271 | CLANG_WARN_STRICT_PROTOTYPES = YES; 272 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 273 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 274 | CLANG_WARN_UNREACHABLE_CODE = YES; 275 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 276 | COPY_PHASE_STRIP = NO; 277 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 278 | ENABLE_NS_ASSERTIONS = NO; 279 | ENABLE_STRICT_OBJC_MSGSEND = YES; 280 | GCC_C_LANGUAGE_STANDARD = gnu11; 281 | GCC_NO_COMMON_BLOCKS = YES; 282 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 283 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 284 | GCC_WARN_UNDECLARED_SELECTOR = YES; 285 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 286 | GCC_WARN_UNUSED_FUNCTION = YES; 287 | GCC_WARN_UNUSED_VARIABLE = YES; 288 | IPHONEOS_DEPLOYMENT_TARGET = 16.0; 289 | MTL_ENABLE_DEBUG_INFO = NO; 290 | MTL_FAST_MATH = YES; 291 | SDKROOT = iphoneos; 292 | SWIFT_COMPILATION_MODE = wholemodule; 293 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 294 | VALIDATE_PRODUCT = YES; 295 | }; 296 | name = Release; 297 | }; 298 | BA19309029F48480009EBFFB /* Debug */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 302 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 303 | ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; 304 | CODE_SIGN_STYLE = Automatic; 305 | CURRENT_PROJECT_VERSION = 1; 306 | DEVELOPMENT_ASSET_PATHS = "\"Push To-Do/Preview Content\""; 307 | DEVELOPMENT_TEAM = T923YGVK3Z; 308 | ENABLE_PREVIEWS = YES; 309 | GENERATE_INFOPLIST_FILE = YES; 310 | INFOPLIST_KEY_CFBundleDisplayName = "Push To-Do"; 311 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; 312 | INFOPLIST_KEY_NSMicrophoneUsageDescription = "To record and push to-dos"; 313 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 314 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 315 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 316 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 317 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 318 | LD_RUNPATH_SEARCH_PATHS = ( 319 | "$(inherited)", 320 | "@executable_path/Frameworks", 321 | ); 322 | MARKETING_VERSION = 1.0; 323 | PRODUCT_BUNDLE_IDENTIFIER = "sahillavingia.Push-To-Do-App"; 324 | PRODUCT_NAME = "$(TARGET_NAME)"; 325 | SWIFT_EMIT_LOC_STRINGS = YES; 326 | SWIFT_VERSION = 5.0; 327 | TARGETED_DEVICE_FAMILY = "1,2"; 328 | }; 329 | name = Debug; 330 | }; 331 | BA19309129F48480009EBFFB /* Release */ = { 332 | isa = XCBuildConfiguration; 333 | buildSettings = { 334 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 335 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 336 | ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; 337 | CODE_SIGN_STYLE = Automatic; 338 | CURRENT_PROJECT_VERSION = 1; 339 | DEVELOPMENT_ASSET_PATHS = "\"Push To-Do/Preview Content\""; 340 | DEVELOPMENT_TEAM = T923YGVK3Z; 341 | ENABLE_PREVIEWS = YES; 342 | GENERATE_INFOPLIST_FILE = YES; 343 | INFOPLIST_KEY_CFBundleDisplayName = "Push To-Do"; 344 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; 345 | INFOPLIST_KEY_NSMicrophoneUsageDescription = "To record and push to-dos"; 346 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 347 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 348 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 349 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 350 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 351 | LD_RUNPATH_SEARCH_PATHS = ( 352 | "$(inherited)", 353 | "@executable_path/Frameworks", 354 | ); 355 | MARKETING_VERSION = 1.0; 356 | PRODUCT_BUNDLE_IDENTIFIER = "sahillavingia.Push-To-Do-App"; 357 | PRODUCT_NAME = "$(TARGET_NAME)"; 358 | SWIFT_EMIT_LOC_STRINGS = YES; 359 | SWIFT_VERSION = 5.0; 360 | TARGETED_DEVICE_FAMILY = "1,2"; 361 | }; 362 | name = Release; 363 | }; 364 | /* End XCBuildConfiguration section */ 365 | 366 | /* Begin XCConfigurationList section */ 367 | BA19307C29F4847F009EBFFB /* Build configuration list for PBXProject "Push To-Do" */ = { 368 | isa = XCConfigurationList; 369 | buildConfigurations = ( 370 | BA19308D29F48480009EBFFB /* Debug */, 371 | BA19308E29F48480009EBFFB /* Release */, 372 | ); 373 | defaultConfigurationIsVisible = 0; 374 | defaultConfigurationName = Release; 375 | }; 376 | BA19308F29F48480009EBFFB /* Build configuration list for PBXNativeTarget "Push To-Do" */ = { 377 | isa = XCConfigurationList; 378 | buildConfigurations = ( 379 | BA19309029F48480009EBFFB /* Debug */, 380 | BA19309129F48480009EBFFB /* Release */, 381 | ); 382 | defaultConfigurationIsVisible = 0; 383 | defaultConfigurationName = Release; 384 | }; 385 | /* End XCConfigurationList section */ 386 | 387 | /* Begin XCRemoteSwiftPackageReference section */ 388 | BA19309B29F48695009EBFFB /* XCRemoteSwiftPackageReference "Alamofire" */ = { 389 | isa = XCRemoteSwiftPackageReference; 390 | repositoryURL = "https://github.com/Alamofire/Alamofire.git"; 391 | requirement = { 392 | kind = upToNextMajorVersion; 393 | minimumVersion = 5.0.0; 394 | }; 395 | }; 396 | BA19309E29F486A2009EBFFB /* XCRemoteSwiftPackageReference "NotionSwift" */ = { 397 | isa = XCRemoteSwiftPackageReference; 398 | repositoryURL = "https://github.com/chojnac/NotionSwift"; 399 | requirement = { 400 | kind = upToNextMajorVersion; 401 | minimumVersion = 0.8.0; 402 | }; 403 | }; 404 | /* End XCRemoteSwiftPackageReference section */ 405 | 406 | /* Begin XCSwiftPackageProductDependency section */ 407 | BA19309C29F48695009EBFFB /* Alamofire */ = { 408 | isa = XCSwiftPackageProductDependency; 409 | package = BA19309B29F48695009EBFFB /* XCRemoteSwiftPackageReference "Alamofire" */; 410 | productName = Alamofire; 411 | }; 412 | BA19309F29F486A2009EBFFB /* NotionSwift */ = { 413 | isa = XCSwiftPackageProductDependency; 414 | package = BA19309E29F486A2009EBFFB /* XCRemoteSwiftPackageReference "NotionSwift" */; 415 | productName = NotionSwift; 416 | }; 417 | /* End XCSwiftPackageProductDependency section */ 418 | }; 419 | rootObject = BA19307929F4847F009EBFFB /* Project object */; 420 | } 421 | -------------------------------------------------------------------------------- /Push To-Do.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Push To-Do.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Push To-Do.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "alamofire", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/Alamofire/Alamofire.git", 7 | "state" : { 8 | "revision" : "78424be314842833c04bc3bef5b72e85fff99204", 9 | "version" : "5.6.4" 10 | } 11 | }, 12 | { 13 | "identity" : "notionswift", 14 | "kind" : "remoteSourceControl", 15 | "location" : "https://github.com/chojnac/NotionSwift", 16 | "state" : { 17 | "revision" : "56c0c3a0dca35583aab0ef26fe2694e4c303bb72", 18 | "version" : "0.8.0" 19 | } 20 | } 21 | ], 22 | "version" : 2 23 | } 24 | -------------------------------------------------------------------------------- /Push To-Do.xcodeproj/xcuserdata/sahil.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Push To-Do.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Push To-Do/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "platform" : "universal", 6 | "reference" : "labelColor" 7 | }, 8 | "idiom" : "universal" 9 | } 10 | ], 11 | "info" : { 12 | "author" : "xcode", 13 | "version" : 1 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Push To-Do/Assets.xcassets/AppIcon.appiconset/App_store_1024_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slavingia/push-to-do/b6609b20ae980e77868ecd84358a1a101a5c1498/Push To-Do/Assets.xcassets/AppIcon.appiconset/App_store_1024_1x.png -------------------------------------------------------------------------------- /Push To-Do/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "iPhone_Notifications_20_2x.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "scale" : "2x", 8 | "size" : "20x20" 9 | }, 10 | { 11 | "filename" : "iPhone_Notifications_20_3x.png", 12 | "idiom" : "universal", 13 | "platform" : "ios", 14 | "scale" : "3x", 15 | "size" : "20x20" 16 | }, 17 | { 18 | "idiom" : "universal", 19 | "platform" : "ios", 20 | "scale" : "2x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "universal", 25 | "platform" : "ios", 26 | "scale" : "3x", 27 | "size" : "29x29" 28 | }, 29 | { 30 | "idiom" : "universal", 31 | "platform" : "ios", 32 | "scale" : "2x", 33 | "size" : "38x38" 34 | }, 35 | { 36 | "idiom" : "universal", 37 | "platform" : "ios", 38 | "scale" : "3x", 39 | "size" : "38x38" 40 | }, 41 | { 42 | "idiom" : "universal", 43 | "platform" : "ios", 44 | "scale" : "2x", 45 | "size" : "40x40" 46 | }, 47 | { 48 | "idiom" : "universal", 49 | "platform" : "ios", 50 | "scale" : "3x", 51 | "size" : "40x40" 52 | }, 53 | { 54 | "idiom" : "universal", 55 | "platform" : "ios", 56 | "scale" : "2x", 57 | "size" : "60x60" 58 | }, 59 | { 60 | "idiom" : "universal", 61 | "platform" : "ios", 62 | "scale" : "3x", 63 | "size" : "60x60" 64 | }, 65 | { 66 | "idiom" : "universal", 67 | "platform" : "ios", 68 | "scale" : "2x", 69 | "size" : "64x64" 70 | }, 71 | { 72 | "idiom" : "universal", 73 | "platform" : "ios", 74 | "scale" : "3x", 75 | "size" : "64x64" 76 | }, 77 | { 78 | "idiom" : "universal", 79 | "platform" : "ios", 80 | "scale" : "2x", 81 | "size" : "68x68" 82 | }, 83 | { 84 | "idiom" : "universal", 85 | "platform" : "ios", 86 | "scale" : "2x", 87 | "size" : "76x76" 88 | }, 89 | { 90 | "idiom" : "universal", 91 | "platform" : "ios", 92 | "scale" : "2x", 93 | "size" : "83.5x83.5" 94 | }, 95 | { 96 | "filename" : "App_store_1024_1x.png", 97 | "idiom" : "universal", 98 | "platform" : "ios", 99 | "size" : "1024x1024" 100 | } 101 | ], 102 | "info" : { 103 | "author" : "xcode", 104 | "version" : 1 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Push To-Do/Assets.xcassets/AppIcon.appiconset/iPhone_Notifications_20_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slavingia/push-to-do/b6609b20ae980e77868ecd84358a1a101a5c1498/Push To-Do/Assets.xcassets/AppIcon.appiconset/iPhone_Notifications_20_2x.png -------------------------------------------------------------------------------- /Push To-Do/Assets.xcassets/AppIcon.appiconset/iPhone_Notifications_20_3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slavingia/push-to-do/b6609b20ae980e77868ecd84358a1a101a5c1498/Push To-Do/Assets.xcassets/AppIcon.appiconset/iPhone_Notifications_20_3x.png -------------------------------------------------------------------------------- /Push To-Do/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Push To-Do/AudioRecorder.swift .swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import AVFoundation 3 | 4 | class AudioRecorder: NSObject, ObservableObject, AVAudioRecorderDelegate { 5 | @Published var audioRecorder: AVAudioRecorder? 6 | var audioSession: AVAudioSession! 7 | var audioFileURL: URL? 8 | 9 | override init() { 10 | super.init() 11 | audioSession = AVAudioSession.sharedInstance() 12 | setupAudioRecorder() 13 | } 14 | 15 | func setupAudioRecorder() { 16 | do { 17 | // Set up the audio session category, mode, and activation 18 | try audioSession.setCategory(.record, mode: .default) 19 | try audioSession.setActive(true) 20 | 21 | let audioFilename = getDocumentsDirectory().appendingPathComponent("recording.m4a") 22 | 23 | let settings = [ 24 | AVFormatIDKey: Int(kAudioFormatMPEG4AAC), 25 | AVSampleRateKey: 12000, 26 | AVNumberOfChannelsKey: 1, 27 | AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue 28 | ] 29 | 30 | audioRecorder = try AVAudioRecorder(url: audioFilename, settings: settings) 31 | audioRecorder?.delegate = self 32 | audioRecorder?.record() 33 | audioFileURL = audioFilename 34 | } catch { 35 | // Handle error 36 | print("Failed to set up audio recorder: \(error)") 37 | } 38 | } 39 | 40 | func startRecording() { 41 | audioRecorder?.record() 42 | } 43 | 44 | func stopRecording() { 45 | audioRecorder?.stop() 46 | } 47 | 48 | func getDocumentsDirectory() -> URL { 49 | let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) 50 | return paths[0] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Push To-Do/ContentView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import AVFoundation 3 | import Alamofire 4 | import NotionSwift 5 | 6 | struct ContentView: View { 7 | @EnvironmentObject var audioRecorder: AudioRecorder 8 | @EnvironmentObject var whisperNotionManager: WhisperNotionManager 9 | @State private var isRecording = false 10 | 11 | var body: some View { 12 | VStack { 13 | Button(action: { 14 | if isRecording { 15 | audioRecorder.stopRecording() 16 | isRecording = false 17 | 18 | if let audioUrl = audioRecorder.audioFileURL { 19 | print(audioUrl) 20 | whisperNotionManager.transcribeAudio(audioUrl: audioUrl) { transcript in 21 | if let transcript = transcript { 22 | whisperNotionManager.addToNotion(text: transcript) 23 | } 24 | } 25 | } 26 | } else { 27 | // Start a new recording session and reset the state 28 | audioRecorder.startRecording() 29 | isRecording = true 30 | } 31 | }) { 32 | Text(isRecording ? "Push to Notion" : "Record to-do") 33 | .font(.title2) 34 | .padding() 35 | .background(Color.black) 36 | .foregroundColor(.white) 37 | .cornerRadius(10) 38 | } 39 | .padding() 40 | } 41 | .onAppear(perform: { 42 | audioRecorder.startRecording() 43 | isRecording = true 44 | }) 45 | } 46 | } 47 | 48 | struct ContentView_Previews: PreviewProvider { 49 | static var previews: some View { 50 | ContentView() 51 | .environmentObject(AudioRecorder()) 52 | .environmentObject(WhisperNotionManager()) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Push To-Do/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Push To-Do/Push_To_DoApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Push_To_DoApp.swift 3 | // Push To-Do 4 | // 5 | // Created by Sahil Lavingia on 4/22/23. 6 | // 7 | 8 | import SwiftUI 9 | import AVFoundation 10 | import Alamofire 11 | import NotionSwift 12 | import UIKit 13 | 14 | 15 | @main 16 | struct Push_To_DoApp: App { 17 | @StateObject private var audioRecorder = AudioRecorder() 18 | @StateObject private var whisperNotionManager = WhisperNotionManager() 19 | @State private var showSettingsAlert = false 20 | 21 | var body: some Scene { 22 | WindowGroup { 23 | ContentView() 24 | .environmentObject(audioRecorder) 25 | .environmentObject(whisperNotionManager) 26 | .alert(isPresented: $showSettingsAlert) { 27 | Alert( 28 | title: Text("Configuration Required"), 29 | message: Text("Please set the pageId and databaseId in the Settings app."), 30 | primaryButton: .default(Text("Go to Settings"), action: redirectToSettingsApp), 31 | secondaryButton: .cancel() 32 | ) 33 | } 34 | .onAppear(perform: checkConfig) 35 | } 36 | } 37 | 38 | func getInternalIntegrationToken() -> String? { 39 | return UserDefaults.standard.string(forKey: "internalIntegrationToken") 40 | } 41 | 42 | func getAddToDatabase() -> Bool { 43 | return UserDefaults.standard.bool(forKey: "addToDatabase") 44 | } 45 | 46 | func getPageId() -> String? { 47 | return UserDefaults.standard.string(forKey: "pageId") 48 | } 49 | 50 | func getDatabaseId() -> String? { 51 | return UserDefaults.standard.string(forKey: "databaseId") 52 | } 53 | 54 | func checkConfig() { 55 | if getPageId() == nil && !getAddToDatabase() || 56 | getDatabaseId() == nil && getAddToDatabase() || 57 | getInternalIntegrationToken() == nil { 58 | showSettingsAlert = true 59 | } 60 | } 61 | 62 | func redirectToSettingsApp() { 63 | if let settingsUrl = URL(string: UIApplication.openSettingsURLString) { 64 | if UIApplication.shared.canOpenURL(settingsUrl) { 65 | UIApplication.shared.open(settingsUrl, options: [:], completionHandler: nil) 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Push To-Do/Settings.bundle/Root.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | StringsTable 6 | Root 7 | PreferenceSpecifiers 8 | 9 | 10 | Type 11 | PSTextFieldSpecifier 12 | Title 13 | Internal Integration Token 14 | Key 15 | internalIntegrationToken 16 | 17 | 18 | Type 19 | PSTextFieldSpecifier 20 | Title 21 | Page ID 22 | Key 23 | pageId 24 | 25 | 26 | Type 27 | PSTextFieldSpecifier 28 | Title 29 | Database ID 30 | Key 31 | databaseId 32 | 33 | 34 | Type 35 | PSToggleSwitchSpecifier 36 | Title 37 | Add to database 38 | Key 39 | addToDatabase 40 | DefaultValue 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Push To-Do/Settings.bundle/en.lproj/Root.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slavingia/push-to-do/b6609b20ae980e77868ecd84358a1a101a5c1498/Push To-Do/Settings.bundle/en.lproj/Root.strings -------------------------------------------------------------------------------- /Push To-Do/WhisperNotionManager.swift .swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import Alamofire 3 | import NotionSwift 4 | 5 | class WhisperNotionManager: ObservableObject { 6 | @Published var notionClient: NotionClient? 7 | 8 | init() { 9 | do { 10 | if let internalIntegrationToken = getInternalIntegrationToken() { 11 | print(internalIntegrationToken) 12 | let notion = NotionClient(accessKeyProvider: StringAccessKeyProvider(accessKey: internalIntegrationToken)) 13 | notionClient = notion 14 | } else { 15 | notionClient = nil 16 | throw NSError(domain: "NotionClientInitializationError", code: 1, userInfo: [NSLocalizedDescriptionKey: "Internal Integration Token is missing"]) 17 | } 18 | } catch { 19 | print("Error initializing NotionClient: \(error.localizedDescription)") 20 | // You can choose to do nothing here if you want to handle the error silently 21 | } 22 | } 23 | 24 | func transcribeAudio(audioUrl: URL, completion: @escaping (String?) -> Void) { 25 | let openAIUrl = "https://api.openai.com/v1/audio/transcriptions" 26 | let apiKey = "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" 27 | let headers: HTTPHeaders = [ 28 | "Authorization": "Bearer \(apiKey)", 29 | "Content-Type": "multipart/form-data" 30 | ] 31 | 32 | AF.upload(multipartFormData: { multipartFormData in 33 | multipartFormData.append(audioUrl, withName: "file") 34 | multipartFormData.append("whisper-1".data(using: .utf8)!, withName: "model") 35 | }, to: openAIUrl, headers: headers) 36 | .responseDecodable(of: WhisperResponse.self) { response in 37 | switch response.result { 38 | case .success(let whisperResponse): 39 | print(whisperResponse.text!) 40 | completion(whisperResponse.text) 41 | case .failure(let error): 42 | print("Error decoding response: \(error)") 43 | completion(nil) 44 | } 45 | } 46 | } 47 | 48 | func addToNotion(text: String) { 49 | var trimmedText = text 50 | let periodCharacterSet = CharacterSet(charactersIn: ".") 51 | trimmedText = trimmedText.trimmingCharacters(in: periodCharacterSet) 52 | 53 | if (UserDefaults.standard.bool(forKey: "addToDatabase")) { 54 | let databaseId = Database.Identifier(getDatabaseId()!) 55 | 56 | let request = PageCreateRequest( 57 | parent: .database(databaseId), 58 | properties: [ 59 | "title": .init( 60 | type: .title([ 61 | .init(string: trimmedText) 62 | ]) 63 | ) 64 | ] 65 | ) 66 | 67 | notionClient!.pageCreate(request: request) { 68 | print($0) 69 | } 70 | } else { 71 | // ebd556b1-c267-401c-817a-aa0efe8eb6c7 72 | let pageId = Block.Identifier(getPageId()!) 73 | let blocks: [WriteBlock] = [ 74 | .toDo([RichText(string: trimmedText)]) 75 | ] 76 | notionClient!.blockAppend(blockId: pageId, children: blocks) { 77 | print($0) 78 | } 79 | } 80 | } 81 | } 82 | 83 | func getInternalIntegrationToken() -> String? { 84 | return UserDefaults.standard.string(forKey: "internalIntegrationToken") 85 | } 86 | 87 | func getPageId() -> String? { 88 | return UserDefaults.standard.string(forKey: "pageId") 89 | } 90 | 91 | func getDatabaseId() -> String? { 92 | return UserDefaults.standard.string(forKey: "databaseId") 93 | } 94 | 95 | struct WhisperResponse: Decodable { 96 | let text: String? 97 | } 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Built in a few hours with ChatGPT. Chat logs available on Gumroad: https://sahil.gumroad.com/l/ios-with-chatgpt 2 | 3 | 4 | # Push To-Do 5 | 6 | The fastest, simplest way to add to-dos to Notion. 7 | 8 | ### How to use 9 | 10 | Upon opening, Push To-Do will be recording. Tap the button once you are finished talking to create a new to-do. 11 | 12 | ### How to setup 13 | 14 | 1. Create a Notion integration: https://developers.notion.com/docs/create-a-notion-integration 15 | 16 | 2. Download this repo to your PC. 17 | 18 | 3. Add the app to your device with Xcode. 19 | 20 | 4. Replace `apiKey` in WhisperNotionManager.swift with your OpenAI API key. 21 | 22 | 5. Within the app settings within Settings.app, add: 23 | 24 | - The internal integration token from the integration above 25 | - The page ID if you want to add a to-do to a page 26 | - The database ID if you want to add a page to a database 27 | 28 | Options: 29 | 30 | - Enable "Add to database" if you prefer new pages instead of new to-dos. 31 | --------------------------------------------------------------------------------