├── .gitignore ├── AutoVolume.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── AutoVolume ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ └── Main.storyboard ├── Info.plist ├── Notifications.swift ├── ViewController.swift └── Volume.swift ├── AutoVolumeHelper ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ └── MainMenu.xib ├── Info.plist └── main.m ├── AutoVolumeHelperTests ├── AutoVolumeHelperTests.m └── Info.plist ├── AutoVolumeTests ├── Info.plist └── Tests.swift ├── AutoVolumeUITests ├── Info.plist └── UITests.swift ├── CONTRIBUTING.md ├── LICENSE ├── README.md └── website ├── humans.txt ├── index.html ├── resources ├── css │ ├── main.css │ └── main.css.map ├── images │ ├── Screenshot.png │ ├── Screenshot@2x.png │ └── avoid-this-happening.gif └── scss │ └── main.scss └── robots.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/xcode,macos 2 | 3 | ### Xcode ### 4 | # Xcode 5 | # 6 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 7 | 8 | ## Build generated 9 | build/ 10 | DerivedData/ 11 | 12 | ## Various settings 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata/ 22 | 23 | ## Other 24 | *.moved-aside 25 | *.xccheckout 26 | *.xcscmblueprint 27 | 28 | 29 | ### macOS ### 30 | *.DS_Store 31 | .AppleDouble 32 | .LSOverride 33 | 34 | # Icon must end with two \r 35 | Icon 36 | # Thumbnails 37 | ._* 38 | # Files that might appear in the root of a volume 39 | .DocumentRevisions-V100 40 | .fseventsd 41 | .Spotlight-V100 42 | .TemporaryItems 43 | .Trashes 44 | .VolumeIcon.icns 45 | .com.apple.timemachine.donotpresent 46 | # Directories potentially created on remote AFP share 47 | .AppleDB 48 | .AppleDesktop 49 | Network Trash Folder 50 | Temporary Items 51 | .apdisk 52 | 53 | # End of https://www.gitignore.io/api/xcode,macos 54 | -------------------------------------------------------------------------------- /AutoVolume.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 884EBE891E14842C007DE6F4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 884EBE881E14842C007DE6F4 /* AppDelegate.m */; }; 11 | 884EBE8C1E14842C007DE6F4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 884EBE8B1E14842C007DE6F4 /* main.m */; }; 12 | 884EBE8E1E14842C007DE6F4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 884EBE8D1E14842C007DE6F4 /* Assets.xcassets */; }; 13 | 884EBE911E14842C007DE6F4 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 884EBE8F1E14842C007DE6F4 /* MainMenu.xib */; }; 14 | 884EBE9C1E14842C007DE6F4 /* AutoVolumeHelperTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 884EBE9B1E14842C007DE6F4 /* AutoVolumeHelperTests.m */; }; 15 | 8857E51A1E107A3200837A87 /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8857E5191E107A3100837A87 /* Notifications.swift */; }; 16 | 886F9D041E05F14700F8A083 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886F9D031E05F14700F8A083 /* AppDelegate.swift */; }; 17 | 886F9D061E05F14700F8A083 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886F9D051E05F14700F8A083 /* ViewController.swift */; }; 18 | 886F9D081E05F14700F8A083 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 886F9D071E05F14700F8A083 /* Assets.xcassets */; }; 19 | 886F9D0B1E05F14700F8A083 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 886F9D091E05F14700F8A083 /* Main.storyboard */; }; 20 | 886F9D161E05F14700F8A083 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886F9D151E05F14700F8A083 /* Tests.swift */; }; 21 | 886F9D211E05F14700F8A083 /* UITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886F9D201E05F14700F8A083 /* UITests.swift */; }; 22 | 886F9D2F1E05F1C800F8A083 /* README.md in Sources */ = {isa = PBXBuildFile; fileRef = 886F9D2E1E05F1C800F8A083 /* README.md */; }; 23 | 886F9D311E05F1DF00F8A083 /* Volume.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886F9D301E05F1DF00F8A083 /* Volume.swift */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXContainerItemProxy section */ 27 | 884EBE981E14842C007DE6F4 /* PBXContainerItemProxy */ = { 28 | isa = PBXContainerItemProxy; 29 | containerPortal = 886F9CF81E05F14700F8A083 /* Project object */; 30 | proxyType = 1; 31 | remoteGlobalIDString = 884EBE841E14842C007DE6F4; 32 | remoteInfo = AutoVolumeHelper; 33 | }; 34 | 886F9D121E05F14700F8A083 /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = 886F9CF81E05F14700F8A083 /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = 886F9CFF1E05F14700F8A083; 39 | remoteInfo = AutoVolume; 40 | }; 41 | 886F9D1D1E05F14700F8A083 /* PBXContainerItemProxy */ = { 42 | isa = PBXContainerItemProxy; 43 | containerPortal = 886F9CF81E05F14700F8A083 /* Project object */; 44 | proxyType = 1; 45 | remoteGlobalIDString = 886F9CFF1E05F14700F8A083; 46 | remoteInfo = AutoVolume; 47 | }; 48 | /* End PBXContainerItemProxy section */ 49 | 50 | /* Begin PBXCopyFilesBuildPhase section */ 51 | 884EBEA41E15C15C007DE6F4 /* CopyFiles */ = { 52 | isa = PBXCopyFilesBuildPhase; 53 | buildActionMask = 2147483647; 54 | dstPath = Contents/Library/LoginItems; 55 | dstSubfolderSpec = 1; 56 | files = ( 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | /* End PBXCopyFilesBuildPhase section */ 61 | 62 | /* Begin PBXFileReference section */ 63 | 884EBE871E14842C007DE6F4 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 64 | 884EBE881E14842C007DE6F4 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 65 | 884EBE8B1E14842C007DE6F4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 66 | 884EBE8D1E14842C007DE6F4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 67 | 884EBE901E14842C007DE6F4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 68 | 884EBE921E14842C007DE6F4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 69 | 884EBE9B1E14842C007DE6F4 /* AutoVolumeHelperTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AutoVolumeHelperTests.m; sourceTree = ""; }; 70 | 884EBE9D1E14842C007DE6F4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 71 | 8857E5191E107A3100837A87 /* Notifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Notifications.swift; sourceTree = ""; }; 72 | 886F9D031E05F14700F8A083 /* AppDelegate.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; tabWidth = 2; }; 73 | 886F9D051E05F14700F8A083 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; tabWidth = 2; }; 74 | 886F9D071E05F14700F8A083 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 75 | 886F9D0A1E05F14700F8A083 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 76 | 886F9D0C1E05F14700F8A083 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 77 | 886F9D151E05F14700F8A083 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = ""; }; 78 | 886F9D171E05F14700F8A083 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 79 | 886F9D201E05F14700F8A083 /* UITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITests.swift; sourceTree = ""; }; 80 | 886F9D221E05F14700F8A083 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 81 | 886F9D2E1E05F1C800F8A083 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; 82 | 886F9D301E05F1DF00F8A083 /* Volume.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = Volume.swift; sourceTree = ""; tabWidth = 2; }; 83 | 889910B01E22FE2A00EFC0B4 /* AutoVolume.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutoVolume.app; sourceTree = BUILT_PRODUCTS_DIR; }; 84 | 889910B11E22FE2A00EFC0B4 /* AutoVolumeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AutoVolumeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 85 | 889910B21E22FE2A00EFC0B4 /* AutoVolumeUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AutoVolumeUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 86 | 889910B31E22FE2A00EFC0B4 /* AutoVolumeHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AutoVolumeHelper.app; sourceTree = BUILT_PRODUCTS_DIR; }; 87 | 889910B41E22FE2A00EFC0B4 /* AutoVolumeHelperTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AutoVolumeHelperTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 88 | /* End PBXFileReference section */ 89 | 90 | /* Begin PBXFrameworksBuildPhase section */ 91 | 884EBE821E14842C007DE6F4 /* Frameworks */ = { 92 | isa = PBXFrameworksBuildPhase; 93 | buildActionMask = 2147483647; 94 | files = ( 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | 884EBE941E14842C007DE6F4 /* Frameworks */ = { 99 | isa = PBXFrameworksBuildPhase; 100 | buildActionMask = 2147483647; 101 | files = ( 102 | ); 103 | runOnlyForDeploymentPostprocessing = 0; 104 | }; 105 | 886F9CFD1E05F14700F8A083 /* Frameworks */ = { 106 | isa = PBXFrameworksBuildPhase; 107 | buildActionMask = 2147483647; 108 | files = ( 109 | ); 110 | runOnlyForDeploymentPostprocessing = 0; 111 | }; 112 | 886F9D0E1E05F14700F8A083 /* Frameworks */ = { 113 | isa = PBXFrameworksBuildPhase; 114 | buildActionMask = 2147483647; 115 | files = ( 116 | ); 117 | runOnlyForDeploymentPostprocessing = 0; 118 | }; 119 | 886F9D191E05F14700F8A083 /* Frameworks */ = { 120 | isa = PBXFrameworksBuildPhase; 121 | buildActionMask = 2147483647; 122 | files = ( 123 | ); 124 | runOnlyForDeploymentPostprocessing = 0; 125 | }; 126 | /* End PBXFrameworksBuildPhase section */ 127 | 128 | /* Begin PBXGroup section */ 129 | 884EBE861E14842C007DE6F4 /* AutoVolumeHelper */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 884EBE871E14842C007DE6F4 /* AppDelegate.h */, 133 | 884EBE881E14842C007DE6F4 /* AppDelegate.m */, 134 | 884EBE8D1E14842C007DE6F4 /* Assets.xcassets */, 135 | 884EBE8F1E14842C007DE6F4 /* MainMenu.xib */, 136 | 884EBE921E14842C007DE6F4 /* Info.plist */, 137 | 884EBE8A1E14842C007DE6F4 /* Supporting Files */, 138 | ); 139 | path = AutoVolumeHelper; 140 | sourceTree = ""; 141 | }; 142 | 884EBE8A1E14842C007DE6F4 /* Supporting Files */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | 884EBE8B1E14842C007DE6F4 /* main.m */, 146 | ); 147 | name = "Supporting Files"; 148 | sourceTree = ""; 149 | }; 150 | 884EBE9A1E14842C007DE6F4 /* AutoVolumeHelperTests */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 884EBE9B1E14842C007DE6F4 /* AutoVolumeHelperTests.m */, 154 | 884EBE9D1E14842C007DE6F4 /* Info.plist */, 155 | ); 156 | path = AutoVolumeHelperTests; 157 | sourceTree = ""; 158 | }; 159 | 886F9CF71E05F14700F8A083 = { 160 | isa = PBXGroup; 161 | children = ( 162 | 886F9D021E05F14700F8A083 /* AutoVolume */, 163 | 886F9D141E05F14700F8A083 /* AutoVolumeTests */, 164 | 886F9D1F1E05F14700F8A083 /* AutoVolumeUITests */, 165 | 884EBE861E14842C007DE6F4 /* AutoVolumeHelper */, 166 | 884EBE9A1E14842C007DE6F4 /* AutoVolumeHelperTests */, 167 | 889910B51E22FE3A00EFC0B4 /* Products */, 168 | ); 169 | indentWidth = 2; 170 | sourceTree = ""; 171 | tabWidth = 2; 172 | }; 173 | 886F9D021E05F14700F8A083 /* AutoVolume */ = { 174 | isa = PBXGroup; 175 | children = ( 176 | 886F9D2E1E05F1C800F8A083 /* README.md */, 177 | 886F9D031E05F14700F8A083 /* AppDelegate.swift */, 178 | 886F9D051E05F14700F8A083 /* ViewController.swift */, 179 | 886F9D301E05F1DF00F8A083 /* Volume.swift */, 180 | 886F9D071E05F14700F8A083 /* Assets.xcassets */, 181 | 886F9D091E05F14700F8A083 /* Main.storyboard */, 182 | 886F9D0C1E05F14700F8A083 /* Info.plist */, 183 | 8857E5191E107A3100837A87 /* Notifications.swift */, 184 | ); 185 | path = AutoVolume; 186 | sourceTree = ""; 187 | }; 188 | 886F9D141E05F14700F8A083 /* AutoVolumeTests */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | 886F9D151E05F14700F8A083 /* Tests.swift */, 192 | 886F9D171E05F14700F8A083 /* Info.plist */, 193 | ); 194 | path = AutoVolumeTests; 195 | sourceTree = ""; 196 | }; 197 | 886F9D1F1E05F14700F8A083 /* AutoVolumeUITests */ = { 198 | isa = PBXGroup; 199 | children = ( 200 | 886F9D201E05F14700F8A083 /* UITests.swift */, 201 | 886F9D221E05F14700F8A083 /* Info.plist */, 202 | ); 203 | path = AutoVolumeUITests; 204 | sourceTree = ""; 205 | }; 206 | 889910B51E22FE3A00EFC0B4 /* Products */ = { 207 | isa = PBXGroup; 208 | children = ( 209 | 889910B01E22FE2A00EFC0B4 /* AutoVolume.app */, 210 | 889910B11E22FE2A00EFC0B4 /* AutoVolumeTests.xctest */, 211 | 889910B21E22FE2A00EFC0B4 /* AutoVolumeUITests.xctest */, 212 | 889910B31E22FE2A00EFC0B4 /* AutoVolumeHelper.app */, 213 | 889910B41E22FE2A00EFC0B4 /* AutoVolumeHelperTests.xctest */, 214 | ); 215 | name = Products; 216 | sourceTree = ""; 217 | }; 218 | /* End PBXGroup section */ 219 | 220 | /* Begin PBXNativeTarget section */ 221 | 884EBE841E14842C007DE6F4 /* AutoVolumeHelper */ = { 222 | isa = PBXNativeTarget; 223 | buildConfigurationList = 884EBEA21E14842C007DE6F4 /* Build configuration list for PBXNativeTarget "AutoVolumeHelper" */; 224 | buildPhases = ( 225 | 884EBE811E14842C007DE6F4 /* Sources */, 226 | 884EBE821E14842C007DE6F4 /* Frameworks */, 227 | 884EBE831E14842C007DE6F4 /* Resources */, 228 | ); 229 | buildRules = ( 230 | ); 231 | dependencies = ( 232 | ); 233 | name = AutoVolumeHelper; 234 | productName = AutoVolumeHelper; 235 | productReference = 889910B31E22FE2A00EFC0B4 /* AutoVolumeHelper.app */; 236 | productType = "com.apple.product-type.application"; 237 | }; 238 | 884EBE961E14842C007DE6F4 /* AutoVolumeHelperTests */ = { 239 | isa = PBXNativeTarget; 240 | buildConfigurationList = 884EBEA31E14842C007DE6F4 /* Build configuration list for PBXNativeTarget "AutoVolumeHelperTests" */; 241 | buildPhases = ( 242 | 884EBE931E14842C007DE6F4 /* Sources */, 243 | 884EBE941E14842C007DE6F4 /* Frameworks */, 244 | 884EBE951E14842C007DE6F4 /* Resources */, 245 | ); 246 | buildRules = ( 247 | ); 248 | dependencies = ( 249 | 884EBE991E14842C007DE6F4 /* PBXTargetDependency */, 250 | ); 251 | name = AutoVolumeHelperTests; 252 | productName = AutoVolumeHelperTests; 253 | productReference = 889910B41E22FE2A00EFC0B4 /* AutoVolumeHelperTests.xctest */; 254 | productType = "com.apple.product-type.bundle.unit-test"; 255 | }; 256 | 886F9CFF1E05F14700F8A083 /* AutoVolume */ = { 257 | isa = PBXNativeTarget; 258 | buildConfigurationList = 886F9D251E05F14700F8A083 /* Build configuration list for PBXNativeTarget "AutoVolume" */; 259 | buildPhases = ( 260 | 886F9CFC1E05F14700F8A083 /* Sources */, 261 | 886F9CFD1E05F14700F8A083 /* Frameworks */, 262 | 886F9CFE1E05F14700F8A083 /* Resources */, 263 | 884EBEA41E15C15C007DE6F4 /* CopyFiles */, 264 | ); 265 | buildRules = ( 266 | ); 267 | dependencies = ( 268 | ); 269 | name = AutoVolume; 270 | productName = AutoVolume; 271 | productReference = 889910B01E22FE2A00EFC0B4 /* AutoVolume.app */; 272 | productType = "com.apple.product-type.application"; 273 | }; 274 | 886F9D101E05F14700F8A083 /* AutoVolumeTests */ = { 275 | isa = PBXNativeTarget; 276 | buildConfigurationList = 886F9D281E05F14700F8A083 /* Build configuration list for PBXNativeTarget "AutoVolumeTests" */; 277 | buildPhases = ( 278 | 886F9D0D1E05F14700F8A083 /* Sources */, 279 | 886F9D0E1E05F14700F8A083 /* Frameworks */, 280 | 886F9D0F1E05F14700F8A083 /* Resources */, 281 | ); 282 | buildRules = ( 283 | ); 284 | dependencies = ( 285 | 886F9D131E05F14700F8A083 /* PBXTargetDependency */, 286 | ); 287 | name = AutoVolumeTests; 288 | productName = AutoVolumeTests; 289 | productReference = 889910B11E22FE2A00EFC0B4 /* AutoVolumeTests.xctest */; 290 | productType = "com.apple.product-type.bundle.unit-test"; 291 | }; 292 | 886F9D1B1E05F14700F8A083 /* AutoVolumeUITests */ = { 293 | isa = PBXNativeTarget; 294 | buildConfigurationList = 886F9D2B1E05F14700F8A083 /* Build configuration list for PBXNativeTarget "AutoVolumeUITests" */; 295 | buildPhases = ( 296 | 886F9D181E05F14700F8A083 /* Sources */, 297 | 886F9D191E05F14700F8A083 /* Frameworks */, 298 | 886F9D1A1E05F14700F8A083 /* Resources */, 299 | ); 300 | buildRules = ( 301 | ); 302 | dependencies = ( 303 | 886F9D1E1E05F14700F8A083 /* PBXTargetDependency */, 304 | ); 305 | name = AutoVolumeUITests; 306 | productName = AutoVolumeUITests; 307 | productReference = 889910B21E22FE2A00EFC0B4 /* AutoVolumeUITests.xctest */; 308 | productType = "com.apple.product-type.bundle.ui-testing"; 309 | }; 310 | /* End PBXNativeTarget section */ 311 | 312 | /* Begin PBXProject section */ 313 | 886F9CF81E05F14700F8A083 /* Project object */ = { 314 | isa = PBXProject; 315 | attributes = { 316 | LastSwiftUpdateCheck = 0820; 317 | LastUpgradeCheck = 0820; 318 | ORGANIZATIONNAME = "Jesse Claven"; 319 | TargetAttributes = { 320 | 884EBE841E14842C007DE6F4 = { 321 | CreatedOnToolsVersion = 8.2; 322 | DevelopmentTeam = SCM43BAGSW; 323 | ProvisioningStyle = Automatic; 324 | }; 325 | 884EBE961E14842C007DE6F4 = { 326 | CreatedOnToolsVersion = 8.2; 327 | DevelopmentTeam = SCM43BAGSW; 328 | ProvisioningStyle = Automatic; 329 | TestTargetID = 884EBE841E14842C007DE6F4; 330 | }; 331 | 886F9CFF1E05F14700F8A083 = { 332 | CreatedOnToolsVersion = 8.2; 333 | DevelopmentTeam = SCM43BAGSW; 334 | ProvisioningStyle = Automatic; 335 | }; 336 | 886F9D101E05F14700F8A083 = { 337 | CreatedOnToolsVersion = 8.2; 338 | DevelopmentTeam = SCM43BAGSW; 339 | ProvisioningStyle = Automatic; 340 | TestTargetID = 886F9CFF1E05F14700F8A083; 341 | }; 342 | 886F9D1B1E05F14700F8A083 = { 343 | CreatedOnToolsVersion = 8.2; 344 | DevelopmentTeam = SCM43BAGSW; 345 | ProvisioningStyle = Automatic; 346 | TestTargetID = 886F9CFF1E05F14700F8A083; 347 | }; 348 | }; 349 | }; 350 | buildConfigurationList = 886F9CFB1E05F14700F8A083 /* Build configuration list for PBXProject "AutoVolume" */; 351 | compatibilityVersion = "Xcode 3.2"; 352 | developmentRegion = English; 353 | hasScannedForEncodings = 0; 354 | knownRegions = ( 355 | en, 356 | Base, 357 | ); 358 | mainGroup = 886F9CF71E05F14700F8A083; 359 | productRefGroup = 886F9CF71E05F14700F8A083; 360 | projectDirPath = ""; 361 | projectRoot = ""; 362 | targets = ( 363 | 886F9CFF1E05F14700F8A083 /* AutoVolume */, 364 | 886F9D101E05F14700F8A083 /* AutoVolumeTests */, 365 | 886F9D1B1E05F14700F8A083 /* AutoVolumeUITests */, 366 | 884EBE841E14842C007DE6F4 /* AutoVolumeHelper */, 367 | 884EBE961E14842C007DE6F4 /* AutoVolumeHelperTests */, 368 | ); 369 | }; 370 | /* End PBXProject section */ 371 | 372 | /* Begin PBXResourcesBuildPhase section */ 373 | 884EBE831E14842C007DE6F4 /* Resources */ = { 374 | isa = PBXResourcesBuildPhase; 375 | buildActionMask = 2147483647; 376 | files = ( 377 | 884EBE8E1E14842C007DE6F4 /* Assets.xcassets in Resources */, 378 | 884EBE911E14842C007DE6F4 /* MainMenu.xib in Resources */, 379 | ); 380 | runOnlyForDeploymentPostprocessing = 0; 381 | }; 382 | 884EBE951E14842C007DE6F4 /* Resources */ = { 383 | isa = PBXResourcesBuildPhase; 384 | buildActionMask = 2147483647; 385 | files = ( 386 | ); 387 | runOnlyForDeploymentPostprocessing = 0; 388 | }; 389 | 886F9CFE1E05F14700F8A083 /* Resources */ = { 390 | isa = PBXResourcesBuildPhase; 391 | buildActionMask = 2147483647; 392 | files = ( 393 | 886F9D081E05F14700F8A083 /* Assets.xcassets in Resources */, 394 | 886F9D0B1E05F14700F8A083 /* Main.storyboard in Resources */, 395 | ); 396 | runOnlyForDeploymentPostprocessing = 0; 397 | }; 398 | 886F9D0F1E05F14700F8A083 /* Resources */ = { 399 | isa = PBXResourcesBuildPhase; 400 | buildActionMask = 2147483647; 401 | files = ( 402 | ); 403 | runOnlyForDeploymentPostprocessing = 0; 404 | }; 405 | 886F9D1A1E05F14700F8A083 /* Resources */ = { 406 | isa = PBXResourcesBuildPhase; 407 | buildActionMask = 2147483647; 408 | files = ( 409 | ); 410 | runOnlyForDeploymentPostprocessing = 0; 411 | }; 412 | /* End PBXResourcesBuildPhase section */ 413 | 414 | /* Begin PBXSourcesBuildPhase section */ 415 | 884EBE811E14842C007DE6F4 /* Sources */ = { 416 | isa = PBXSourcesBuildPhase; 417 | buildActionMask = 2147483647; 418 | files = ( 419 | 884EBE8C1E14842C007DE6F4 /* main.m in Sources */, 420 | 884EBE891E14842C007DE6F4 /* AppDelegate.m in Sources */, 421 | ); 422 | runOnlyForDeploymentPostprocessing = 0; 423 | }; 424 | 884EBE931E14842C007DE6F4 /* Sources */ = { 425 | isa = PBXSourcesBuildPhase; 426 | buildActionMask = 2147483647; 427 | files = ( 428 | 884EBE9C1E14842C007DE6F4 /* AutoVolumeHelperTests.m in Sources */, 429 | ); 430 | runOnlyForDeploymentPostprocessing = 0; 431 | }; 432 | 886F9CFC1E05F14700F8A083 /* Sources */ = { 433 | isa = PBXSourcesBuildPhase; 434 | buildActionMask = 2147483647; 435 | files = ( 436 | 8857E51A1E107A3200837A87 /* Notifications.swift in Sources */, 437 | 886F9D2F1E05F1C800F8A083 /* README.md in Sources */, 438 | 886F9D061E05F14700F8A083 /* ViewController.swift in Sources */, 439 | 886F9D041E05F14700F8A083 /* AppDelegate.swift in Sources */, 440 | 886F9D311E05F1DF00F8A083 /* Volume.swift in Sources */, 441 | ); 442 | runOnlyForDeploymentPostprocessing = 0; 443 | }; 444 | 886F9D0D1E05F14700F8A083 /* Sources */ = { 445 | isa = PBXSourcesBuildPhase; 446 | buildActionMask = 2147483647; 447 | files = ( 448 | 886F9D161E05F14700F8A083 /* Tests.swift in Sources */, 449 | ); 450 | runOnlyForDeploymentPostprocessing = 0; 451 | }; 452 | 886F9D181E05F14700F8A083 /* Sources */ = { 453 | isa = PBXSourcesBuildPhase; 454 | buildActionMask = 2147483647; 455 | files = ( 456 | 886F9D211E05F14700F8A083 /* UITests.swift in Sources */, 457 | ); 458 | runOnlyForDeploymentPostprocessing = 0; 459 | }; 460 | /* End PBXSourcesBuildPhase section */ 461 | 462 | /* Begin PBXTargetDependency section */ 463 | 884EBE991E14842C007DE6F4 /* PBXTargetDependency */ = { 464 | isa = PBXTargetDependency; 465 | target = 884EBE841E14842C007DE6F4 /* AutoVolumeHelper */; 466 | targetProxy = 884EBE981E14842C007DE6F4 /* PBXContainerItemProxy */; 467 | }; 468 | 886F9D131E05F14700F8A083 /* PBXTargetDependency */ = { 469 | isa = PBXTargetDependency; 470 | target = 886F9CFF1E05F14700F8A083 /* AutoVolume */; 471 | targetProxy = 886F9D121E05F14700F8A083 /* PBXContainerItemProxy */; 472 | }; 473 | 886F9D1E1E05F14700F8A083 /* PBXTargetDependency */ = { 474 | isa = PBXTargetDependency; 475 | target = 886F9CFF1E05F14700F8A083 /* AutoVolume */; 476 | targetProxy = 886F9D1D1E05F14700F8A083 /* PBXContainerItemProxy */; 477 | }; 478 | /* End PBXTargetDependency section */ 479 | 480 | /* Begin PBXVariantGroup section */ 481 | 884EBE8F1E14842C007DE6F4 /* MainMenu.xib */ = { 482 | isa = PBXVariantGroup; 483 | children = ( 484 | 884EBE901E14842C007DE6F4 /* Base */, 485 | ); 486 | name = MainMenu.xib; 487 | sourceTree = ""; 488 | }; 489 | 886F9D091E05F14700F8A083 /* Main.storyboard */ = { 490 | isa = PBXVariantGroup; 491 | children = ( 492 | 886F9D0A1E05F14700F8A083 /* Base */, 493 | ); 494 | name = Main.storyboard; 495 | sourceTree = ""; 496 | }; 497 | /* End PBXVariantGroup section */ 498 | 499 | /* Begin XCBuildConfiguration section */ 500 | 884EBE9E1E14842C007DE6F4 /* Debug */ = { 501 | isa = XCBuildConfiguration; 502 | buildSettings = { 503 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 504 | COMBINE_HIDPI_IMAGES = YES; 505 | DEVELOPMENT_TEAM = SCM43BAGSW; 506 | INFOPLIST_FILE = AutoVolumeHelper/Info.plist; 507 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 508 | PRODUCT_BUNDLE_IDENTIFIER = "jesse-c.AutoVolumeHelper"; 509 | PRODUCT_NAME = "$(TARGET_NAME)"; 510 | SKIP_INSTALL = YES; 511 | }; 512 | name = Debug; 513 | }; 514 | 884EBE9F1E14842C007DE6F4 /* Release */ = { 515 | isa = XCBuildConfiguration; 516 | buildSettings = { 517 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 518 | COMBINE_HIDPI_IMAGES = YES; 519 | DEVELOPMENT_TEAM = SCM43BAGSW; 520 | INFOPLIST_FILE = AutoVolumeHelper/Info.plist; 521 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 522 | PRODUCT_BUNDLE_IDENTIFIER = "jesse-c.AutoVolumeHelper"; 523 | PRODUCT_NAME = "$(TARGET_NAME)"; 524 | SKIP_INSTALL = YES; 525 | }; 526 | name = Release; 527 | }; 528 | 884EBEA01E14842C007DE6F4 /* Debug */ = { 529 | isa = XCBuildConfiguration; 530 | buildSettings = { 531 | BUNDLE_LOADER = "$(TEST_HOST)"; 532 | COMBINE_HIDPI_IMAGES = YES; 533 | DEVELOPMENT_TEAM = SCM43BAGSW; 534 | INFOPLIST_FILE = AutoVolumeHelperTests/Info.plist; 535 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 536 | PRODUCT_BUNDLE_IDENTIFIER = "jesse-c.AutoVolumeHelperTests"; 537 | PRODUCT_NAME = "$(TARGET_NAME)"; 538 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AutoVolumeHelper.app/Contents/MacOS/AutoVolumeHelper"; 539 | }; 540 | name = Debug; 541 | }; 542 | 884EBEA11E14842C007DE6F4 /* Release */ = { 543 | isa = XCBuildConfiguration; 544 | buildSettings = { 545 | BUNDLE_LOADER = "$(TEST_HOST)"; 546 | COMBINE_HIDPI_IMAGES = YES; 547 | DEVELOPMENT_TEAM = SCM43BAGSW; 548 | INFOPLIST_FILE = AutoVolumeHelperTests/Info.plist; 549 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 550 | PRODUCT_BUNDLE_IDENTIFIER = "jesse-c.AutoVolumeHelperTests"; 551 | PRODUCT_NAME = "$(TARGET_NAME)"; 552 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AutoVolumeHelper.app/Contents/MacOS/AutoVolumeHelper"; 553 | }; 554 | name = Release; 555 | }; 556 | 886F9D231E05F14700F8A083 /* Debug */ = { 557 | isa = XCBuildConfiguration; 558 | buildSettings = { 559 | ALWAYS_SEARCH_USER_PATHS = NO; 560 | CLANG_ANALYZER_NONNULL = YES; 561 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 562 | CLANG_CXX_LIBRARY = "libc++"; 563 | CLANG_ENABLE_MODULES = YES; 564 | CLANG_ENABLE_OBJC_ARC = YES; 565 | CLANG_WARN_BOOL_CONVERSION = YES; 566 | CLANG_WARN_CONSTANT_CONVERSION = YES; 567 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 568 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 569 | CLANG_WARN_EMPTY_BODY = YES; 570 | CLANG_WARN_ENUM_CONVERSION = YES; 571 | CLANG_WARN_INFINITE_RECURSION = YES; 572 | CLANG_WARN_INT_CONVERSION = YES; 573 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 574 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 575 | CLANG_WARN_UNREACHABLE_CODE = YES; 576 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 577 | CODE_SIGN_IDENTITY = "-"; 578 | COPY_PHASE_STRIP = NO; 579 | DEBUG_INFORMATION_FORMAT = dwarf; 580 | ENABLE_STRICT_OBJC_MSGSEND = YES; 581 | ENABLE_TESTABILITY = YES; 582 | GCC_C_LANGUAGE_STANDARD = gnu99; 583 | GCC_DYNAMIC_NO_PIC = NO; 584 | GCC_NO_COMMON_BLOCKS = YES; 585 | GCC_OPTIMIZATION_LEVEL = 0; 586 | GCC_PREPROCESSOR_DEFINITIONS = ( 587 | "DEBUG=1", 588 | "$(inherited)", 589 | ); 590 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 591 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 592 | GCC_WARN_UNDECLARED_SELECTOR = YES; 593 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 594 | GCC_WARN_UNUSED_FUNCTION = YES; 595 | GCC_WARN_UNUSED_VARIABLE = YES; 596 | MACOSX_DEPLOYMENT_TARGET = 10.12; 597 | MTL_ENABLE_DEBUG_INFO = YES; 598 | ONLY_ACTIVE_ARCH = YES; 599 | SDKROOT = macosx; 600 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 601 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 602 | }; 603 | name = Debug; 604 | }; 605 | 886F9D241E05F14700F8A083 /* Release */ = { 606 | isa = XCBuildConfiguration; 607 | buildSettings = { 608 | ALWAYS_SEARCH_USER_PATHS = NO; 609 | CLANG_ANALYZER_NONNULL = YES; 610 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 611 | CLANG_CXX_LIBRARY = "libc++"; 612 | CLANG_ENABLE_MODULES = YES; 613 | CLANG_ENABLE_OBJC_ARC = YES; 614 | CLANG_WARN_BOOL_CONVERSION = YES; 615 | CLANG_WARN_CONSTANT_CONVERSION = YES; 616 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 617 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 618 | CLANG_WARN_EMPTY_BODY = YES; 619 | CLANG_WARN_ENUM_CONVERSION = YES; 620 | CLANG_WARN_INFINITE_RECURSION = YES; 621 | CLANG_WARN_INT_CONVERSION = YES; 622 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 623 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 624 | CLANG_WARN_UNREACHABLE_CODE = YES; 625 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 626 | CODE_SIGN_IDENTITY = "-"; 627 | COPY_PHASE_STRIP = NO; 628 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 629 | ENABLE_NS_ASSERTIONS = NO; 630 | ENABLE_STRICT_OBJC_MSGSEND = YES; 631 | GCC_C_LANGUAGE_STANDARD = gnu99; 632 | GCC_NO_COMMON_BLOCKS = YES; 633 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 634 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 635 | GCC_WARN_UNDECLARED_SELECTOR = YES; 636 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 637 | GCC_WARN_UNUSED_FUNCTION = YES; 638 | GCC_WARN_UNUSED_VARIABLE = YES; 639 | MACOSX_DEPLOYMENT_TARGET = 10.12; 640 | MTL_ENABLE_DEBUG_INFO = NO; 641 | SDKROOT = macosx; 642 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 643 | }; 644 | name = Release; 645 | }; 646 | 886F9D261E05F14700F8A083 /* Debug */ = { 647 | isa = XCBuildConfiguration; 648 | buildSettings = { 649 | COMBINE_HIDPI_IMAGES = YES; 650 | DEVELOPMENT_TEAM = SCM43BAGSW; 651 | INFOPLIST_FILE = AutoVolume/Info.plist; 652 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 653 | PRODUCT_BUNDLE_IDENTIFIER = "jesse-c.AutoVolume"; 654 | PRODUCT_NAME = "$(TARGET_NAME)"; 655 | SWIFT_VERSION = 3.0; 656 | }; 657 | name = Debug; 658 | }; 659 | 886F9D271E05F14700F8A083 /* Release */ = { 660 | isa = XCBuildConfiguration; 661 | buildSettings = { 662 | COMBINE_HIDPI_IMAGES = YES; 663 | DEVELOPMENT_TEAM = SCM43BAGSW; 664 | INFOPLIST_FILE = AutoVolume/Info.plist; 665 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 666 | PRODUCT_BUNDLE_IDENTIFIER = "jesse-c.AutoVolume"; 667 | PRODUCT_NAME = "$(TARGET_NAME)"; 668 | SWIFT_VERSION = 3.0; 669 | }; 670 | name = Release; 671 | }; 672 | 886F9D291E05F14700F8A083 /* Debug */ = { 673 | isa = XCBuildConfiguration; 674 | buildSettings = { 675 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 676 | BUNDLE_LOADER = "$(TEST_HOST)"; 677 | COMBINE_HIDPI_IMAGES = YES; 678 | DEVELOPMENT_TEAM = SCM43BAGSW; 679 | INFOPLIST_FILE = AutoVolumeTests/Info.plist; 680 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 681 | PRODUCT_BUNDLE_IDENTIFIER = "jesse-c.AutoVolumeTests"; 682 | PRODUCT_NAME = "$(TARGET_NAME)"; 683 | SWIFT_VERSION = 3.0; 684 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AutoVolume.app/Contents/MacOS/AutoVolume"; 685 | }; 686 | name = Debug; 687 | }; 688 | 886F9D2A1E05F14700F8A083 /* Release */ = { 689 | isa = XCBuildConfiguration; 690 | buildSettings = { 691 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 692 | BUNDLE_LOADER = "$(TEST_HOST)"; 693 | COMBINE_HIDPI_IMAGES = YES; 694 | DEVELOPMENT_TEAM = SCM43BAGSW; 695 | INFOPLIST_FILE = AutoVolumeTests/Info.plist; 696 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 697 | PRODUCT_BUNDLE_IDENTIFIER = "jesse-c.AutoVolumeTests"; 698 | PRODUCT_NAME = "$(TARGET_NAME)"; 699 | SWIFT_VERSION = 3.0; 700 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AutoVolume.app/Contents/MacOS/AutoVolume"; 701 | }; 702 | name = Release; 703 | }; 704 | 886F9D2C1E05F14700F8A083 /* Debug */ = { 705 | isa = XCBuildConfiguration; 706 | buildSettings = { 707 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 708 | COMBINE_HIDPI_IMAGES = YES; 709 | DEVELOPMENT_TEAM = SCM43BAGSW; 710 | INFOPLIST_FILE = AutoVolumeUITests/Info.plist; 711 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 712 | PRODUCT_BUNDLE_IDENTIFIER = "jesse-c.AutoVolumeUITests"; 713 | PRODUCT_NAME = "$(TARGET_NAME)"; 714 | SWIFT_VERSION = 3.0; 715 | TEST_TARGET_NAME = AutoVolume; 716 | }; 717 | name = Debug; 718 | }; 719 | 886F9D2D1E05F14700F8A083 /* Release */ = { 720 | isa = XCBuildConfiguration; 721 | buildSettings = { 722 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 723 | COMBINE_HIDPI_IMAGES = YES; 724 | DEVELOPMENT_TEAM = SCM43BAGSW; 725 | INFOPLIST_FILE = AutoVolumeUITests/Info.plist; 726 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 727 | PRODUCT_BUNDLE_IDENTIFIER = "jesse-c.AutoVolumeUITests"; 728 | PRODUCT_NAME = "$(TARGET_NAME)"; 729 | SWIFT_VERSION = 3.0; 730 | TEST_TARGET_NAME = AutoVolume; 731 | }; 732 | name = Release; 733 | }; 734 | /* End XCBuildConfiguration section */ 735 | 736 | /* Begin XCConfigurationList section */ 737 | 884EBEA21E14842C007DE6F4 /* Build configuration list for PBXNativeTarget "AutoVolumeHelper" */ = { 738 | isa = XCConfigurationList; 739 | buildConfigurations = ( 740 | 884EBE9E1E14842C007DE6F4 /* Debug */, 741 | 884EBE9F1E14842C007DE6F4 /* Release */, 742 | ); 743 | defaultConfigurationIsVisible = 0; 744 | defaultConfigurationName = Release; 745 | }; 746 | 884EBEA31E14842C007DE6F4 /* Build configuration list for PBXNativeTarget "AutoVolumeHelperTests" */ = { 747 | isa = XCConfigurationList; 748 | buildConfigurations = ( 749 | 884EBEA01E14842C007DE6F4 /* Debug */, 750 | 884EBEA11E14842C007DE6F4 /* Release */, 751 | ); 752 | defaultConfigurationIsVisible = 0; 753 | defaultConfigurationName = Release; 754 | }; 755 | 886F9CFB1E05F14700F8A083 /* Build configuration list for PBXProject "AutoVolume" */ = { 756 | isa = XCConfigurationList; 757 | buildConfigurations = ( 758 | 886F9D231E05F14700F8A083 /* Debug */, 759 | 886F9D241E05F14700F8A083 /* Release */, 760 | ); 761 | defaultConfigurationIsVisible = 0; 762 | defaultConfigurationName = Release; 763 | }; 764 | 886F9D251E05F14700F8A083 /* Build configuration list for PBXNativeTarget "AutoVolume" */ = { 765 | isa = XCConfigurationList; 766 | buildConfigurations = ( 767 | 886F9D261E05F14700F8A083 /* Debug */, 768 | 886F9D271E05F14700F8A083 /* Release */, 769 | ); 770 | defaultConfigurationIsVisible = 0; 771 | defaultConfigurationName = Release; 772 | }; 773 | 886F9D281E05F14700F8A083 /* Build configuration list for PBXNativeTarget "AutoVolumeTests" */ = { 774 | isa = XCConfigurationList; 775 | buildConfigurations = ( 776 | 886F9D291E05F14700F8A083 /* Debug */, 777 | 886F9D2A1E05F14700F8A083 /* Release */, 778 | ); 779 | defaultConfigurationIsVisible = 0; 780 | defaultConfigurationName = Release; 781 | }; 782 | 886F9D2B1E05F14700F8A083 /* Build configuration list for PBXNativeTarget "AutoVolumeUITests" */ = { 783 | isa = XCConfigurationList; 784 | buildConfigurations = ( 785 | 886F9D2C1E05F14700F8A083 /* Debug */, 786 | 886F9D2D1E05F14700F8A083 /* Release */, 787 | ); 788 | defaultConfigurationIsVisible = 0; 789 | defaultConfigurationName = Release; 790 | }; 791 | /* End XCConfigurationList section */ 792 | }; 793 | rootObject = 886F9CF81E05F14700F8A083 /* Project object */; 794 | } 795 | -------------------------------------------------------------------------------- /AutoVolume.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AutoVolume/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import AudioToolbox 3 | import ServiceManagement 4 | 5 | typealias ValInfo = [String: Float] 6 | typealias EnabledInfo = [String: Int] 7 | typealias LoginStartInfo = [String: Int] 8 | 9 | @NSApplicationMain 10 | class AppDelegate: NSObject, NSApplicationDelegate { 11 | 12 | let defaults: UserDefaults = UserDefaults.standard 13 | let desiredVolumeKey: String = "desiredVolume" 14 | let enabledKey: String = "enabled" 15 | let loginStartKey: String = "loginStart" 16 | 17 | var defaultOutputDeviceID: AudioDeviceID? = kAudioObjectUnknown // TODO Remove default assigned value? Stop it being nil and default to unknown 18 | 19 | let nc: NotificationCenter = NSWorkspace.shared().notificationCenter 20 | 21 | func applicationDidFinishLaunching(_ aNotification: Notification) { 22 | // Notifications 23 | NSLog("Setting up notification handlers") 24 | nc.addObserver(self, selector: #selector(self.handleWillSleep), name: NSNotification.Name.NSWorkspaceWillSleep, object: nil) 25 | nc.addObserver(self, selector: #selector(self.handleDidWake), name: NSNotification.Name.NSWorkspaceDidWake, object: nil) 26 | nc.addObserver(self, selector: #selector(self.handleVolumeChanged), name: NSNotification.Name.OnVolumeChanged, object: nil) 27 | nc.addObserver(self, selector: #selector(self.handleEnabledStateChanged), name: NSNotification.Name.OnEnabledButtonPressed, object: nil) 28 | nc.addObserver(self, selector: #selector(self.handleLoginStartStateChanged), name: NSNotification.Name.OnLoginStartButtonPressed, object: nil) 29 | nc.addObserver(self, selector: #selector(self.handleQuit), name: NSNotification.Name.OnQuitButtonPressed, object: nil) 30 | 31 | do { 32 | try defaultOutputDeviceID = getDefaultOutputDevice() 33 | NSLog("Default output device ID: \(String(describing: defaultOutputDeviceID))") 34 | } catch VolumeError.noDefaultOutputDevice { 35 | NSLog("No default output device found, qutting") 36 | showAlert(style: NSAlertStyle.critical, message: "Failed to find system audio device.", info: "Application will now quit.") 37 | self.nc.post(name: NSNotification.Name.OnQuitButtonPressed, object: nil, userInfo: nil) 38 | } catch { 39 | showAlert(style: NSAlertStyle.critical, message: error as! String, info: "Application will now quit.") 40 | } 41 | 42 | // Bring to front 43 | NSApplication.shared().activate(ignoringOtherApps: true) 44 | } 45 | 46 | func showAlert(style: NSAlertStyle, message: String, info: String) { 47 | let alert = NSAlert.init() 48 | alert.alertStyle = NSAlertStyle.critical 49 | alert.messageText = message 50 | alert.informativeText = info 51 | alert.addButton(withTitle: "Okay") 52 | alert.runModal() 53 | } 54 | 55 | func handleWillSleep(notification: Notification) { 56 | NSLog("Received \(notification.name)") 57 | } 58 | 59 | func handleDidWake(notification: Notification) { 60 | NSLog("Received \(notification.name)") 61 | 62 | // Check if enabled state is on 63 | let enabledState = defaults.integer(forKey: enabledKey) 64 | guard enabledState == NSOnState else { 65 | NSLog("Not enabled") 66 | return 67 | } 68 | 69 | let err = checkOutputDevice(outputDeviceID: defaultOutputDeviceID!) 70 | guard err == nil else { 71 | NSLog(err!.localizedDescription) 72 | return 73 | } 74 | 75 | // Defaults to 0.0 if no value had been set 76 | let desiredVolume = defaults.float(forKey: desiredVolumeKey) 77 | 78 | do { 79 | try setDeviceVolume(outputDeviceID: defaultOutputDeviceID!, value: desiredVolume) 80 | NSLog("Set volume to \(desiredVolume)") 81 | } catch VolumeError.failedToSetVolume { 82 | NSLog("Failed to set volume") 83 | } catch VolumeError.outputDeviceHasNoVolumeProperty { 84 | NSLog("Output device has no volume property") 85 | } catch { 86 | NSLog("Other") 87 | } 88 | } 89 | 90 | func handleVolumeChanged(notification: Notification) { 91 | NSLog("Received \(notification.name)") 92 | let userInfo = notification.userInfo as! ValInfo 93 | defaults.set(userInfo["val"], forKey: desiredVolumeKey) 94 | } 95 | 96 | func handleLoginStartStateChanged(notification: Notification) { 97 | NSLog("Received \(notification.name)") 98 | let userInfo = notification.userInfo as! LoginStartInfo 99 | let state = (userInfo["buttonState"] == NSOnState) 100 | 101 | _ = setLoginStartState(state: state) 102 | defaults.set(userInfo["buttonState"], forKey: loginStartKey) 103 | } 104 | 105 | func setLoginStartState(state: Bool) -> Bool { 106 | let appBundleIdentifier = "jesse-c.AutoVolumeHelper" 107 | 108 | if SMLoginItemSetEnabled(appBundleIdentifier as CFString, state) { 109 | if state { 110 | NSLog("Successfully added login item.") 111 | } else { 112 | NSLog("Successfully removed login item.") 113 | } 114 | 115 | return true 116 | } else { 117 | NSLog("Failed to add login item.") 118 | 119 | return false 120 | } 121 | } 122 | 123 | func handleEnabledStateChanged(notification: Notification) { 124 | NSLog("Received \(notification.name)") 125 | let userInfo = notification.userInfo as! EnabledInfo 126 | defaults.set(userInfo["buttonState"], forKey: enabledKey) 127 | } 128 | 129 | func handleQuit(notification: Notification) { 130 | NSApplication.shared().terminate(self) 131 | } 132 | 133 | func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool { 134 | /* TODO For now, we know there is only 1 window, so we can access the 0th element 135 | * But ideally we're a bit smarter about this—i.e. check for which window to 136 | * make key and visible. 137 | */ 138 | let windows = sender.windows 139 | if windows.count > 0 { 140 | sender.windows[0].makeKeyAndOrderFront(self) 141 | return true 142 | } 143 | 144 | return false 145 | } 146 | 147 | func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 148 | return false 149 | } 150 | 151 | func applicationWillTerminate(_ aNotification: Notification) { 152 | nc.removeObserver(self) 153 | defaults.synchronize() 154 | } 155 | 156 | } 157 | 158 | -------------------------------------------------------------------------------- /AutoVolume/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /AutoVolume/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | Default 511 | 512 | 513 | 514 | 515 | 516 | 517 | Left to Right 518 | 519 | 520 | 521 | 522 | 523 | 524 | Right to Left 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | Default 536 | 537 | 538 | 539 | 540 | 541 | 542 | Left to Right 543 | 544 | 545 | 546 | 547 | 548 | 549 | Right to Left 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 770 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | -------------------------------------------------------------------------------- /AutoVolume/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LSUIElement 6 | 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | $(PRODUCT_NAME) 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | Copyright © 2016 Jesse Claven. All rights reserved. 29 | NSMainStoryboardFile 30 | Main 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /AutoVolume/Notifications.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Notification.Name { 4 | static let OnVolumeChanged = Notification.Name("on-volume-changed") 5 | static let OnEnabledButtonPressed = Notification.Name("on-enabled-button-pressed") 6 | static let OnLoginStartButtonPressed = Notification.Name("on-login-start-button-pressed") 7 | static let OnQuitButtonPressed = Notification.Name("on-quit-button-pressed") 8 | } 9 | -------------------------------------------------------------------------------- /AutoVolume/ViewController.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | 3 | class ViewController: NSViewController { 4 | 5 | let appDelegate = NSApplication.shared().delegate as! AppDelegate 6 | 7 | @IBOutlet weak var volumeSlider: NSSlider! 8 | @IBOutlet weak var currentVolume: NSTextField! 9 | @IBOutlet weak var loginStartCheckbox: NSButton! 10 | @IBOutlet weak var enabledCheckbox: NSButton! 11 | @IBOutlet weak var quitButton: NSButtonCell! 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | // Do any additional setup after loading the view. 17 | 18 | let volume = appDelegate.defaults.float(forKey: appDelegate.desiredVolumeKey) 19 | self.currentVolume.placeholderString = "?" 20 | self.currentVolume.stringValue = NSString(format: "%.2f", volume) as String 21 | 22 | self.currentVolume.isEditable = false 23 | self.currentVolume.isSelectable = false 24 | 25 | // Set slider to current volume 26 | volumeSlider.floatValue = volume 27 | 28 | // Set enabled button to current state 29 | let enabledButtonState = appDelegate.defaults.integer(forKey: appDelegate.enabledKey) 30 | enabledCheckbox.state = enabledButtonState 31 | 32 | // Set login enabled button to current state 33 | let loginStartButtonState = appDelegate.defaults.integer(forKey: appDelegate.loginStartKey) 34 | loginStartCheckbox.state = loginStartButtonState 35 | 36 | // Centre 37 | self.view.window?.center() 38 | // Prevent resizing 39 | _ = self.view.window?.styleMask.remove([.resizable]) 40 | 41 | // Notifications 42 | appDelegate.nc.addObserver(self, selector: #selector(self.handleVolumeChanged), name: NSNotification.Name.OnVolumeChanged, object: nil) 43 | 44 | } 45 | 46 | override var representedObject: Any? { 47 | didSet { 48 | // Update the view, if already loaded. 49 | } 50 | } 51 | 52 | @IBAction func sliderChanged(_ sender: NSSlider) { 53 | let val: Float = sender.floatValue 54 | let userInfo: ValInfo = ["val": val] 55 | 56 | NSLog("Slider changed to: \(val)") 57 | 58 | appDelegate.nc.post(name: NSNotification.Name.OnVolumeChanged, object: nil, userInfo: userInfo) 59 | } 60 | 61 | @IBAction func loginStartButtonPressed(_ sender: NSButton) { 62 | let buttonState = loginStartCheckbox.state 63 | let userInfo: LoginStartInfo = ["buttonState": buttonState] 64 | 65 | appDelegate.nc.post(name: NSNotification.Name.OnLoginStartButtonPressed, object: nil, userInfo: userInfo) 66 | } 67 | 68 | @IBAction func enabledButtonPressed(_ sender: NSButton) { 69 | let buttonState = enabledCheckbox.state 70 | let userInfo: EnabledInfo = ["buttonState": buttonState] 71 | 72 | NSLog("Enabled button pressed. State is: \(buttonState)") 73 | 74 | appDelegate.nc.post(name: NSNotification.Name.OnEnabledButtonPressed, object: nil, userInfo: userInfo) 75 | } 76 | 77 | @IBAction func quitButtonPressed(_ sender: Any) { 78 | NSLog("Quit button pressed") 79 | appDelegate.nc.post(name: NSNotification.Name.OnQuitButtonPressed, object: nil, userInfo: nil) 80 | } 81 | 82 | // This is done here in case we have multiple sources posting notifications 83 | // modifying the volume. 84 | func handleVolumeChanged(notification: Notification) { 85 | NSLog("Received \(notification.name)") 86 | let userInfo = notification.userInfo as! ValInfo 87 | let volume = userInfo["val"]! as Float 88 | currentVolume.stringValue = NSString(format: "%.2f", volume) as String 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /AutoVolume/Volume.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import AudioToolbox 3 | 4 | enum VolumeError: Error { 5 | case noDefaultOutputDevice(status: Int32) 6 | case invalidOutputDeviceID 7 | case outputDeviceHasNoVolumeProperty 8 | case invalidVolumeValue 9 | case failedToSetVolume(status: Int32) 10 | case failedToGetVolume(status: Int32) 11 | } 12 | 13 | func getDefaultOutputDevice() throws -> AudioDeviceID { 14 | var defaultOutputDeviceID: AudioDeviceID = AudioDeviceID(0) 15 | var defaultOutputDeviceIDSize: UInt32 = UInt32(MemoryLayout.size(ofValue: defaultOutputDeviceID)) 16 | 17 | var getDefaultOutputDevicePropertyAddress = AudioObjectPropertyAddress( 18 | mSelector: AudioObjectPropertySelector(kAudioHardwarePropertyDefaultOutputDevice), 19 | mScope: AudioObjectPropertyScope(kAudioObjectPropertyScopeGlobal), 20 | mElement: AudioObjectPropertyElement(kAudioObjectPropertyElementMaster)) 21 | 22 | let status = AudioObjectGetPropertyData( 23 | AudioObjectID(kAudioObjectSystemObject), 24 | &getDefaultOutputDevicePropertyAddress, 25 | 0, 26 | nil, 27 | &defaultOutputDeviceIDSize, 28 | &defaultOutputDeviceID 29 | ) 30 | 31 | guard defaultOutputDeviceID != kAudioObjectUnknown && status == noErr else { 32 | throw VolumeError.noDefaultOutputDevice(status: status) 33 | } 34 | 35 | return defaultOutputDeviceID 36 | } 37 | 38 | 39 | func setDeviceVolume(outputDeviceID: AudioDeviceID, value: Float32) throws { 40 | let err = checkOutputDevice(outputDeviceID: outputDeviceID) 41 | guard err == nil else { 42 | throw err! 43 | } 44 | 45 | guard value >= 0.0 || value <= 1.0 else { 46 | throw VolumeError.invalidVolumeValue 47 | } 48 | 49 | var volume = value 50 | let volumeSize = UInt32(MemoryLayout.size(ofValue: volume)) 51 | 52 | var volumePropertyAddress = AudioObjectPropertyAddress( 53 | mSelector: AudioObjectPropertySelector(kAudioHardwareServiceDeviceProperty_VirtualMasterVolume), 54 | mScope: AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput), 55 | mElement: AudioObjectPropertyElement(kAudioObjectPropertyElementMaster)) 56 | 57 | let status = AudioObjectSetPropertyData( 58 | outputDeviceID, 59 | &volumePropertyAddress, 60 | 0, 61 | nil, 62 | volumeSize, 63 | &volume 64 | ) 65 | 66 | guard status == noErr else { 67 | throw VolumeError.failedToSetVolume(status: status) 68 | } 69 | } 70 | 71 | func getDeviceVolume(outputDeviceID: AudioDeviceID) throws -> Float32 { 72 | let err = checkOutputDevice(outputDeviceID: outputDeviceID) 73 | guard err == nil else { 74 | throw err! 75 | } 76 | 77 | var volume: Float32 = -1.0 78 | var volumeSize = UInt32(MemoryLayout.size(ofValue: volume)) 79 | 80 | var volumePropertyAddress = AudioObjectPropertyAddress( 81 | mSelector: AudioObjectPropertySelector(kAudioHardwareServiceDeviceProperty_VirtualMasterVolume), 82 | mScope: AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput), 83 | mElement: AudioObjectPropertyElement(kAudioObjectPropertyElementMaster)) 84 | 85 | let status = AudioObjectGetPropertyData( 86 | outputDeviceID, 87 | &volumePropertyAddress, 88 | 0, 89 | nil, 90 | &volumeSize, 91 | &volume 92 | ) 93 | 94 | guard status == noErr && volume != -1.0 else { 95 | throw VolumeError.failedToGetVolume(status: status) 96 | } 97 | 98 | return volume 99 | } 100 | 101 | func checkOutputDevice(outputDeviceID: AudioDeviceID) -> Error? { 102 | // Has volume property 103 | var volumePropertyAddress = AudioObjectPropertyAddress( 104 | mSelector: AudioObjectPropertySelector(kAudioHardwareServiceDeviceProperty_VirtualMasterVolume), 105 | mScope: AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput), 106 | mElement: AudioObjectPropertyElement(kAudioObjectPropertyElementMaster)) 107 | 108 | guard AudioObjectHasProperty(outputDeviceID, &volumePropertyAddress) else { 109 | return VolumeError.outputDeviceHasNoVolumeProperty 110 | } 111 | 112 | // Unknown ID 113 | guard outputDeviceID != kAudioObjectUnknown else { 114 | return VolumeError.invalidOutputDeviceID 115 | } 116 | 117 | return nil 118 | } 119 | -------------------------------------------------------------------------------- /AutoVolumeHelper/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // AgentHelper 4 | // 5 | // Created by Jesse Claven on 29/12/16. 6 | // Copyright © 2016 Jesse Claven. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : NSObject 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /AutoVolumeHelper/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // AgentHelper 4 | // 5 | // Created by Jesse Claven on 29/12/16. 6 | // Copyright © 2016 Jesse Claven. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @property (weak) IBOutlet NSWindow *window; 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 19 | NSArray *pathComponents = [[[NSBundle mainBundle] bundlePath] pathComponents]; 20 | pathComponents = [pathComponents subarrayWithRange:NSMakeRange(0, [pathComponents count] - 4)]; 21 | NSString *path = [NSString pathWithComponents:pathComponents]; 22 | [[NSWorkspace sharedWorkspace] launchApplication:path]; 23 | [NSApp terminate:nil]; 24 | } 25 | 26 | 27 | - (void)applicationWillTerminate:(NSNotification *)aNotification { 28 | // Insert code here to tear down your application 29 | } 30 | 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /AutoVolumeHelper/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /AutoVolumeHelper/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | Default 538 | 539 | 540 | 541 | 542 | 543 | 544 | Left to Right 545 | 546 | 547 | 548 | 549 | 550 | 551 | Right to Left 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | Default 563 | 564 | 565 | 566 | 567 | 568 | 569 | Left to Right 570 | 571 | 572 | 573 | 574 | 575 | 576 | Right to Left 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | -------------------------------------------------------------------------------- /AutoVolumeHelper/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSBackgroundOnly 24 | 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | Copyright © 2016 Jesse Claven. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /AutoVolumeHelper/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // AgentHelper 4 | // 5 | // Created by Jesse Claven on 29/12/16. 6 | // Copyright © 2016 Jesse Claven. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) { 12 | return NSApplicationMain(argc, argv); 13 | } 14 | -------------------------------------------------------------------------------- /AutoVolumeHelperTests/AutoVolumeHelperTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // AutoVolumeHelperTests.m 3 | // AutoVolumeHelperTests 4 | // 5 | // Created by Jesse Claven on 29/12/16. 6 | // Copyright © 2016 Jesse Claven. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AutoVolumeHelperTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation AutoVolumeHelperTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /AutoVolumeHelperTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /AutoVolumeTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /AutoVolumeTests/Tests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Tests.swift 3 | // AutoVolumeTests 4 | // 5 | // Created by Jesse Claven on 17/12/16. 6 | // Copyright © 2016 Jesse Claven. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import AutoVolume 11 | 12 | class Tests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | } 17 | 18 | override func tearDown() { 19 | super.tearDown() 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 | AutoVolume.AppDelegate 26 | } 27 | 28 | func testPerformanceExample() { 29 | // This is an example of a performance test case. 30 | self.measure { 31 | // Put the code you want to measure the time of here. 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /AutoVolumeUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /AutoVolumeUITests/UITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // agent_macOSUITests.swift 3 | // agent-macOSUITests 4 | // 5 | // Created by Jesse Claven on 17/12/16. 6 | // Copyright © 2016 Jesse Claven. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class agent_macOSUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // 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. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are welcome! No formal process is setup, simply create a PR and let me know. Check existing issues and PRs first. 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jesse Claven 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AutoVolume (macOS) 2 | 3 | [Home page](http://www.jesseclaven.com/projects/AutoVolume) 4 | 5 | AutoVolume automatically sets the volume of macOS to a specified volume. At the moment it only fires on sleep. For example, the primary use case is to set the system volume to 0 when waking from sleep to save being surprised if you were listening to music quite loud before you closed it and fell asleep. 6 | 7 | Why? To learn about macOS development, begin the 'Agent' idea, and practice design. 8 | 9 | Alternative: 10 | 11 | Use HammerSpoon and hook into [systemDidWake](http://www.hammerspoon.org/docs/hs.caffeinate.watcher.html#systemDidWake) and [mute default audio device](https://github.com/STRML/init/blob/master/hammerspoon/init.lua#L218). For example: 12 | 13 | ```lua 14 | function sleepWatch(eventType) 15 | if (eventType == hs.caffeinate.watcher.systemWillSleep or eventType == hs.caffeinate.watcher.systemDidWake) then 16 | hs.audiodevice.defaultOutputDevice():setVolume(0) 17 | end 18 | end 19 | 20 | sleepWatcher = hs.caffeinate.watcher.new(sleepWatch) 21 | sleepWatcher:start() 22 | ``` 23 | 24 | ## TODO 25 | 26 | - [ ] Add user notifications 27 | - [ ] Remove NSLog or hide behind debug flag 28 | 29 | ## Wishlist 30 | 31 | - Choose audio device 32 | - Choose event for when to act 33 | - Only change volume if a specified amount of time has elapsed 34 | - Add option to display the current volume in a notable way on event 35 | - Act only if volume is above a specified threshold 36 | - Set time when to set volume ([suggested by Simone M](https://www.designernews.co/comments/254374)) 37 | - [Optional] menu bar icon 38 | - Set volume on system login 39 | 40 | ## Contributing 41 | 42 | Contributions are welcome! See [contributing](CONTRIBUTING.md). 43 | 44 | ## License 45 | 46 | See [license](LICENSE). 47 | -------------------------------------------------------------------------------- /website/humans.txt: -------------------------------------------------------------------------------- 1 | # humanstxt.org/ 2 | # The humans responsible & technology colophon 3 | 4 | # TEAM 5 | 6 | Jesse Claven -- Software engineer & designer -- @jqiye 7 | -------------------------------------------------------------------------------- /website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | AutoVolume for macOS — Automatically change the volume when your Mac wakes from sleep. 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 | A project by Jesse Claven————Home 17 |
18 |
19 | Email 20 | Instagram 21 |
22 |
23 |
24 |
25 |
26 |

