├── .gitignore ├── Images ├── 1.png └── 2.png ├── MacReachability.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── MacReachability ├── AppDelegate.swift ├── Application.xib ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── icon-status-item-dark.imageset │ │ ├── Contents.json │ │ ├── icon-status-item-dark.png │ │ └── icon-status-item-dark@2x.png │ └── icon-status-item.imageset │ │ ├── Contents.json │ │ ├── icon-status-item.png │ │ └── icon-status-item@2x.png ├── Info.plist ├── PopoverView.xib ├── PopoverViewController.swift ├── ReachabilityChecker.swift └── Utils.swift ├── README-en.md ├── README.md └── Resources ├── icon-status-item-dark.png ├── icon-status-item-dark@2x.png ├── icon-status-item.png └── icon-status-item@2x.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | -------------------------------------------------------------------------------- /Images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixzii/MacReachability/5f50ec3ee67f0e0838ca42d54b529f35651d9de1/Images/1.png -------------------------------------------------------------------------------- /Images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixzii/MacReachability/5f50ec3ee67f0e0838ca42d54b529f35651d9de1/Images/2.png -------------------------------------------------------------------------------- /MacReachability.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9D3375C31CE98677008FE0AF /* PopoverView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9D3375C21CE98677008FE0AF /* PopoverView.xib */; }; 11 | 9D3375C51CE98CD5008FE0AF /* PopoverViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D3375C41CE98CD5008FE0AF /* PopoverViewController.swift */; }; 12 | 9D4257DB1CE8414500C74B50 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D4257DA1CE8414500C74B50 /* AppDelegate.swift */; }; 13 | 9D4257DF1CE8414500C74B50 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9D4257DE1CE8414500C74B50 /* Assets.xcassets */; }; 14 | 9D4257EC1CE847FF00C74B50 /* ReachabilityChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D4257EB1CE847FF00C74B50 /* ReachabilityChecker.swift */; }; 15 | 9D4257EE1CE8494100C74B50 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D4257ED1CE8494100C74B50 /* Utils.swift */; }; 16 | 9DE1BAC31CE983F1005959DE /* Application.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9DE1BAC21CE983F1005959DE /* Application.xib */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | 9D3375C21CE98677008FE0AF /* PopoverView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PopoverView.xib; sourceTree = ""; }; 21 | 9D3375C41CE98CD5008FE0AF /* PopoverViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PopoverViewController.swift; sourceTree = ""; }; 22 | 9D4257D71CE8414500C74B50 /* MacReachability.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MacReachability.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 9D4257DA1CE8414500C74B50 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 24 | 9D4257DE1CE8414500C74B50 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 25 | 9D4257E31CE8414500C74B50 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 26 | 9D4257EB1CE847FF00C74B50 /* ReachabilityChecker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReachabilityChecker.swift; sourceTree = ""; }; 27 | 9D4257ED1CE8494100C74B50 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; 28 | 9DE1BAC21CE983F1005959DE /* Application.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = Application.xib; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 9D4257D41CE8414500C74B50 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 9D4257CE1CE8414500C74B50 = { 43 | isa = PBXGroup; 44 | children = ( 45 | 9D4257D91CE8414500C74B50 /* MacReachability */, 46 | 9D4257D81CE8414500C74B50 /* Products */, 47 | ); 48 | sourceTree = ""; 49 | }; 50 | 9D4257D81CE8414500C74B50 /* Products */ = { 51 | isa = PBXGroup; 52 | children = ( 53 | 9D4257D71CE8414500C74B50 /* MacReachability.app */, 54 | ); 55 | name = Products; 56 | sourceTree = ""; 57 | }; 58 | 9D4257D91CE8414500C74B50 /* MacReachability */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 9D4257DA1CE8414500C74B50 /* AppDelegate.swift */, 62 | 9D3375C41CE98CD5008FE0AF /* PopoverViewController.swift */, 63 | 9D4257EB1CE847FF00C74B50 /* ReachabilityChecker.swift */, 64 | 9D4257ED1CE8494100C74B50 /* Utils.swift */, 65 | 9D4257DE1CE8414500C74B50 /* Assets.xcassets */, 66 | 9DE1BAC21CE983F1005959DE /* Application.xib */, 67 | 9D3375C21CE98677008FE0AF /* PopoverView.xib */, 68 | 9D4257E31CE8414500C74B50 /* Info.plist */, 69 | ); 70 | path = MacReachability; 71 | sourceTree = ""; 72 | }; 73 | /* End PBXGroup section */ 74 | 75 | /* Begin PBXNativeTarget section */ 76 | 9D4257D61CE8414500C74B50 /* MacReachability */ = { 77 | isa = PBXNativeTarget; 78 | buildConfigurationList = 9D4257E61CE8414500C74B50 /* Build configuration list for PBXNativeTarget "MacReachability" */; 79 | buildPhases = ( 80 | 9D4257D31CE8414500C74B50 /* Sources */, 81 | 9D4257D41CE8414500C74B50 /* Frameworks */, 82 | 9D4257D51CE8414500C74B50 /* Resources */, 83 | ); 84 | buildRules = ( 85 | ); 86 | dependencies = ( 87 | ); 88 | name = MacReachability; 89 | productName = MacReachability; 90 | productReference = 9D4257D71CE8414500C74B50 /* MacReachability.app */; 91 | productType = "com.apple.product-type.application"; 92 | }; 93 | /* End PBXNativeTarget section */ 94 | 95 | /* Begin PBXProject section */ 96 | 9D4257CF1CE8414500C74B50 /* Project object */ = { 97 | isa = PBXProject; 98 | attributes = { 99 | LastSwiftUpdateCheck = 0730; 100 | LastUpgradeCheck = 0730; 101 | ORGANIZATIONNAME = Cyandev; 102 | TargetAttributes = { 103 | 9D4257D61CE8414500C74B50 = { 104 | CreatedOnToolsVersion = 7.3; 105 | }; 106 | }; 107 | }; 108 | buildConfigurationList = 9D4257D21CE8414500C74B50 /* Build configuration list for PBXProject "MacReachability" */; 109 | compatibilityVersion = "Xcode 3.2"; 110 | developmentRegion = English; 111 | hasScannedForEncodings = 0; 112 | knownRegions = ( 113 | en, 114 | Base, 115 | ); 116 | mainGroup = 9D4257CE1CE8414500C74B50; 117 | productRefGroup = 9D4257D81CE8414500C74B50 /* Products */; 118 | projectDirPath = ""; 119 | projectRoot = ""; 120 | targets = ( 121 | 9D4257D61CE8414500C74B50 /* MacReachability */, 122 | ); 123 | }; 124 | /* End PBXProject section */ 125 | 126 | /* Begin PBXResourcesBuildPhase section */ 127 | 9D4257D51CE8414500C74B50 /* Resources */ = { 128 | isa = PBXResourcesBuildPhase; 129 | buildActionMask = 2147483647; 130 | files = ( 131 | 9D4257DF1CE8414500C74B50 /* Assets.xcassets in Resources */, 132 | 9DE1BAC31CE983F1005959DE /* Application.xib in Resources */, 133 | 9D3375C31CE98677008FE0AF /* PopoverView.xib in Resources */, 134 | ); 135 | runOnlyForDeploymentPostprocessing = 0; 136 | }; 137 | /* End PBXResourcesBuildPhase section */ 138 | 139 | /* Begin PBXSourcesBuildPhase section */ 140 | 9D4257D31CE8414500C74B50 /* Sources */ = { 141 | isa = PBXSourcesBuildPhase; 142 | buildActionMask = 2147483647; 143 | files = ( 144 | 9D3375C51CE98CD5008FE0AF /* PopoverViewController.swift in Sources */, 145 | 9D4257EE1CE8494100C74B50 /* Utils.swift in Sources */, 146 | 9D4257EC1CE847FF00C74B50 /* ReachabilityChecker.swift in Sources */, 147 | 9D4257DB1CE8414500C74B50 /* AppDelegate.swift in Sources */, 148 | ); 149 | runOnlyForDeploymentPostprocessing = 0; 150 | }; 151 | /* End PBXSourcesBuildPhase section */ 152 | 153 | /* Begin XCBuildConfiguration section */ 154 | 9D4257E41CE8414500C74B50 /* Debug */ = { 155 | isa = XCBuildConfiguration; 156 | buildSettings = { 157 | ALWAYS_SEARCH_USER_PATHS = NO; 158 | CLANG_ANALYZER_NONNULL = YES; 159 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 160 | CLANG_CXX_LIBRARY = "libc++"; 161 | CLANG_ENABLE_MODULES = YES; 162 | CLANG_ENABLE_OBJC_ARC = YES; 163 | CLANG_WARN_BOOL_CONVERSION = YES; 164 | CLANG_WARN_CONSTANT_CONVERSION = YES; 165 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 166 | CLANG_WARN_EMPTY_BODY = YES; 167 | CLANG_WARN_ENUM_CONVERSION = YES; 168 | CLANG_WARN_INT_CONVERSION = YES; 169 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 170 | CLANG_WARN_UNREACHABLE_CODE = YES; 171 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 172 | CODE_SIGN_IDENTITY = "-"; 173 | COPY_PHASE_STRIP = NO; 174 | DEBUG_INFORMATION_FORMAT = dwarf; 175 | ENABLE_STRICT_OBJC_MSGSEND = YES; 176 | ENABLE_TESTABILITY = YES; 177 | GCC_C_LANGUAGE_STANDARD = gnu99; 178 | GCC_DYNAMIC_NO_PIC = NO; 179 | GCC_NO_COMMON_BLOCKS = YES; 180 | GCC_OPTIMIZATION_LEVEL = 0; 181 | GCC_PREPROCESSOR_DEFINITIONS = ( 182 | "DEBUG=1", 183 | "$(inherited)", 184 | ); 185 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 186 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 187 | GCC_WARN_UNDECLARED_SELECTOR = YES; 188 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 189 | GCC_WARN_UNUSED_FUNCTION = YES; 190 | GCC_WARN_UNUSED_VARIABLE = YES; 191 | MACOSX_DEPLOYMENT_TARGET = 10.11; 192 | MTL_ENABLE_DEBUG_INFO = YES; 193 | ONLY_ACTIVE_ARCH = YES; 194 | SDKROOT = macosx; 195 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 196 | }; 197 | name = Debug; 198 | }; 199 | 9D4257E51CE8414500C74B50 /* Release */ = { 200 | isa = XCBuildConfiguration; 201 | buildSettings = { 202 | ALWAYS_SEARCH_USER_PATHS = NO; 203 | CLANG_ANALYZER_NONNULL = YES; 204 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 205 | CLANG_CXX_LIBRARY = "libc++"; 206 | CLANG_ENABLE_MODULES = YES; 207 | CLANG_ENABLE_OBJC_ARC = YES; 208 | CLANG_WARN_BOOL_CONVERSION = YES; 209 | CLANG_WARN_CONSTANT_CONVERSION = YES; 210 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 211 | CLANG_WARN_EMPTY_BODY = YES; 212 | CLANG_WARN_ENUM_CONVERSION = YES; 213 | CLANG_WARN_INT_CONVERSION = YES; 214 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 215 | CLANG_WARN_UNREACHABLE_CODE = YES; 216 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 217 | CODE_SIGN_IDENTITY = "-"; 218 | COPY_PHASE_STRIP = NO; 219 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 220 | ENABLE_NS_ASSERTIONS = NO; 221 | ENABLE_STRICT_OBJC_MSGSEND = YES; 222 | GCC_C_LANGUAGE_STANDARD = gnu99; 223 | GCC_NO_COMMON_BLOCKS = YES; 224 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 225 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 226 | GCC_WARN_UNDECLARED_SELECTOR = YES; 227 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 228 | GCC_WARN_UNUSED_FUNCTION = YES; 229 | GCC_WARN_UNUSED_VARIABLE = YES; 230 | MACOSX_DEPLOYMENT_TARGET = 10.11; 231 | MTL_ENABLE_DEBUG_INFO = NO; 232 | SDKROOT = macosx; 233 | }; 234 | name = Release; 235 | }; 236 | 9D4257E71CE8414500C74B50 /* Debug */ = { 237 | isa = XCBuildConfiguration; 238 | buildSettings = { 239 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 240 | COMBINE_HIDPI_IMAGES = YES; 241 | INFOPLIST_FILE = MacReachability/Info.plist; 242 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 243 | PRODUCT_BUNDLE_IDENTIFIER = com.cyandev.MacReachability; 244 | PRODUCT_NAME = "$(TARGET_NAME)"; 245 | }; 246 | name = Debug; 247 | }; 248 | 9D4257E81CE8414500C74B50 /* Release */ = { 249 | isa = XCBuildConfiguration; 250 | buildSettings = { 251 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 252 | COMBINE_HIDPI_IMAGES = YES; 253 | INFOPLIST_FILE = MacReachability/Info.plist; 254 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 255 | PRODUCT_BUNDLE_IDENTIFIER = com.cyandev.MacReachability; 256 | PRODUCT_NAME = "$(TARGET_NAME)"; 257 | }; 258 | name = Release; 259 | }; 260 | /* End XCBuildConfiguration section */ 261 | 262 | /* Begin XCConfigurationList section */ 263 | 9D4257D21CE8414500C74B50 /* Build configuration list for PBXProject "MacReachability" */ = { 264 | isa = XCConfigurationList; 265 | buildConfigurations = ( 266 | 9D4257E41CE8414500C74B50 /* Debug */, 267 | 9D4257E51CE8414500C74B50 /* Release */, 268 | ); 269 | defaultConfigurationIsVisible = 0; 270 | defaultConfigurationName = Release; 271 | }; 272 | 9D4257E61CE8414500C74B50 /* Build configuration list for PBXNativeTarget "MacReachability" */ = { 273 | isa = XCConfigurationList; 274 | buildConfigurations = ( 275 | 9D4257E71CE8414500C74B50 /* Debug */, 276 | 9D4257E81CE8414500C74B50 /* Release */, 277 | ); 278 | defaultConfigurationIsVisible = 0; 279 | defaultConfigurationName = Release; 280 | }; 281 | /* End XCConfigurationList section */ 282 | }; 283 | rootObject = 9D4257CF1CE8414500C74B50 /* Project object */; 284 | } 285 | -------------------------------------------------------------------------------- /MacReachability.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MacReachability/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // MacReachability 4 | // 5 | // Created by 杨弘宇 on 16/5/15. 6 | // Copyright © 2016年 Cyandev. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | var popover: NSPopover! 15 | var statusItem: NSStatusItem! 16 | 17 | var eventMonitor: AnyObject? 18 | 19 | func applicationDidFinishLaunching(aNotification: NSNotification) { 20 | NSApp.setActivationPolicy(.Accessory) 21 | 22 | NSDistributedNotificationCenter.defaultCenter().addObserver(self, selector: #selector(makeStatusItem), name: "AppleInterfaceThemeChangedNotification", object: nil) 23 | 24 | popover = NSPopover() 25 | popover.contentViewController = PopoverViewController(nibName: "PopoverView", bundle: nil) 26 | 27 | makeStatusItem() 28 | } 29 | 30 | func applicationWillTerminate(notification: NSNotification) { 31 | NSStatusBar.systemStatusBar().removeStatusItem(statusItem) 32 | statusItem = nil 33 | } 34 | 35 | func makeStatusItem() { 36 | if statusItem == nil { 37 | statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSVariableStatusItemLength) 38 | statusItem.button?.action = #selector(showPopover) 39 | } 40 | 41 | let style = NSUserDefaults.standardUserDefaults().stringForKey("AppleInterfaceStyle") 42 | let iconName = style == "Dark" ? "icon-status-item" : "icon-status-item-dark" 43 | 44 | statusItem.button?.image = NSImage(named: iconName) 45 | statusItem.button?.alternateImage = NSImage(named: iconName) 46 | } 47 | 48 | func showPopover() { 49 | if popover.shown { 50 | hidePopover() 51 | return 52 | } 53 | 54 | if let button = statusItem.button { 55 | popover.showRelativeToRect(button.frame, ofView: button, preferredEdge: .MinY) 56 | 57 | eventMonitor = NSEvent.addGlobalMonitorForEventsMatchingMask([.LeftMouseDownMask, .RightMouseDownMask]) { event in 58 | self.hidePopover() 59 | } 60 | } 61 | } 62 | 63 | func hidePopover() { 64 | if popover.shown { 65 | popover.close() 66 | 67 | if self.eventMonitor != nil { 68 | NSEvent.removeMonitor(self.eventMonitor!) 69 | self.eventMonitor = nil 70 | } 71 | } 72 | } 73 | 74 | } 75 | 76 | -------------------------------------------------------------------------------- /MacReachability/Application.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /MacReachability/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 | } -------------------------------------------------------------------------------- /MacReachability/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /MacReachability/Assets.xcassets/icon-status-item-dark.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon-status-item-dark.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icon-status-item-dark@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /MacReachability/Assets.xcassets/icon-status-item-dark.imageset/icon-status-item-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixzii/MacReachability/5f50ec3ee67f0e0838ca42d54b529f35651d9de1/MacReachability/Assets.xcassets/icon-status-item-dark.imageset/icon-status-item-dark.png -------------------------------------------------------------------------------- /MacReachability/Assets.xcassets/icon-status-item-dark.imageset/icon-status-item-dark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixzii/MacReachability/5f50ec3ee67f0e0838ca42d54b529f35651d9de1/MacReachability/Assets.xcassets/icon-status-item-dark.imageset/icon-status-item-dark@2x.png -------------------------------------------------------------------------------- /MacReachability/Assets.xcassets/icon-status-item.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon-status-item.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icon-status-item@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /MacReachability/Assets.xcassets/icon-status-item.imageset/icon-status-item.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixzii/MacReachability/5f50ec3ee67f0e0838ca42d54b529f35651d9de1/MacReachability/Assets.xcassets/icon-status-item.imageset/icon-status-item.png -------------------------------------------------------------------------------- /MacReachability/Assets.xcassets/icon-status-item.imageset/icon-status-item@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixzii/MacReachability/5f50ec3ee67f0e0838ca42d54b529f35651d9de1/MacReachability/Assets.xcassets/icon-status-item.imageset/icon-status-item@2x.png -------------------------------------------------------------------------------- /MacReachability/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 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | Copyright © 2016年 Cyandev. All rights reserved. 29 | NSMainNibFile 30 | Application 31 | LSUIElement 32 | 33 | NSPrincipalClass 34 | NSApplication 35 | 36 | 37 | -------------------------------------------------------------------------------- /MacReachability/PopoverView.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 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /MacReachability/PopoverViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopoverViewController.swift 3 | // MacReachability 4 | // 5 | // Created by 杨弘宇 on 16/5/16. 6 | // Copyright © 2016年 Cyandev. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class PopoverViewController: NSViewController { 12 | 13 | @IBOutlet weak var baiduStatus: NSTextField! 14 | @IBOutlet weak var googleStatus: NSTextField! 15 | @IBOutlet weak var progressIndicatior: NSProgressIndicator! 16 | 17 | var baiduChecker: ReachabilityChecker! 18 | var googleChecker: ReachabilityChecker! 19 | 20 | override func viewDidLoad() { 21 | super.viewDidLoad() 22 | 23 | baiduChecker = ReachabilityChecker(URLString: "https://www.baidu.com/", observer: makeObserverWithStatusLabel(baiduStatus)) 24 | googleChecker = ReachabilityChecker(URLString: "https://www.google.com/", observer: makeObserverWithStatusLabel(googleStatus)) 25 | } 26 | 27 | override func viewWillAppear() { 28 | super.viewWillAppear() 29 | 30 | progressIndicatior.startAnimation(self) 31 | 32 | baiduChecker.start() 33 | googleChecker.start() 34 | } 35 | 36 | override func viewWillDisappear() { 37 | super.viewWillDisappear() 38 | 39 | baiduChecker.stop() 40 | googleChecker.stop() 41 | } 42 | 43 | @IBAction func quitButtonDidClick(sender: AnyObject) { 44 | NSApp.terminate(sender) 45 | } 46 | 47 | func makeObserverWithStatusLabel(statusLabel: NSTextField) -> ((ReachabilityCheckerStatus) -> Void) { 48 | return { status in 49 | statusLabel.hidden = false 50 | 51 | switch status { 52 | case .Succeed: 53 | statusLabel.stringValue = "Connectable" 54 | break 55 | case .Failed: 56 | statusLabel.stringValue = "Not Connectable" 57 | break 58 | case .Pending: 59 | statusLabel.stringValue = "Pending..." 60 | break 61 | default: 62 | statusLabel.hidden = true 63 | } 64 | 65 | if !self.baiduChecker.running && !self.googleChecker.running { 66 | self.progressIndicatior.stopAnimation(nil) 67 | } 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /MacReachability/ReachabilityChecker.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReachabilityChecker.swift 3 | // MacReachability 4 | // 5 | // Created by 杨弘宇 on 16/5/15. 6 | // Copyright © 2016年 Cyandev. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | enum ReachabilityCheckerStatus { 12 | case Pending 13 | case Failed 14 | case Succeed 15 | case Cancelled 16 | } 17 | 18 | 19 | class ReachabilityChecker: NSObject { 20 | 21 | var URLString: String 22 | var observer: (ReachabilityCheckerStatus) -> Void 23 | var task: NSURLSessionTask? 24 | 25 | var running: Bool { 26 | return task != nil 27 | } 28 | 29 | init(URLString: String, observer: (ReachabilityCheckerStatus) -> Void) { 30 | self.URLString = URLString 31 | self.observer = observer 32 | 33 | super.init() 34 | } 35 | 36 | func start() { 37 | task?.cancel() 38 | 39 | let configuration = NSURLSessionConfiguration.defaultSessionConfiguration() 40 | configuration.timeoutIntervalForRequest = 5.0 41 | let session = NSURLSession(configuration: configuration) 42 | task = session.dataTaskWithURL(NSURL(string: URLString)!) { (data, response, error) in 43 | dispatch_async(dispatch_get_main_queue()) { 44 | self.task = nil 45 | 46 | if (response as? NSHTTPURLResponse)?.statusCode == 200 { 47 | self.observer(.Succeed) 48 | } else { 49 | self.observer(.Failed) 50 | } 51 | } 52 | } 53 | 54 | task?.resume() 55 | 56 | self.observer(.Pending) 57 | } 58 | 59 | func stop() { 60 | task?.cancel() 61 | task = nil 62 | 63 | self.observer(.Cancelled) 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /MacReachability/Utils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Utils.swift 3 | // MacReachability 4 | // 5 | // Created by 杨弘宇 on 16/5/15. 6 | // Copyright © 2016年 Cyandev. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | typealias Cancellable = () -> Void 12 | 13 | func delay(seconds secs: Double, block: () -> Void) -> Cancellable { 14 | var cancelled = false 15 | 16 | let time = dispatch_time(DISPATCH_TIME_NOW, Int64(Double(NSEC_PER_SEC) * secs)) 17 | dispatch_after(time, dispatch_get_main_queue()) { 18 | if !cancelled { 19 | block() 20 | } 21 | } 22 | 23 | return { 24 | cancelled = true 25 | } 26 | } 27 | 28 | func delayWithoutCancellable(seconds secs: Double, block: () -> Void) { 29 | let _ = delay(seconds: secs, block: block) 30 | } 31 | 32 | func fade(view: NSView, toVisible visible: Bool) { 33 | NSAnimationContext.beginGrouping() 34 | NSAnimationContext.currentContext().duration = 0.4 35 | view.animator().alphaValue = visible ? 1.0 : 0.0 36 | NSAnimationContext.endGrouping() 37 | } -------------------------------------------------------------------------------- /README-en.md: -------------------------------------------------------------------------------- 1 | # MacReachability 2 | 3 | A status bar tool, which can easily check your network status. 4 | 5 | ## Preface 6 | Actually, if you live in U.S. or whatever, you don't this. Because you will always see the scene below: 7 | 8 | ![](https://raw.githubusercontent.com/unixzii/MacReachability/master/Images/2.png) 9 | 10 | ## Feature 11 | Nothing but check your network status. 12 | 13 | ## Installing / Usage 14 | No need to install, just open it and whenever you want to check your network condition, click its icon on the status bar and it will begin working. 15 | 16 | ## FAQ 17 | 18 | #### 1. What's the fucking repo? 19 | I enjoy it. 20 | #### 2. This question is unavailable in your country. 21 | N / A 22 | #### 3. Why did you write such an easy app instead of writing a script? 23 | I always want to write a Mac app, I just like GUI applications. ╮(╯▽╰)╭ 24 | #### 4. I want autorun feature. 25 | I don't want to maintain this repo anymore, I would appreciate it if you do it, submit a PR please. 26 | 27 | ## License 28 | None. Freely play with it. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [README in English](README-en.md) 2 | 3 | # MacReachability 4 | 5 | 一个状态栏小工具,轻松检测你的网络状态。 6 | 7 | ## 前言 8 | 我们知道,百度是一个非常好用的网络检测工具,但是每次都要打开浏览器,输入 baidu.com 然后等待页面出现,感觉好繁琐。于是我开发了这样一个小工具。 9 | 10 | ![](https://raw.githubusercontent.com/unixzii/MacReachability/master/Images/1.png) 11 | 12 | 没错,正如你所见,为了测试 VPN 是否能正常运作,我还使用了 Google 作为墙外代表,当你启动 VPN 后你会看到: 13 | 14 | ![](https://raw.githubusercontent.com/unixzii/MacReachability/master/Images/2.png) 15 | 16 | ## 功能 17 | 没有任何其他功能,就是检测网络状态。 18 | 19 | ## 安装 / 使用方法 20 | 不需要安装,双击 app 文件,它就出现在你的状态栏了。需要检测时就点一下状态栏图标,它就会弹出图中的气泡。 21 | 22 | ## FAQ 23 | 24 | #### 1. 这是什么项目? 25 | 这是我随便写的,应该还有点用处,大家开心就好。 26 | #### 2. 作者你这是要黑百度吗? 27 | 没错,就是这样。 28 | #### 3. 这么简单的程序写个脚本不就好了嘛? 29 | 其实我一直想做个 Mac app,有图形界面难道不好么 ╮(╯▽╰)╭ 30 | #### 4. 你这 app 还挺好用,我想开机自启呢。 31 | 额,这项目我不想维护了,你如果愿意就帮我写了吧,然后顺便提交个 PR。 32 | 33 | ## 许可 34 | 没有版权,完全开源。 35 | -------------------------------------------------------------------------------- /Resources/icon-status-item-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixzii/MacReachability/5f50ec3ee67f0e0838ca42d54b529f35651d9de1/Resources/icon-status-item-dark.png -------------------------------------------------------------------------------- /Resources/icon-status-item-dark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixzii/MacReachability/5f50ec3ee67f0e0838ca42d54b529f35651d9de1/Resources/icon-status-item-dark@2x.png -------------------------------------------------------------------------------- /Resources/icon-status-item.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixzii/MacReachability/5f50ec3ee67f0e0838ca42d54b529f35651d9de1/Resources/icon-status-item.png -------------------------------------------------------------------------------- /Resources/icon-status-item@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/unixzii/MacReachability/5f50ec3ee67f0e0838ca42d54b529f35651d9de1/Resources/icon-status-item@2x.png --------------------------------------------------------------------------------