AutoVolume

27 |

Automatically change the volume when your Mac wakes from sleep.

28 |

Free and open source.

29 |
30 |
31 | Download 32 |
33 |
34 | Source code 35 |
36 |
37 | Supported: macOS Sierra 10.12 / License: MIT 38 |
39 |
40 |
41 |

Avoid this happening.

42 | Animation of laptop emitting music unexpectedly 43 |
44 |
45 |
46 |

Instructions

47 |
48 | Screenshot 49 |
50 |
51 |
    52 |
  1. Enable or disable automatically setting the volume.
  2. 53 |
  3. Enable or disable starting the app at login.
  4. 54 |
  5. Set the target value you’d like the volume to be set to.
  6. 55 |
  7. Quit the app—this stops the volume from automatically being set.
  8. 56 |
  9. Closes the window—the app will continue running in the background.
  10. 57 |
58 |
59 |
60 |
61 |
62 |
63 | Copyright © 2017 Jesse Claven 64 |
65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /website/resources/css/main.css: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | font-size: 62.5%; } 4 | 5 | *, 6 | *:after, 7 | *:before { 8 | box-sizing: inherit; } 9 | 10 | body { 11 | margin: 0; 12 | font-size: 1.4em; 13 | letter-spacing: .01em; 14 | line-height: 1.6; 15 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Helvetica, sans-serif; 16 | color: #111; 17 | background-color: #fff; } 18 | 19 | img { 20 | max-width: 100%; 21 | height: auto; } 22 | 23 | svg { 24 | max-height: 100%; } 25 | 26 | h1, h2, h3, 27 | h4, h5, h6 { 28 | font-weight: 600; 29 | line-height: 1.25; 30 | margin-top: 1em; 31 | margin-bottom: .5em; } 32 | 33 | h1 { 34 | font-size: 2rem; } 35 | 36 | h2 { 37 | font-size: 1.5rem; } 38 | 39 | h3 { 40 | font-size: 1.25rem; } 41 | 42 | h4 { 43 | font-size: 1rem; } 44 | 45 | h5 { 46 | font-size: 0.875rem; } 47 | 48 | h6 { 49 | font-size: 0.75rem; } 50 | 51 | p, ul, small { 52 | margin-top: 1em; 53 | margin-bottom: 1em; } 54 | 55 | a { 56 | color: #0068F7; 57 | outline-width: 0; 58 | cursor: pointer; } 59 | 60 | hr { 61 | box-sizing: content-box; 62 | height: 0; 63 | overflow: visible; 64 | margin-top: 2.0em; 65 | margin-bottom: 2.0em; 66 | border: 0; 67 | border-bottom-width: 1px; 68 | border-bottom-style: solid; 69 | border-bottom-color: #ccc; 70 | width: 100%; } 71 | 72 | /* Hang (Credit: https://ianlunn.github.io/Hover/) */ 73 | @-webkit-keyframes hvr-hang { 74 | 0% { 75 | -webkit-transform: translateY(8px); 76 | transform: translateY(8px); } 77 | 50% { 78 | -webkit-transform: translateY(4px); 79 | transform: translateY(4px); } 80 | 100% { 81 | -webkit-transform: translateY(8px); 82 | transform: translateY(8px); } } 83 | @keyframes hvr-hang { 84 | 0% { 85 | -webkit-transform: translateY(8px); 86 | transform: translateY(8px); } 87 | 50% { 88 | -webkit-transform: translateY(4px); 89 | transform: translateY(4px); } 90 | 100% { 91 | -webkit-transform: translateY(8px); 92 | transform: translateY(8px); } } 93 | @-webkit-keyframes hvr-hang-sink { 94 | 100% { 95 | -webkit-transform: translateY(8px); 96 | transform: translateY(8px); } } 97 | @keyframes hvr-hang-sink { 98 | 100% { 99 | -webkit-transform: translateY(8px); 100 | transform: translateY(8px); } } 101 | body > div:nth-of-type(2) > div:nth-of-type(1) a { 102 | display: inline-block; 103 | vertical-align: middle; 104 | -webkit-transform: perspective(1px) translateZ(0); 105 | transform: perspective(1px) translateZ(0); 106 | box-shadow: 0 0 1px transparent; } 107 | 108 | body > div:nth-of-type(2) > div:nth-of-type(1) a:hover, body > div:nth-of-type(2) > div:nth-of-type(1) a:focus, body > div:nth-of-type(2) > div:nth-of-type(1) a:active { 109 | -webkit-animation-name: hvr-hang-sink, hvr-hang; 110 | animation-name: hvr-hang-sink, hvr-hang; 111 | -webkit-animation-duration: .3s, 1.5s; 112 | animation-duration: .3s, 1.5s; 113 | -webkit-animation-delay: 0s, .3s; 114 | animation-delay: 0s, .3s; 115 | -webkit-animation-timing-function: ease-out, ease-in-out; 116 | animation-timing-function: ease-out, ease-in-out; 117 | -webkit-animation-iteration-count: 1, infinite; 118 | animation-iteration-count: 1, infinite; 119 | -webkit-animation-fill-mode: forwards; 120 | animation-fill-mode: forwards; 121 | -webkit-animation-direction: normal, alternate; 122 | animation-direction: normal, alternate; } 123 | 124 | body > div:nth-of-type(1), body > div:nth-of-type(2), body > div:nth-of-type(3) { 125 | margin: 0 auto; 126 | max-width: 70.0rem; 127 | padding: 0 2.0rem; 128 | position: relative; 129 | width: 100%; } 130 | 131 | body > div:nth-of-type(1) > div:nth-of-type(1), body > div:nth-of-type(2) > div:nth-of-type(1), body > div:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(1), body > div:nth-of-type(2) > div:nth-of-type(2), body > div:nth-of-type(2) > div:nth-of-type(3), body > div:nth-of-type(3) > div:nth-of-type(1) { 132 | padding: 0; 133 | width: 100%; } 134 | 135 | body > div:nth-of-type(2) > div:nth-of-type(1) { 136 | max-width: 35.0rem; } 137 | 138 | body > div:nth-of-type(1) > div:nth-of-type(1):after, body > div:nth-of-type(2) > div:nth-of-type(3):after { 139 | clear: both; 140 | content: ' '; 141 | display: table; } 142 | 143 | body > div:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1), body > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(2) { 144 | float: left; } 145 | 146 | body > div:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(2), body > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(1) { 147 | float: right; } 148 | 149 | body > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(1), body > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(2) { 150 | width: 50%; } 151 | 152 | body > div:nth-of-type(2) > div:nth-of-type(1) { 153 | margin: 0 auto; } 154 | 155 | body > div:nth-of-type(2) > div:nth-of-type(1) a { 156 | border: 1px solid #0068F7; 157 | border-radius: 2px; 158 | padding: 8px 15px; 159 | text-decoration: none; 160 | box-shadow: 3px 3px 0px 0px #0068F7; 161 | color: #0068F7; } 162 | body > div:nth-of-type(2) > div:nth-of-type(1) a:active { 163 | background-color: #0068F7; } 164 | 165 | body > div:nth-of-type(1) > div:nth-of-type(1) { 166 | background-color: #000000; 167 | color: #FFFFFF; 168 | padding: 10px 15px; 169 | font-size: 0.8em; } 170 | body > div:nth-of-type(1) > div:nth-of-type(1) a { 171 | color: #FFFFFF; } 172 | body > div:nth-of-type(1) > div:nth-of-type(1) a:hover { 173 | color: #F8D353; } 174 | body > div:nth-of-type(2) > div:nth-of-type(1) { 175 | text-align: center; 176 | margin-bottom: 30px; } 177 | body > div:nth-of-type(2) > div:nth-of-type(1) > h1 { 178 | font-size: 2.5rem; 179 | margin-bottom: 1em; } 180 | body > div:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(1) { 181 | margin-top: 3rem; 182 | margin-bottom: 3rem; } 183 | body > div:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1) { 184 | display: inline-block; 185 | margin-right: 10px; } 186 | body > div:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(2) { 187 | display: inline-block; } 188 | body > div:nth-of-type(2) > div:nth-of-type(1) > small { 189 | display: block; } 190 | body > div:nth-of-type(2) > div:nth-of-type(2) { 191 | text-align: center; } 192 | body > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(2) > ol { 193 | padding-left: 1.75rem; } 194 | body > div:nth-of-type(3) { 195 | position: absolute; 196 | right: 0; 197 | bottom: 0; 198 | left: 0; } 199 | body > div:nth-of-type(3) > div:nth-of-type(1) { 200 | padding: 10px 0px; 201 | border-top: 1px solid #000000; } 202 | body > div:nth-of-type(3) > div:nth-of-type(1) > span { 203 | font-size: 0.8em; 204 | margin: 0; 205 | padding: 0; } 206 | 207 | @media only screen and (max-device-width: 768px) { 208 | body > div:nth-of-type(3) { 209 | position: relative; } } 210 | @media only screen and (max-device-width: 414px) { 211 | body > div:nth-of-type(1) { 212 | width: 100vw; 213 | max-width: 100vw; 214 | padding: 0; } 215 | body > div:nth-of-type(2) > div:nth-of-type(3) > h2 { 216 | text-align: center; } 217 | body > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(1) { 218 | width: 100%; } 219 | body > div:nth-of-type(2) > div:nth-of-type(3) > div:nth-of-type(2) { 220 | width: 100%; } 221 | body > div:nth-of-type(3) { 222 | width: 100vw; 223 | max-width: 100vw; 224 | padding: 0; 225 | position: relative; } 226 | body > div:nth-of-type(3) > div:nth-of-type(1) { 227 | padding-left: 15px; } } 228 | 229 | /*# sourceMappingURL=main.css.map */ 230 | -------------------------------------------------------------------------------- /website/resources/css/main.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "AAAA,IAAK;EACH,UAAU,EAAE,UAAU;EACtB,SAAS,EAAE,KAAK;;AAGlB;;QAES;EACP,UAAU,EAAE,OAAO;;AAGrB,IAAK;EACH,MAAM,EAAE,CAAC;EACT,SAAS,EAAE,KAAK;EAChB,cAAc,EAAE,KAAK;EACrB,WAAW,EAAE,GAAG;EAChB,WAAW,EACT,gGAMU;EACZ,KAAK,EAAE,IAAI;EACX,gBAAgB,EAAE,IAAI;;AAGxB,GAAI;EACF,SAAS,EAAE,IAAI;EACf,MAAM,EAAE,IAAI;;AAGd,GAAI;EACF,UAAU,EAAE,IAAI;;AAGlB;UACW;EACT,WAAW,EAAE,GAAG;EAChB,WAAW,EAAE,IAAI;EACjB,UAAU,EAAE,GAAG;EACf,aAAa,EAAE,IAAI;;AAGrB,EAAG;EAAE,SAAS,EAAE,IAAI;;AACpB,EAAG;EAAE,SAAS,EAAE,MAAM;;AACtB,EAAG;EAAE,SAAS,EAAE,OAAO;;AACvB,EAAG;EAAE,SAAS,EAAE,IAAI;;AACpB,EAAG;EAAE,SAAS,EAAE,QAAO;;AACvB,EAAG;EAAE,SAAS,EAAE,OAAM;;AAEtB,YAAa;EACX,UAAU,EAAE,GAAG;EACf,aAAa,EAAE,GAAG;;AAGpB,CAAE;EACA,KAAK,EAAE,OAAO;EACf,aAAa,EAAE,CAAC;EAChB,MAAM,EAAE,OAAO;;AAGhB,EAAG;EACD,UAAU,EAAE,WAAW;EACvB,MAAM,EAAE,CAAC;EACT,QAAQ,EAAE,OAAO;EACjB,UAAU,EAAE,KAAK;EACjB,aAAa,EAAE,KAAK;EACpB,MAAM,EAAE,CAAC;EACT,mBAAmB,EAAE,GAAG;EACxB,mBAAmB,EAAE,KAAK;EAC1B,mBAAmB,EAAE,IAAI;EAC1B,KAAK,EAAE,IAAI;;AAGZ,qDAAqD;AACrD,2BAaC;EAZC,EAAG;IACD,iBAAiB,EAAE,eAAe;IAClC,SAAS,EAAE,eAAe;EAE5B,GAAI;IACF,iBAAiB,EAAE,eAAe;IAClC,SAAS,EAAE,eAAe;EAE5B,IAAK;IACH,iBAAiB,EAAE,eAAe;IAClC,SAAS,EAAE,eAAe;AAG9B,mBAaC;EAZC,EAAG;IACD,iBAAiB,EAAE,eAAe;IAClC,SAAS,EAAE,eAAe;EAE5B,GAAI;IACF,iBAAiB,EAAE,eAAe;IAClC,SAAS,EAAE,eAAe;EAE5B,IAAK;IACH,iBAAiB,EAAE,eAAe;IAClC,SAAS,EAAE,eAAe;AAG9B,gCAKC;EAJC,IAAK;IACH,iBAAiB,EAAE,eAAe;IAClC,SAAS,EAAE,eAAe;AAG9B,wBAKC;EAJC,IAAK;IACH,iBAAiB,EAAE,eAAe;IAClC,SAAS,EAAE,eAAe;AAG9B,gDAAU;EACR,OAAO,EAAE,YAAY;EACrB,cAAc,EAAE,MAAM;EACtB,iBAAiB,EAAE,8BAA8B;EACjD,SAAS,EAAE,8BAA8B;EACzC,UAAU,EAAE,mBAAmB;;AAEjC,uKAAmD;EACjD,sBAAsB,EAAE,uBAAuB;EAC/C,cAAc,EAAE,uBAAuB;EACvC,0BAA0B,EAAE,SAAS;EACrC,kBAAkB,EAAE,SAAS;EAC7B,uBAAuB,EAAE,OAAO;EAChC,eAAe,EAAE,OAAO;EACxB,iCAAiC,EAAE,qBAAqB;EACxD,yBAAyB,EAAE,qBAAqB;EAChD,iCAAiC,EAAE,WAAW;EAC9C,yBAAyB,EAAE,WAAW;EACtC,2BAA2B,EAAE,QAAQ;EACrC,mBAAmB,EAAE,QAAQ;EAC7B,2BAA2B,EAAE,iBAAiB;EAC9C,mBAAmB,EAAE,iBAAiB;;AAGxC,+EAAW;EACT,MAAM,EAAE,MAAM;EACd,SAAS,EAAE,OAAO;EAClB,OAAO,EAAE,QAAQ;EACjB,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,IAAI;;AAGb,mTAAK;EACJ,OAAO,EAAE,CAAC;EACT,KAAK,EAAE,IAAI;;AAGb,8CAAa;EACZ,SAAS,EAAE,OAAO;;AAGnB,0GAAU;EACR,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,GAAG;EACZ,OAAO,EAAE,KAAK;;AAGhB,wIAAI;EACF,KAAK,EAAE,IAAI;;AAGb,wIAAI;EACF,KAAK,EAAE,KAAK;;AAGd,wIAAK;EACJ,KAAK,EAAE,GAAG;;AAOX,8CAAQ;EACN,MAAM,EAAE,MAAM;;AAGhB,gDAAU;EAGR,MAAM,EAAE,iBAAiB;EACzB,aAAa,EAAE,GAAG;EACnB,OAAO,EAAE,QAAQ;EACjB,eAAe,EAAE,IAAI;EACrB,UAAU,EAAE,uBAAuB;EACnC,KAAK,EAAE,OAAO;EAMd,uDAAS;IACR,gBAAgB,EAAE,OAAO;;AAazB,8CAAqB;EAIpB,gBAAgB,EAAE,OAAO;EACzB,KAAK,EAAE,OAAO;EACd,OAAO,EAAE,SAAS;EAClB,SAAS,EAAE,KAAK;EAEhB,gDAAE;IACD,KAAK,EAAE,OAAO;IAEd,sDAAQ;MACP,KAAK,EAAE,OAAO;AAiBf,8CAAqB;EAMnB,UAAU,EAAE,MAAM;EACrB,aAAa,EAAE,IAAI;EAEnB,mDAAK;IACJ,SAAS,EAAE,MAAM;IACjB,aAAa,EAAE,GAAG;EAGhB,mEAAqB;IAGvB,UAAU,EAAE,IAAI;IAChB,aAAa,EAAE,IAAI;IAEf,wFAAqB;MACxB,OAAO,EAAE,YAAY;MACrB,YAAY,EAAE,IAAI;IAGf,wFAAqB;MACxB,OAAO,EAAE,YAAY;EAIvB,sDAAQ;IACP,OAAO,EAAE,KAAK;AAId,8CAAqB;EAGnB,UAAU,EAAE,MAAM;AAgBpB,wEAAK;EACJ,YAAY,EAAE,OAAO;AAMzB,yBAAqB;EAGpB,QAAQ,EAAE,QAAQ;EAChB,KAAK,EAAE,CAAC;EACV,MAAM,EAAE,CAAC;EACT,IAAI,EAAE,CAAC;EAEP,8CAAqB;IAEpB,OAAO,EAAE,QAAQ;IACjB,UAAU,EAAE,iBAAiB;IAE7B,qDAAO;MACN,SAAS,EAAE,KAAK;MAChB,MAAM,EAAE,CAAC;MACT,OAAO,EAAE,CAAC;;AAMd,gDAAkD;EAEhD,yBAAqB;IACpB,QAAQ,EAAE,QAAQ;AAKrB,gDAAkD;EAEhD,yBAAqB;IACpB,KAAK,EAAE,KAAK;IACZ,SAAS,EAAE,KAAK;IAChB,OAAO,EAAE,CAAC;EAKT,mDAAK;IACJ,UAAU,EAAE,MAAM;EAGnB,mEAAqB;IACpB,KAAK,EAAE,IAAI;EAGZ,mEAAqB;IACpB,KAAK,EAAE,IAAI;EAKd,yBAAqB;IACpB,KAAK,EAAE,KAAK;IACZ,SAAS,EAAE,KAAK;IAChB,OAAO,EAAE,CAAC;IACV,QAAQ,EAAE,QAAQ;IAElB,8CAAqB;MACpB,YAAY,EAAE,IAAI", 4 | "sources": ["../scss/main.scss"], 5 | "names": [], 6 | "file": "main.css" 7 | } -------------------------------------------------------------------------------- /website/resources/images/Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesse-c/AutoVolume/3b5ec23a2f4dd6146673c01fa399262a636f94a3/website/resources/images/Screenshot.png -------------------------------------------------------------------------------- /website/resources/images/Screenshot@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesse-c/AutoVolume/3b5ec23a2f4dd6146673c01fa399262a636f94a3/website/resources/images/Screenshot@2x.png -------------------------------------------------------------------------------- /website/resources/images/avoid-this-happening.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesse-c/AutoVolume/3b5ec23a2f4dd6146673c01fa399262a636f94a3/website/resources/images/avoid-this-happening.gif -------------------------------------------------------------------------------- /website/resources/scss/main.scss: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | font-size: 62.5%; 4 | } 5 | 6 | *, 7 | *:after, 8 | *:before { 9 | box-sizing: inherit; 10 | } 11 | 12 | body { 13 | margin: 0; 14 | font-size: 1.4em; 15 | letter-spacing: .01em; 16 | line-height: 1.6; 17 | font-family: 18 | -apple-system, 19 | BlinkMacSystemFont, 20 | 'Segoe UI', 21 | 'Roboto', 22 | 'Helvetica Neue', 23 | Helvetica, 24 | sans-serif; 25 | color: #111; 26 | background-color: #fff; 27 | } 28 | 29 | img { 30 | max-width: 100%; 31 | height: auto; 32 | } 33 | 34 | svg { 35 | max-height: 100%; 36 | } 37 | 38 | h1, h2, h3, 39 | h4, h5, h6 { 40 | font-weight: 600; 41 | line-height: 1.25; 42 | margin-top: 1em; 43 | margin-bottom: .5em; 44 | } 45 | 46 | h1 { font-size: 2rem } 47 | h2 { font-size: 1.5rem } 48 | h3 { font-size: 1.25rem } 49 | h4 { font-size: 1rem } 50 | h5 { font-size: .875rem } 51 | h6 { font-size: .75rem } 52 | 53 | p, ul, small { 54 | margin-top: 1em; 55 | margin-bottom: 1em; 56 | } 57 | 58 | a { 59 | color: #0068F7; 60 | outline-width: 0; 61 | cursor: pointer; 62 | } 63 | 64 | hr { 65 | box-sizing: content-box; 66 | height: 0; 67 | overflow: visible; 68 | margin-top: 2.0em; 69 | margin-bottom: 2.0em; 70 | border: 0; 71 | border-bottom-width: 1px; 72 | border-bottom-style: solid; 73 | border-bottom-color: #ccc; 74 | width: 100%; 75 | } 76 | 77 | /* Hang (Credit: https://ianlunn.github.io/Hover/) */ 78 | @-webkit-keyframes hvr-hang { 79 | 0% { 80 | -webkit-transform: translateY(8px); 81 | transform: translateY(8px); 82 | } 83 | 50% { 84 | -webkit-transform: translateY(4px); 85 | transform: translateY(4px); 86 | } 87 | 100% { 88 | -webkit-transform: translateY(8px); 89 | transform: translateY(8px); 90 | } 91 | } 92 | @keyframes hvr-hang { 93 | 0% { 94 | -webkit-transform: translateY(8px); 95 | transform: translateY(8px); 96 | } 97 | 50% { 98 | -webkit-transform: translateY(4px); 99 | transform: translateY(4px); 100 | } 101 | 100% { 102 | -webkit-transform: translateY(8px); 103 | transform: translateY(8px); 104 | } 105 | } 106 | @-webkit-keyframes hvr-hang-sink { 107 | 100% { 108 | -webkit-transform: translateY(8px); 109 | transform: translateY(8px); 110 | } 111 | } 112 | @keyframes hvr-hang-sink { 113 | 100% { 114 | -webkit-transform: translateY(8px); 115 | transform: translateY(8px); 116 | } 117 | } 118 | %hvr-hang { 119 | display: inline-block; 120 | vertical-align: middle; 121 | -webkit-transform: perspective(1px) translateZ(0); 122 | transform: perspective(1px) translateZ(0); 123 | box-shadow: 0 0 1px transparent; 124 | } 125 | %hvr-hang:hover, %hvr-hang:focus, %hvr-hang:active { 126 | -webkit-animation-name: hvr-hang-sink, hvr-hang; 127 | animation-name: hvr-hang-sink, hvr-hang; 128 | -webkit-animation-duration: .3s, 1.5s; 129 | animation-duration: .3s, 1.5s; 130 | -webkit-animation-delay: 0s, .3s; 131 | animation-delay: 0s, .3s; 132 | -webkit-animation-timing-function: ease-out, ease-in-out; 133 | animation-timing-function: ease-out, ease-in-out; 134 | -webkit-animation-iteration-count: 1, infinite; 135 | animation-iteration-count: 1, infinite; 136 | -webkit-animation-fill-mode: forwards; 137 | animation-fill-mode: forwards; 138 | -webkit-animation-direction: normal, alternate; 139 | animation-direction: normal, alternate; 140 | } 141 | 142 | %container { 143 | margin: 0 auto; 144 | max-width: 70.0rem; 145 | padding: 0 2.0rem; 146 | position: relative; 147 | width: 100%; 148 | } 149 | 150 | %row { 151 | padding: 0; 152 | width: 100%; 153 | } 154 | 155 | %mx-w-medium { 156 | max-width: 35.0rem; 157 | } 158 | 159 | %cf:after { 160 | clear: both; 161 | content: ' '; 162 | display: table; 163 | } 164 | 165 | %fl { 166 | float: left; 167 | } 168 | 169 | %fr { 170 | float: right; 171 | } 172 | 173 | %w50 { 174 | width: 50%; 175 | } 176 | 177 | %w100 { 178 | width: 100%; 179 | } 180 | 181 | %centre { 182 | margin: 0 auto; 183 | } 184 | 185 | %action a { 186 | @extend %hvr-hang; 187 | 188 | border: 1px solid #0068F7; 189 | border-radius: 2px; 190 | padding: 8px 15px; 191 | text-decoration: none; 192 | box-shadow: 3px 3px 0px 0px #0068F7; 193 | color: #0068F7; 194 | 195 | 196 | &:hover { 197 | } 198 | 199 | &:active { 200 | background-color: #0068F7; 201 | } 202 | } 203 | 204 | // --- 205 | // TODO Move comments to the beginning! 206 | 207 | 208 | 209 | body { 210 | > div:nth-of-type(1) { //
div:nth-of-type(1) { // div:nth-of-type(1) { //