├── .gitignore ├── CONTRIBUTING.md ├── EchoSDK.podspec ├── Images ├── echoArch.jpg ├── intro.jpg ├── ios14permission.jpg ├── mockGPS.jpg ├── network.jpg ├── nslog.jpg ├── solution.jpg ├── view.jpg └── view_dark.jpg ├── LICENSE ├── Mac ├── Echo.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── Echo.xcscheme ├── Echo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── 1024.png │ │ │ ├── 128.png │ │ │ ├── 16.png │ │ │ ├── 256-1.png │ │ │ ├── 256.png │ │ │ ├── 32-1.png │ │ │ ├── 32.png │ │ │ ├── 512-1.png │ │ │ ├── 512.png │ │ │ ├── 64.png │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── connect_btn_color.colorset │ │ │ └── Contents.json │ │ ├── connect_btn_ing_color.colorset │ │ │ └── Contents.json │ │ ├── connect_line_color.colorset │ │ │ └── Contents.json │ │ ├── connect_title_color.colorset │ │ │ └── Contents.json │ │ ├── deviceBgColor.colorset │ │ │ └── Contents.json │ │ ├── deviceGuide_arrow.imageset │ │ │ ├── Contents.json │ │ │ ├── 新手引导箭头-1.png │ │ │ ├── 新手引导箭头-2.png │ │ │ └── 新手引导箭头.png │ │ ├── deviceGuide_info.imageset │ │ │ ├── Contents.json │ │ │ ├── 新手引导-1.png │ │ │ ├── 新手引导-2.png │ │ │ └── 新手引导.png │ │ ├── deviceTop.imageset │ │ │ ├── Contents.json │ │ │ ├── LOGO信息_white-1.png │ │ │ ├── LOGO信息_white.png │ │ │ └── LOGO组.png │ │ ├── device_authed.imageset │ │ │ ├── Contents.json │ │ │ ├── 设备选中态-1.png │ │ │ ├── 设备选中态-2.png │ │ │ └── 设备选中态.png │ │ ├── device_connect_tip.imageset │ │ │ ├── Contents.json │ │ │ └── 图片.png │ │ ├── device_connected.imageset │ │ │ ├── Contents.json │ │ │ ├── 连接.png │ │ │ ├── 连接未选中态-1.png │ │ │ └── 连接未选中态.png │ │ ├── device_disConnected.imageset │ │ │ ├── Contents.json │ │ │ ├── 未连接-1.png │ │ │ ├── 未连接-2.png │ │ │ └── 未连接.png │ │ ├── device_unAuthed.imageset │ │ │ ├── Contents.json │ │ │ ├── 设备未选中态-1.png │ │ │ ├── 设备未选中态-2.png │ │ │ └── 设备未选中态.png │ │ ├── dot_default.colorset │ │ │ └── Contents.json │ │ ├── dot_red.colorset │ │ │ └── Contents.json │ │ ├── icon_arrow_down.imageset │ │ │ ├── Contents.json │ │ │ ├── 向下-1.png │ │ │ ├── 向下-2.png │ │ │ └── 向下.png │ │ ├── icon_arrow_up.imageset │ │ │ ├── Contents.json │ │ │ ├── 向上-1.png │ │ │ ├── 向上-2.png │ │ │ └── 向上.png │ │ ├── listDetail_cellSelection.colorset │ │ │ └── Contents.json │ │ ├── listDetail_delete.imageset │ │ │ ├── Contents.json │ │ │ ├── 删除-1.png │ │ │ └── 删除.png │ │ ├── listDetail_header.colorset │ │ │ └── Contents.json │ │ ├── listDetail_headerTitle.colorset │ │ │ └── Contents.json │ │ ├── listDetail_line.colorset │ │ │ └── Contents.json │ │ ├── listDetail_searchBg.colorset │ │ │ └── Contents.json │ │ ├── listDetail_text.colorset │ │ │ └── Contents.json │ │ ├── network_switch_color.colorset │ │ │ └── Contents.json │ │ ├── normalArrow.imageset │ │ │ ├── Contents.json │ │ │ └── bts_homepage_button@3x.png │ │ ├── outline_refresh.imageset │ │ │ ├── Contents.json │ │ │ ├── 刷新.png │ │ │ └── 刷新1.png │ │ ├── pluginBgColor.colorset │ │ │ └── Contents.json │ │ ├── pluginList_selected.colorset │ │ │ └── Contents.json │ │ ├── plugin_icon_default.imageset │ │ │ ├── Contents.json │ │ │ ├── 其他未选中态-1.png │ │ │ ├── 其他未选中态-2.png │ │ │ └── 其他未选中态.png │ │ ├── plugin_icon_selected.imageset │ │ │ ├── Contents.json │ │ │ ├── 其他选中态-1.png │ │ │ ├── 其他选中态-2.png │ │ │ └── 其他选中态.png │ │ ├── plugin_network_default.imageset │ │ │ ├── Contents.json │ │ │ ├── 网络请求未选中态-1.png │ │ │ ├── 网络请求未选中态-2.png │ │ │ └── 网络请求未选中态.png │ │ ├── plugin_network_selected.imageset │ │ │ ├── Contents.json │ │ │ ├── 网络请求选中态-1.png │ │ │ ├── 网络请求选中态-2.png │ │ │ └── 网络请求选中态.png │ │ ├── selectedArrow.imageset │ │ │ ├── Contents.json │ │ │ └── bts_homepage_button@3x 2.png │ │ ├── text_black.colorset │ │ │ └── Contents.json │ │ ├── text_gray.colorset │ │ │ └── Contents.json │ │ ├── text_lightBlack.colorset │ │ │ └── Contents.json │ │ ├── text_lightGray.colorset │ │ │ └── Contents.json │ │ ├── viewList_line_color.colorset │ │ │ └── Contents.json │ │ ├── viewList_text_color.colorset │ │ │ └── Contents.json │ │ ├── viewScene_bg_color.colorset │ │ │ └── Contents.json │ │ ├── view_hierarchy_color.colorset │ │ │ └── Contents.json │ │ ├── view_info_bg_color.colorset │ │ │ └── Contents.json │ │ ├── view_info_cell_color.colorset │ │ │ └── Contents.json │ │ ├── view_menu_color.colorset │ │ │ └── Contents.json │ │ ├── view_menu_refresh.imageset │ │ │ ├── Contents.json │ │ │ ├── 刷新-1.png │ │ │ ├── 刷新.png │ │ │ └── 刷新2.png │ │ └── view_menu_reset.imageset │ │ │ ├── Contents.json │ │ │ ├── 重置-1.png │ │ │ ├── 重置-2.png │ │ │ └── 重置.png │ ├── Base.lproj │ │ └── Main.storyboard │ ├── Echo.entitlements │ ├── Info.plist │ ├── Models │ │ ├── ECODeviceModel.h │ │ ├── ECODeviceModel.m │ │ ├── ECOPacketsDispatcher.h │ │ ├── ECOPacketsDispatcher.m │ │ ├── ECOPluginModel.h │ │ ├── ECOPluginModel.m │ │ ├── ECOProjectModel.h │ │ └── ECOProjectModel.m │ ├── Plugins │ │ ├── Basic │ │ │ └── Network │ │ │ │ ├── ECONetworkDetailViewController.h │ │ │ │ ├── ECONetworkDetailViewController.m │ │ │ │ ├── ECONetworkDetailViewController.storyboard │ │ │ │ ├── ECONetworkJSONViewController.h │ │ │ │ ├── ECONetworkJSONViewController.m │ │ │ │ ├── ECONetworkKeyValueListViewController.h │ │ │ │ ├── ECONetworkKeyValueListViewController.m │ │ │ │ ├── ECONetworkListTableCellView.h │ │ │ │ ├── ECONetworkListTableCellView.m │ │ │ │ ├── ECONetworkOverviewViewController.h │ │ │ │ ├── ECONetworkOverviewViewController.m │ │ │ │ ├── ECONetworkRequestViewController.h │ │ │ │ ├── ECONetworkRequestViewController.m │ │ │ │ ├── ECONetworkResponseViewController.h │ │ │ │ ├── ECONetworkResponseViewController.m │ │ │ │ ├── ECONetworkScrollTextViewController.h │ │ │ │ ├── ECONetworkScrollTextViewController.m │ │ │ │ ├── ECONetworkViewController.h │ │ │ │ ├── ECONetworkViewController.m │ │ │ │ └── ECONetworkViewController.xib │ │ ├── ECOPluginUIProtocol.h │ │ ├── Performance │ │ │ └── performance.md │ │ └── UI │ │ │ └── ViewHierarchy │ │ │ ├── ECOSceneView.h │ │ │ ├── ECOSceneView.m │ │ │ ├── ECOSelectableTextView.h │ │ │ ├── ECOSelectableTextView.m │ │ │ ├── ECOViewHierarchyContentViewController.storyboard │ │ │ ├── ECOViewHierarchyInfoViewController.h │ │ │ ├── ECOViewHierarchyInfoViewController.m │ │ │ ├── ECOViewHierarchyListViewController.h │ │ │ ├── ECOViewHierarchyListViewController.m │ │ │ ├── ECOViewHierarchySceneViewController.h │ │ │ ├── ECOViewHierarchySceneViewController.m │ │ │ ├── ECOViewHierarchyViewController.h │ │ │ ├── ECOViewHierarchyViewController.m │ │ │ ├── ECOViewHierarchyViewController.xib │ │ │ ├── cell │ │ │ ├── YVRightCellBase.h │ │ │ ├── YVRightCellBase.m │ │ │ ├── YVRightCellViewClass.h │ │ │ ├── YVRightCellViewClass.m │ │ │ ├── YVRightCellViewClass.xib │ │ │ ├── YVRightCellViewFrame.h │ │ │ ├── YVRightCellViewFrame.m │ │ │ ├── YVRightCellViewFrame.xib │ │ │ ├── YVRightCellViewInfo.h │ │ │ ├── YVRightCellViewInfo.m │ │ │ └── YVRightCellViewInfo.xib │ │ │ ├── defines.h │ │ │ ├── helper │ │ │ ├── SCNNode+YVBorder.h │ │ │ ├── SCNNode+YVBorder.m │ │ │ ├── SCNNode+YVIdentifier.h │ │ │ ├── SCNNode+YVIdentifier.m │ │ │ ├── SCNNode+YVPlane.h │ │ │ ├── SCNNode+YVPlane.m │ │ │ ├── SCNNode+YVSelected.h │ │ │ ├── SCNNode+YVSelected.m │ │ │ ├── SCNNode+YVVisual.h │ │ │ ├── SCNNode+YVVisual.m │ │ │ ├── SCNNode+YVZIndex.h │ │ │ ├── SCNNode+YVZindex.m │ │ │ ├── TravseralContext.h │ │ │ ├── TravseralContext.m │ │ │ ├── YVCGRectHelper.h │ │ │ ├── YVCGRectHelper.m │ │ │ ├── YVDisplayControl.h │ │ │ ├── YVDisplayControl.m │ │ │ ├── YVNodeBackTracking.h │ │ │ └── YVNodeBackTracking.m │ │ │ └── img │ │ │ ├── cellimage_view@2x.png │ │ │ ├── empty.scn │ │ │ ├── left_blue.png │ │ │ ├── left_gray.png │ │ │ ├── refresh.png │ │ │ ├── right_blue.png │ │ │ └── right_gray.png │ ├── Template │ │ ├── H5 │ │ │ ├── ECOTemplateH5ViewController.h │ │ │ ├── ECOTemplateH5ViewController.m │ │ │ ├── ECOTemplateH5ViewController.xib │ │ │ └── echoJS.js │ │ ├── List │ │ │ ├── ECOTemplateListDetailCell.h │ │ │ ├── ECOTemplateListDetailCell.m │ │ │ ├── ECOTemplateListDetailViewController.h │ │ │ ├── ECOTemplateListDetailViewController.m │ │ │ ├── ECOTemplateListDetailViewController.xib │ │ │ ├── ECOTemplateTableHeaderCell.h │ │ │ └── ECOTemplateTableHeaderCell.m │ │ └── Outline │ │ │ ├── ECOOlNode.h │ │ │ ├── ECOOlNode.m │ │ │ ├── ECOOlNodeFactory.h │ │ │ ├── ECOOlNodeFactory.m │ │ │ ├── ECOString.h │ │ │ ├── ECOString.m │ │ │ ├── ECOTemplateOutlineCell.h │ │ │ ├── ECOTemplateOutlineCell.m │ │ │ ├── ECOTemplateOutlineViewController.h │ │ │ ├── ECOTemplateOutlineViewController.m │ │ │ └── ECOTemplateOutlineViewController.xib │ ├── Tools │ │ ├── DarkMode │ │ │ ├── ECODarkModeHelper.h │ │ │ └── ECODarkModeHelper.m │ │ └── Template │ │ │ └── ECOUITemplateMapper.h │ ├── UI │ │ ├── ECOCustomWindowController.h │ │ ├── ECOCustomWindowController.m │ │ ├── ECODeviceConnectView.h │ │ ├── ECODeviceConnectView.m │ │ ├── ECODeviceTableCellView.h │ │ ├── ECODeviceTableCellView.m │ │ ├── ECODevicesListViewController.h │ │ ├── ECODevicesListViewController.m │ │ ├── ECONoTriangleOutlineView.h │ │ ├── ECONoTriangleOutlineView.m │ │ ├── ECOPluginDetailViewController.h │ │ ├── ECOPluginDetailViewController.m │ │ ├── ECOPluginItemsOutlineView.h │ │ ├── ECOPluginItemsOutlineView.m │ │ ├── ECOPluginItemsViewController.h │ │ ├── ECOPluginItemsViewController.m │ │ ├── ECOPluginTableCellView.h │ │ ├── ECOPluginTableCellView.m │ │ ├── ECOSplitView.h │ │ ├── ECOSplitView.m │ │ ├── ECOSplitViewController.h │ │ └── ECOSplitViewController.m │ ├── jsonViewer │ │ ├── jquery.js │ │ ├── json-viewer-dark-theme.css │ │ ├── json-viewer-light-theme.css │ │ ├── json-viewer.js │ │ └── jsonviewer.html │ └── main.m ├── Podfile └── Podfile.lock ├── README.md ├── Sources ├── Client │ ├── ECOClient.h │ ├── ECOClient.m │ ├── ECOClientConfig.h │ ├── ECOClientConfig.m │ └── EchoSDKDefines.h ├── Core │ ├── Access │ │ ├── ECOCoreManager.h │ │ ├── ECOCoreManager.m │ │ ├── ECOPluginsManager.h │ │ └── ECOPluginsManager.m │ ├── Channel │ │ ├── Bonjour │ │ │ ├── ECONetServiceBrowser.h │ │ │ ├── ECONetServiceBrowser.m │ │ │ ├── ECONetServicePublisher.h │ │ │ └── ECONetServicePublisher.m │ │ ├── ECOBaseChannel.h │ │ ├── ECOBaseChannel.m │ │ ├── ECOChannelAppInfo.h │ │ ├── ECOChannelAppInfo.m │ │ ├── ECOChannelDeviceInfo.h │ │ ├── ECOChannelDeviceInfo.m │ │ ├── ECOChannelManager.h │ │ ├── ECOChannelManager.m │ │ ├── ECOSocketChannel.h │ │ ├── ECOSocketChannel.m │ │ ├── ECOUSBChannel.h │ │ ├── ECOUSBChannel.m │ │ └── PeerTalk │ │ │ ├── PTChannel.h │ │ │ ├── PTChannel.m │ │ │ ├── PTPrivate.h │ │ │ ├── PTProtocol.h │ │ │ ├── PTProtocol.m │ │ │ ├── PTUSBHub.h │ │ │ └── PTUSBHub.m │ ├── ECOCoreDefines.h │ ├── Plugin │ │ ├── ECOBasePlugin.h │ │ └── ECOBasePlugin.m │ └── Service │ │ ├── ECOPacketClient.h │ │ └── ECOPacketClient.m ├── Plugins │ ├── Basic │ │ ├── ECOFishhook.c │ │ ├── ECOFishhook.h │ │ ├── ECOSwizzle.h │ │ └── ECOSwizzle.m │ ├── Crash │ │ ├── ECOCrashFileInfo.h │ │ ├── ECOCrashFileInfo.m │ │ ├── ECOCrashFileManager.h │ │ ├── ECOCrashFileManager.m │ │ ├── ECOCrashPlugin.h │ │ ├── ECOCrashPlugin.m │ │ ├── ECOCrashSignalExceptionHandler.h │ │ ├── ECOCrashSignalExceptionHandler.m │ │ ├── ECOCrashUncaughtExceptionHandler.h │ │ └── ECOCrashUncaughtExceptionHandler.m │ ├── GeneralLog │ │ ├── ECOGeneralLogManager.h │ │ ├── ECOGeneralLogManager.m │ │ ├── ECOGeneralLogPlugin.h │ │ └── ECOGeneralLogPlugin.m │ ├── MemoryLeak │ │ ├── ECOMLeaksMessenger.h │ │ ├── ECOMLeaksMessenger.m │ │ ├── ECOMemoryLeakManager.h │ │ ├── ECOMemoryLeakManager.m │ │ ├── ECOMemoryLeakPlugin.h │ │ └── ECOMemoryLeakPlugin.m │ ├── MockGPS │ │ ├── CLLocationManager+ECHO.h │ │ ├── CLLocationManager+ECHO.m │ │ ├── ECOMockGPSManager.h │ │ ├── ECOMockGPSManager.m │ │ ├── ECOMockGPSPlugin.h │ │ └── ECOMockGPSPlugin.m │ ├── NSLog │ │ ├── ECONSLogManager.h │ │ ├── ECONSLogManager.m │ │ ├── ECONSLogPlugin.h │ │ └── ECONSLogPlugin.m │ ├── NSUserDefaults │ │ ├── ECONSUserDefaultsPlugin.h │ │ └── ECONSUserDefaultsPlugin.m │ ├── Network │ │ ├── ECONSURLProtocol.h │ │ ├── ECONSURLProtocol.m │ │ ├── ECONetworkInterceptor.h │ │ ├── ECONetworkInterceptor.m │ │ ├── ECONetworkModel.h │ │ ├── ECONetworkModel.m │ │ ├── ECONetworkPlugin.h │ │ ├── ECONetworkPlugin.m │ │ ├── NSURLSessionConfiguration+ECHO.h │ │ └── NSURLSessionConfiguration+ECHO.m │ ├── Notification │ │ ├── ECONotificationInterceptor.h │ │ ├── ECONotificationInterceptor.m │ │ ├── ECONotificationPlugin.h │ │ └── ECONotificationPlugin.m │ ├── UI │ │ └── ViewHierarchy │ │ │ ├── ECOViewHierarchyPlugin.h │ │ │ ├── ECOViewHierarchyPlugin.m │ │ │ ├── manager │ │ │ ├── YVObjectManager.h │ │ │ └── YVObjectManager.m │ │ │ └── serializer │ │ │ ├── NSObject+YVNodeInfo.h │ │ │ ├── NSObject+YVNodeInfo.m │ │ │ ├── UIView+YVNodeInfo.h │ │ │ ├── UIView+YVNodeInfo.m │ │ │ ├── UIView+YVTraversal.h │ │ │ ├── UIView+YVTraversal.m │ │ │ ├── UIView+YVViewTree.h │ │ │ ├── UIView+YVViewTree.m │ │ │ ├── YVTraversalContext.h │ │ │ ├── YVTraversalContext.m │ │ │ ├── YVTraversalStepin.h │ │ │ └── YVTraversalStepin.m │ ├── ViewBorder │ │ ├── ECOViewBorderInspector.h │ │ ├── ECOViewBorderInspector.m │ │ ├── ECOViewBorderPlugin.h │ │ ├── ECOViewBorderPlugin.m │ │ ├── UIView+ECOViewBorder.h │ │ └── UIView+ECOViewBorder.m │ └── Watchdog │ │ ├── ECOWatchdog.h │ │ ├── ECOWatchdog.m │ │ ├── ECOWatchdogPlugin.h │ │ └── ECOWatchdogPlugin.m └── Resources │ ├── ECOMockGPS.html │ └── ECOViewBorder.html └── iOS └── Example ├── EchoDemo.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ └── EchoDemo.xcscheme ├── EchoDemo ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── EchoAppDelegate.h ├── EchoAppDelegate.m ├── EchoDemo-Info.plist ├── EchoDemo-Prefix.pch ├── EchoTableViewCell.h ├── EchoTableViewCell.m ├── EchoViewController.h ├── EchoViewController.m ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── en.lproj │ └── InfoPlist.strings └── main.m ├── Podfile ├── Podfile.lock └── Tests ├── Tests-Info.plist ├── Tests-Prefix.pch ├── Tests.m └── en.lproj └── InfoPlist.strings /.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 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | Pods/ 38 | Mac/Pods/ 39 | # 40 | # Add this line if you want to avoid checking in source code from the Xcode workspace 41 | *.xcworkspace 42 | Mac/*.xcworkspace 43 | 44 | # Carthage 45 | # 46 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 47 | # Carthage/Checkouts 48 | 49 | Carthage/Build 50 | 51 | # fastlane 52 | # 53 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 54 | # screenshots whenever they are needed. 55 | # For more information about the recommended setup visit: 56 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 57 | 58 | fastlane/report.xml 59 | fastlane/Preview.html 60 | fastlane/screenshots/**/*.png 61 | fastlane/test_output 62 | 63 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guideline 2 | 3 | Thanks for considering to contribute this project. All issues and pull requests are highly appreciated. 4 | 5 | ## Pull Requests 6 | 7 | Before sending pull request to this project, please read and follow guidelines below. 8 | 9 | 1. Branch: We only accept pull request on `master` branch. 10 | 2. Coding style: Follow the coding style used in Echo. 11 | 3. Commit message: Use English and be aware of your spell. 12 | 4. Test: Make sure to test your code. 13 | 14 | Add device mode, API version, related log, screenshots and other related information in your pull request if possible. 15 | 16 | NOTE: We assume all your contribution can be licensed under the [Apache License 2.0](https://github.com/didichuxing/echo/blob/master/LICENSE). 17 | 18 | ## Issues 19 | 20 | We love clearly described issues. :) 21 | 22 | Following information can help us to resolve the issue faster. 23 | 24 | * Device mode and hardware information. 25 | * API version. 26 | * Logs. 27 | * Screenshots. 28 | * Steps to reproduce the issue. 29 | -------------------------------------------------------------------------------- /Images/echoArch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Images/echoArch.jpg -------------------------------------------------------------------------------- /Images/intro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Images/intro.jpg -------------------------------------------------------------------------------- /Images/ios14permission.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Images/ios14permission.jpg -------------------------------------------------------------------------------- /Images/mockGPS.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Images/mockGPS.jpg -------------------------------------------------------------------------------- /Images/network.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Images/network.jpg -------------------------------------------------------------------------------- /Images/nslog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Images/nslog.jpg -------------------------------------------------------------------------------- /Images/solution.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Images/solution.jpg -------------------------------------------------------------------------------- /Images/view.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Images/view.jpg -------------------------------------------------------------------------------- /Images/view_dark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Images/view_dark.jpg -------------------------------------------------------------------------------- /Mac/Echo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/15. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : NSObject 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Mac/Echo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/15. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 19 | // Insert code here to initialize your application 20 | //启动服务 21 | [[ECOCoreManager shared] start]; 22 | } 23 | 24 | - (void)applicationWillTerminate:(NSNotification *)aNotification { 25 | // Insert code here to tear down your application 26 | } 27 | 28 | - (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag { 29 | for (NSWindow *w in sender.windows) { 30 | [w makeKeyAndOrderFront:nil]; 31 | } 32 | return YES; 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/AppIcon.appiconset/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/AppIcon.appiconset/1024.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/AppIcon.appiconset/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/AppIcon.appiconset/128.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/AppIcon.appiconset/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/AppIcon.appiconset/16.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/AppIcon.appiconset/256-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/AppIcon.appiconset/256-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/AppIcon.appiconset/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/AppIcon.appiconset/256.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/AppIcon.appiconset/32-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/AppIcon.appiconset/32-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/AppIcon.appiconset/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/AppIcon.appiconset/32.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/AppIcon.appiconset/512-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/AppIcon.appiconset/512-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/AppIcon.appiconset/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/AppIcon.appiconset/512.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/AppIcon.appiconset/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/AppIcon.appiconset/64.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "32-1.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "256-1.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "512-1.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/connect_btn_color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0xFF", 13 | "alpha" : "1.000", 14 | "blue" : "0x47", 15 | "green" : "0xB9" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/connect_btn_ing_color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "210", 13 | "alpha" : "1.000", 14 | "blue" : "210", 15 | "green" : "210" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/connect_line_color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "225", 13 | "alpha" : "1.000", 14 | "blue" : "225", 15 | "green" : "225" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "225", 31 | "alpha" : "1.000", 32 | "blue" : "225", 33 | "green" : "225" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "80", 49 | "alpha" : "1.000", 50 | "blue" : "80", 51 | "green" : "80" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/connect_title_color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.314", 13 | "alpha" : "1.000", 14 | "blue" : "0.314", 15 | "green" : "0.314" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/deviceBgColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "1.000", 13 | "alpha" : "1.000", 14 | "blue" : "1.000", 15 | "green" : "1.000" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "1.000", 31 | "alpha" : "1.000", 32 | "blue" : "1.000", 33 | "green" : "1.000" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x00", 49 | "alpha" : "1.000", 50 | "blue" : "0x00", 51 | "green" : "0x00" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/deviceGuide_arrow.imageset/新手引导箭头-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/deviceGuide_arrow.imageset/新手引导箭头-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/deviceGuide_arrow.imageset/新手引导箭头-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/deviceGuide_arrow.imageset/新手引导箭头-2.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/deviceGuide_arrow.imageset/新手引导箭头.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/deviceGuide_arrow.imageset/新手引导箭头.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/deviceGuide_info.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "1x", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "universal", 19 | "scale" : "1x", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | }, 27 | { 28 | "idiom" : "universal", 29 | "filename" : "新手引导.png", 30 | "scale" : "2x" 31 | }, 32 | { 33 | "idiom" : "universal", 34 | "filename" : "新手引导-1.png", 35 | "appearances" : [ 36 | { 37 | "appearance" : "luminosity", 38 | "value" : "light" 39 | } 40 | ], 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "universal", 45 | "filename" : "新手引导-2.png", 46 | "appearances" : [ 47 | { 48 | "appearance" : "luminosity", 49 | "value" : "dark" 50 | } 51 | ], 52 | "scale" : "2x" 53 | }, 54 | { 55 | "idiom" : "universal", 56 | "scale" : "3x" 57 | }, 58 | { 59 | "idiom" : "universal", 60 | "scale" : "3x", 61 | "appearances" : [ 62 | { 63 | "appearance" : "luminosity", 64 | "value" : "light" 65 | } 66 | ] 67 | }, 68 | { 69 | "idiom" : "universal", 70 | "scale" : "3x", 71 | "appearances" : [ 72 | { 73 | "appearance" : "luminosity", 74 | "value" : "dark" 75 | } 76 | ] 77 | } 78 | ], 79 | "info" : { 80 | "version" : 1, 81 | "author" : "xcode" 82 | } 83 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/deviceGuide_info.imageset/新手引导-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/deviceGuide_info.imageset/新手引导-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/deviceGuide_info.imageset/新手引导-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/deviceGuide_info.imageset/新手引导-2.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/deviceGuide_info.imageset/新手引导.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/deviceGuide_info.imageset/新手引导.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/deviceTop.imageset/LOGO信息_white-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/deviceTop.imageset/LOGO信息_white-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/deviceTop.imageset/LOGO信息_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/deviceTop.imageset/LOGO信息_white.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/deviceTop.imageset/LOGO组.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/deviceTop.imageset/LOGO组.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_authed.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "1x", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "universal", 19 | "scale" : "1x", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | }, 27 | { 28 | "idiom" : "universal", 29 | "filename" : "设备选中态-2.png", 30 | "scale" : "2x" 31 | }, 32 | { 33 | "idiom" : "universal", 34 | "filename" : "设备选中态.png", 35 | "appearances" : [ 36 | { 37 | "appearance" : "luminosity", 38 | "value" : "light" 39 | } 40 | ], 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "universal", 45 | "filename" : "设备选中态-1.png", 46 | "appearances" : [ 47 | { 48 | "appearance" : "luminosity", 49 | "value" : "dark" 50 | } 51 | ], 52 | "scale" : "2x" 53 | }, 54 | { 55 | "idiom" : "universal", 56 | "scale" : "3x" 57 | }, 58 | { 59 | "idiom" : "universal", 60 | "scale" : "3x", 61 | "appearances" : [ 62 | { 63 | "appearance" : "luminosity", 64 | "value" : "light" 65 | } 66 | ] 67 | }, 68 | { 69 | "idiom" : "universal", 70 | "scale" : "3x", 71 | "appearances" : [ 72 | { 73 | "appearance" : "luminosity", 74 | "value" : "dark" 75 | } 76 | ] 77 | } 78 | ], 79 | "info" : { 80 | "version" : 1, 81 | "author" : "xcode" 82 | } 83 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_authed.imageset/设备选中态-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/device_authed.imageset/设备选中态-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_authed.imageset/设备选中态-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/device_authed.imageset/设备选中态-2.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_authed.imageset/设备选中态.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/device_authed.imageset/设备选中态.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_connect_tip.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "图片.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_connect_tip.imageset/图片.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/device_connect_tip.imageset/图片.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_connected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "1x", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "universal", 19 | "scale" : "1x", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | }, 27 | { 28 | "idiom" : "universal", 29 | "filename" : "连接未选中态-1.png", 30 | "scale" : "2x" 31 | }, 32 | { 33 | "idiom" : "universal", 34 | "filename" : "连接未选中态.png", 35 | "appearances" : [ 36 | { 37 | "appearance" : "luminosity", 38 | "value" : "light" 39 | } 40 | ], 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "universal", 45 | "filename" : "连接.png", 46 | "appearances" : [ 47 | { 48 | "appearance" : "luminosity", 49 | "value" : "dark" 50 | } 51 | ], 52 | "scale" : "2x" 53 | }, 54 | { 55 | "idiom" : "universal", 56 | "scale" : "3x" 57 | }, 58 | { 59 | "idiom" : "universal", 60 | "scale" : "3x", 61 | "appearances" : [ 62 | { 63 | "appearance" : "luminosity", 64 | "value" : "light" 65 | } 66 | ] 67 | }, 68 | { 69 | "idiom" : "universal", 70 | "scale" : "3x", 71 | "appearances" : [ 72 | { 73 | "appearance" : "luminosity", 74 | "value" : "dark" 75 | } 76 | ] 77 | } 78 | ], 79 | "info" : { 80 | "version" : 1, 81 | "author" : "xcode" 82 | } 83 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_connected.imageset/连接.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/device_connected.imageset/连接.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_connected.imageset/连接未选中态-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/device_connected.imageset/连接未选中态-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_connected.imageset/连接未选中态.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/device_connected.imageset/连接未选中态.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_disConnected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "1x", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "universal", 19 | "scale" : "1x", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | }, 27 | { 28 | "idiom" : "universal", 29 | "filename" : "未连接-2.png", 30 | "scale" : "2x" 31 | }, 32 | { 33 | "idiom" : "universal", 34 | "filename" : "未连接.png", 35 | "appearances" : [ 36 | { 37 | "appearance" : "luminosity", 38 | "value" : "light" 39 | } 40 | ], 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "universal", 45 | "filename" : "未连接-1.png", 46 | "appearances" : [ 47 | { 48 | "appearance" : "luminosity", 49 | "value" : "dark" 50 | } 51 | ], 52 | "scale" : "2x" 53 | }, 54 | { 55 | "idiom" : "universal", 56 | "scale" : "3x" 57 | }, 58 | { 59 | "idiom" : "universal", 60 | "scale" : "3x", 61 | "appearances" : [ 62 | { 63 | "appearance" : "luminosity", 64 | "value" : "light" 65 | } 66 | ] 67 | }, 68 | { 69 | "idiom" : "universal", 70 | "scale" : "3x", 71 | "appearances" : [ 72 | { 73 | "appearance" : "luminosity", 74 | "value" : "dark" 75 | } 76 | ] 77 | } 78 | ], 79 | "info" : { 80 | "version" : 1, 81 | "author" : "xcode" 82 | } 83 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_disConnected.imageset/未连接-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/device_disConnected.imageset/未连接-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_disConnected.imageset/未连接-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/device_disConnected.imageset/未连接-2.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_disConnected.imageset/未连接.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/device_disConnected.imageset/未连接.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_unAuthed.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "1x", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "universal", 19 | "scale" : "1x", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | }, 27 | { 28 | "idiom" : "universal", 29 | "filename" : "设备未选中态-2.png", 30 | "scale" : "2x" 31 | }, 32 | { 33 | "idiom" : "universal", 34 | "filename" : "设备未选中态.png", 35 | "appearances" : [ 36 | { 37 | "appearance" : "luminosity", 38 | "value" : "light" 39 | } 40 | ], 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "universal", 45 | "filename" : "设备未选中态-1.png", 46 | "appearances" : [ 47 | { 48 | "appearance" : "luminosity", 49 | "value" : "dark" 50 | } 51 | ], 52 | "scale" : "2x" 53 | }, 54 | { 55 | "idiom" : "universal", 56 | "scale" : "3x" 57 | }, 58 | { 59 | "idiom" : "universal", 60 | "scale" : "3x", 61 | "appearances" : [ 62 | { 63 | "appearance" : "luminosity", 64 | "value" : "light" 65 | } 66 | ] 67 | }, 68 | { 69 | "idiom" : "universal", 70 | "scale" : "3x", 71 | "appearances" : [ 72 | { 73 | "appearance" : "luminosity", 74 | "value" : "dark" 75 | } 76 | ] 77 | } 78 | ], 79 | "info" : { 80 | "version" : 1, 81 | "author" : "xcode" 82 | } 83 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_unAuthed.imageset/设备未选中态-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/device_unAuthed.imageset/设备未选中态-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_unAuthed.imageset/设备未选中态-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/device_unAuthed.imageset/设备未选中态-2.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/device_unAuthed.imageset/设备未选中态.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/device_unAuthed.imageset/设备未选中态.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/dot_default.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0x00", 13 | "alpha" : "1.000", 14 | "blue" : "0xF0", 15 | "green" : "0xD4" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0x00", 31 | "alpha" : "1.000", 32 | "blue" : "0xF0", 33 | "green" : "0xD4" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x00", 49 | "alpha" : "1.000", 50 | "blue" : "0xF5", 51 | "green" : "0xDE" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/dot_red.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0xFF", 13 | "alpha" : "1.000", 14 | "blue" : "0x4B", 15 | "green" : "0x55" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0xFF", 31 | "alpha" : "1.000", 32 | "blue" : "0x4B", 33 | "green" : "0x55" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0xFF", 49 | "alpha" : "1.000", 50 | "blue" : "0x55", 51 | "green" : "0x5F" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/icon_arrow_down.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "1x", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "universal", 19 | "scale" : "1x", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | }, 27 | { 28 | "idiom" : "universal", 29 | "filename" : "向下-2.png", 30 | "scale" : "2x" 31 | }, 32 | { 33 | "idiom" : "universal", 34 | "filename" : "向下.png", 35 | "appearances" : [ 36 | { 37 | "appearance" : "luminosity", 38 | "value" : "light" 39 | } 40 | ], 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "universal", 45 | "filename" : "向下-1.png", 46 | "appearances" : [ 47 | { 48 | "appearance" : "luminosity", 49 | "value" : "dark" 50 | } 51 | ], 52 | "scale" : "2x" 53 | }, 54 | { 55 | "idiom" : "universal", 56 | "scale" : "3x" 57 | }, 58 | { 59 | "idiom" : "universal", 60 | "scale" : "3x", 61 | "appearances" : [ 62 | { 63 | "appearance" : "luminosity", 64 | "value" : "light" 65 | } 66 | ] 67 | }, 68 | { 69 | "idiom" : "universal", 70 | "scale" : "3x", 71 | "appearances" : [ 72 | { 73 | "appearance" : "luminosity", 74 | "value" : "dark" 75 | } 76 | ] 77 | } 78 | ], 79 | "info" : { 80 | "version" : 1, 81 | "author" : "xcode" 82 | } 83 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/icon_arrow_down.imageset/向下-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/icon_arrow_down.imageset/向下-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/icon_arrow_down.imageset/向下-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/icon_arrow_down.imageset/向下-2.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/icon_arrow_down.imageset/向下.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/icon_arrow_down.imageset/向下.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/icon_arrow_up.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "1x", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "universal", 19 | "scale" : "1x", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | }, 27 | { 28 | "idiom" : "universal", 29 | "filename" : "向上-2.png", 30 | "scale" : "2x" 31 | }, 32 | { 33 | "idiom" : "universal", 34 | "filename" : "向上.png", 35 | "appearances" : [ 36 | { 37 | "appearance" : "luminosity", 38 | "value" : "light" 39 | } 40 | ], 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "universal", 45 | "filename" : "向上-1.png", 46 | "appearances" : [ 47 | { 48 | "appearance" : "luminosity", 49 | "value" : "dark" 50 | } 51 | ], 52 | "scale" : "2x" 53 | }, 54 | { 55 | "idiom" : "universal", 56 | "scale" : "3x" 57 | }, 58 | { 59 | "idiom" : "universal", 60 | "scale" : "3x", 61 | "appearances" : [ 62 | { 63 | "appearance" : "luminosity", 64 | "value" : "light" 65 | } 66 | ] 67 | }, 68 | { 69 | "idiom" : "universal", 70 | "scale" : "3x", 71 | "appearances" : [ 72 | { 73 | "appearance" : "luminosity", 74 | "value" : "dark" 75 | } 76 | ] 77 | } 78 | ], 79 | "info" : { 80 | "version" : 1, 81 | "author" : "xcode" 82 | } 83 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/icon_arrow_up.imageset/向上-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/icon_arrow_up.imageset/向上-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/icon_arrow_up.imageset/向上-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/icon_arrow_up.imageset/向上-2.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/icon_arrow_up.imageset/向上.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/icon_arrow_up.imageset/向上.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/listDetail_cellSelection.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0x2A", 13 | "alpha" : "0.250", 14 | "blue" : "0x3F", 15 | "green" : "0x2C" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0x2A", 31 | "alpha" : "0.250", 32 | "blue" : "0x3F", 33 | "green" : "0x2C" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0xFF", 49 | "alpha" : "1.000", 50 | "blue" : "0x39", 51 | "green" : "0xC3" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/listDetail_delete.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "删除.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "删除-1.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/listDetail_delete.imageset/删除-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/listDetail_delete.imageset/删除-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/listDetail_delete.imageset/删除.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/listDetail_delete.imageset/删除.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/listDetail_header.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "22", 13 | "alpha" : "1.000", 14 | "blue" : "22", 15 | "green" : "22" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/listDetail_headerTitle.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "1.000", 13 | "alpha" : "1.000", 14 | "blue" : "1.000", 15 | "green" : "1.000" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "1.000", 31 | "alpha" : "1.000", 32 | "blue" : "1.000", 33 | "green" : "1.000" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x97", 49 | "alpha" : "1.000", 50 | "blue" : "0x97", 51 | "green" : "0x97" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/listDetail_line.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.965", 13 | "alpha" : "1.000", 14 | "blue" : "0.973", 15 | "green" : "0.965" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0xF6", 31 | "alpha" : "1.000", 32 | "blue" : "0xF8", 33 | "green" : "0xF6" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x48", 49 | "alpha" : "1.000", 50 | "blue" : "0x48", 51 | "green" : "0x48" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/listDetail_searchBg.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "1.000", 13 | "alpha" : "1.000", 14 | "blue" : "1.000", 15 | "green" : "1.000" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "1.000", 31 | "alpha" : "1.000", 32 | "blue" : "1.000", 33 | "green" : "1.000" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x38", 49 | "alpha" : "1.000", 50 | "blue" : "0x38", 51 | "green" : "0x38" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/listDetail_text.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.365", 13 | "alpha" : "1.000", 14 | "blue" : "0.365", 15 | "green" : "0.365" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0x5D", 31 | "alpha" : "1.000", 32 | "blue" : "0x5D", 33 | "green" : "0x5D" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0xF2", 49 | "alpha" : "1.000", 50 | "blue" : "0xF7", 51 | "green" : "0xF2" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/network_switch_color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0xFF", 13 | "alpha" : "1.000", 14 | "blue" : "0x39", 15 | "green" : "0xC3" 16 | } 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/normalArrow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "bts_homepage_button@3x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/normalArrow.imageset/bts_homepage_button@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/normalArrow.imageset/bts_homepage_button@3x.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/outline_refresh.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "刷新.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "刷新1.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/outline_refresh.imageset/刷新.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/outline_refresh.imageset/刷新.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/outline_refresh.imageset/刷新1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/outline_refresh.imageset/刷新1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/pluginBgColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.949", 13 | "alpha" : "1.000", 14 | "blue" : "0.949", 15 | "green" : "0.949" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0xF2", 31 | "alpha" : "1.000", 32 | "blue" : "0xF2", 33 | "green" : "0xF2" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x22", 49 | "alpha" : "1.000", 50 | "blue" : "0x22", 51 | "green" : "0x22" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/pluginList_selected.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.973", 13 | "alpha" : "1.000", 14 | "blue" : "0.973", 15 | "green" : "0.973" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0xF8", 31 | "alpha" : "1.000", 32 | "blue" : "0xF8", 33 | "green" : "0xF8" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x38", 49 | "alpha" : "1.000", 50 | "blue" : "0x38", 51 | "green" : "0x38" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/plugin_icon_default.imageset/其他未选中态-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/plugin_icon_default.imageset/其他未选中态-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/plugin_icon_default.imageset/其他未选中态-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/plugin_icon_default.imageset/其他未选中态-2.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/plugin_icon_default.imageset/其他未选中态.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/plugin_icon_default.imageset/其他未选中态.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/plugin_icon_selected.imageset/其他选中态-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/plugin_icon_selected.imageset/其他选中态-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/plugin_icon_selected.imageset/其他选中态-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/plugin_icon_selected.imageset/其他选中态-2.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/plugin_icon_selected.imageset/其他选中态.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/plugin_icon_selected.imageset/其他选中态.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/plugin_network_default.imageset/网络请求未选中态-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/plugin_network_default.imageset/网络请求未选中态-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/plugin_network_default.imageset/网络请求未选中态-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/plugin_network_default.imageset/网络请求未选中态-2.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/plugin_network_default.imageset/网络请求未选中态.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/plugin_network_default.imageset/网络请求未选中态.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/plugin_network_selected.imageset/网络请求选中态-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/plugin_network_selected.imageset/网络请求选中态-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/plugin_network_selected.imageset/网络请求选中态-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/plugin_network_selected.imageset/网络请求选中态-2.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/plugin_network_selected.imageset/网络请求选中态.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/plugin_network_selected.imageset/网络请求选中态.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/selectedArrow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "bts_homepage_button@3x 2.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/selectedArrow.imageset/bts_homepage_button@3x 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/selectedArrow.imageset/bts_homepage_button@3x 2.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/text_black.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.200", 13 | "alpha" : "1.000", 14 | "blue" : "0.200", 15 | "green" : "0.200" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0x33", 31 | "alpha" : "1.000", 32 | "blue" : "0x33", 33 | "green" : "0x33" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0xF2", 49 | "alpha" : "1.000", 50 | "blue" : "0xF7", 51 | "green" : "0xF2" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/text_gray.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.400", 13 | "alpha" : "1.000", 14 | "blue" : "0.400", 15 | "green" : "0.400" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0x66", 31 | "alpha" : "1.000", 32 | "blue" : "0x66", 33 | "green" : "0x66" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0xF2", 49 | "alpha" : "1.000", 50 | "blue" : "0xF7", 51 | "green" : "0xF2" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/text_lightBlack.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.086", 13 | "alpha" : "1.000", 14 | "blue" : "0.086", 15 | "green" : "0.086" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0x16", 31 | "alpha" : "1.000", 32 | "blue" : "0x16", 33 | "green" : "0x16" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x99", 49 | "alpha" : "1.000", 50 | "blue" : "0x99", 51 | "green" : "0x99" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/text_lightGray.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.600", 13 | "alpha" : "1.000", 14 | "blue" : "0.600", 15 | "green" : "0.600" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0x99", 31 | "alpha" : "1.000", 32 | "blue" : "0x99", 33 | "green" : "0x99" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x97", 49 | "alpha" : "1.000", 50 | "blue" : "0x97", 51 | "green" : "0x97" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/viewList_line_color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.592", 13 | "alpha" : "1.000", 14 | "blue" : "0.663", 15 | "green" : "0.604" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0x97", 31 | "alpha" : "1.000", 32 | "blue" : "0xA9", 33 | "green" : "0x9A" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x99", 49 | "alpha" : "1.000", 50 | "blue" : "0x99", 51 | "green" : "0x99" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/viewList_text_color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.314", 13 | "alpha" : "1.000", 14 | "blue" : "0.314", 15 | "green" : "0.314" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0x50", 31 | "alpha" : "1.000", 32 | "blue" : "0x50", 33 | "green" : "0x50" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0xF2", 49 | "alpha" : "1.000", 50 | "blue" : "0xF7", 51 | "green" : "0xF2" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/viewScene_bg_color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0xF9", 13 | "alpha" : "1.000", 14 | "blue" : "0xF9", 15 | "green" : "0xF9" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0xF9", 31 | "alpha" : "1.000", 32 | "blue" : "0xF9", 33 | "green" : "0xF9" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x22", 49 | "alpha" : "1.000", 50 | "blue" : "0x22", 51 | "green" : "0x22" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/view_hierarchy_color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "1.000", 13 | "alpha" : "1.000", 14 | "blue" : "1.000", 15 | "green" : "1.000" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0xFF", 31 | "alpha" : "1.000", 32 | "blue" : "0xFF", 33 | "green" : "0xFF" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x38", 49 | "alpha" : "1.000", 50 | "blue" : "0x38", 51 | "green" : "0x38" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/view_info_bg_color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "1.000", 13 | "alpha" : "1.000", 14 | "blue" : "1.000", 15 | "green" : "1.000" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0xFF", 31 | "alpha" : "1.000", 32 | "blue" : "0xFF", 33 | "green" : "0xFF" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x22", 49 | "alpha" : "1.000", 50 | "blue" : "0x22", 51 | "green" : "0x22" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/view_info_cell_color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.976", 13 | "alpha" : "1.000", 14 | "blue" : "0.976", 15 | "green" : "0.976" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0xF9", 31 | "alpha" : "1.000", 32 | "blue" : "0xF9", 33 | "green" : "0xF9" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x38", 49 | "alpha" : "1.000", 50 | "blue" : "0x38", 51 | "green" : "0x38" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/view_menu_color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "universal", 9 | "color" : { 10 | "color-space" : "srgb", 11 | "components" : { 12 | "red" : "0.973", 13 | "alpha" : "1.000", 14 | "blue" : "0.973", 15 | "green" : "0.973" 16 | } 17 | } 18 | }, 19 | { 20 | "idiom" : "universal", 21 | "appearances" : [ 22 | { 23 | "appearance" : "luminosity", 24 | "value" : "light" 25 | } 26 | ], 27 | "color" : { 28 | "color-space" : "srgb", 29 | "components" : { 30 | "red" : "0xF8", 31 | "alpha" : "1.000", 32 | "blue" : "0xF8", 33 | "green" : "0xF8" 34 | } 35 | } 36 | }, 37 | { 38 | "idiom" : "universal", 39 | "appearances" : [ 40 | { 41 | "appearance" : "luminosity", 42 | "value" : "dark" 43 | } 44 | ], 45 | "color" : { 46 | "color-space" : "srgb", 47 | "components" : { 48 | "red" : "0x38", 49 | "alpha" : "1.000", 50 | "blue" : "0x38", 51 | "green" : "0x38" 52 | } 53 | } 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/view_menu_refresh.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "1x", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "universal", 19 | "scale" : "1x", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | }, 27 | { 28 | "idiom" : "universal", 29 | "filename" : "刷新.png", 30 | "scale" : "2x" 31 | }, 32 | { 33 | "idiom" : "universal", 34 | "filename" : "刷新-1.png", 35 | "appearances" : [ 36 | { 37 | "appearance" : "luminosity", 38 | "value" : "light" 39 | } 40 | ], 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "universal", 45 | "filename" : "刷新2.png", 46 | "appearances" : [ 47 | { 48 | "appearance" : "luminosity", 49 | "value" : "dark" 50 | } 51 | ], 52 | "scale" : "2x" 53 | }, 54 | { 55 | "idiom" : "universal", 56 | "scale" : "3x" 57 | }, 58 | { 59 | "idiom" : "universal", 60 | "scale" : "3x", 61 | "appearances" : [ 62 | { 63 | "appearance" : "luminosity", 64 | "value" : "light" 65 | } 66 | ] 67 | }, 68 | { 69 | "idiom" : "universal", 70 | "scale" : "3x", 71 | "appearances" : [ 72 | { 73 | "appearance" : "luminosity", 74 | "value" : "dark" 75 | } 76 | ] 77 | } 78 | ], 79 | "info" : { 80 | "version" : 1, 81 | "author" : "xcode" 82 | } 83 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/view_menu_refresh.imageset/刷新-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/view_menu_refresh.imageset/刷新-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/view_menu_refresh.imageset/刷新.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/view_menu_refresh.imageset/刷新.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/view_menu_refresh.imageset/刷新2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/view_menu_refresh.imageset/刷新2.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/view_menu_reset.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "1x", 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "light" 14 | } 15 | ] 16 | }, 17 | { 18 | "idiom" : "universal", 19 | "scale" : "1x", 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "dark" 24 | } 25 | ] 26 | }, 27 | { 28 | "idiom" : "universal", 29 | "filename" : "重置-2.png", 30 | "scale" : "2x" 31 | }, 32 | { 33 | "idiom" : "universal", 34 | "filename" : "重置-1.png", 35 | "appearances" : [ 36 | { 37 | "appearance" : "luminosity", 38 | "value" : "light" 39 | } 40 | ], 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "universal", 45 | "filename" : "重置.png", 46 | "appearances" : [ 47 | { 48 | "appearance" : "luminosity", 49 | "value" : "dark" 50 | } 51 | ], 52 | "scale" : "2x" 53 | }, 54 | { 55 | "idiom" : "universal", 56 | "scale" : "3x" 57 | }, 58 | { 59 | "idiom" : "universal", 60 | "scale" : "3x", 61 | "appearances" : [ 62 | { 63 | "appearance" : "luminosity", 64 | "value" : "light" 65 | } 66 | ] 67 | }, 68 | { 69 | "idiom" : "universal", 70 | "scale" : "3x", 71 | "appearances" : [ 72 | { 73 | "appearance" : "luminosity", 74 | "value" : "dark" 75 | } 76 | ] 77 | } 78 | ], 79 | "info" : { 80 | "version" : 1, 81 | "author" : "xcode" 82 | } 83 | } -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/view_menu_reset.imageset/重置-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/view_menu_reset.imageset/重置-1.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/view_menu_reset.imageset/重置-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/view_menu_reset.imageset/重置-2.png -------------------------------------------------------------------------------- /Mac/Echo/Assets.xcassets/view_menu_reset.imageset/重置.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Assets.xcassets/view_menu_reset.imageset/重置.png -------------------------------------------------------------------------------- /Mac/Echo/Echo.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Mac/Echo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | LSMinimumSystemVersion 22 | $(MACOSX_DEPLOYMENT_TARGET) 23 | NSAppTransportSecurity 24 | 25 | NSAllowsArbitraryLoads 26 | 27 | 28 | NSHumanReadableCopyright 29 | Copyright © 2019 陈爱彬. All rights reserved. 30 | NSMainStoryboardFile 31 | Main 32 | NSPrincipalClass 33 | NSApplication 34 | SUFeedURL 35 | 36 | SUPublicEDKey 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Mac/Echo/Models/ECODeviceModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECODeviceModel.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/5/15. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOChannelDeviceInfo.h" 11 | #import "ECOProjectModel.h" 12 | #import "ECOBasePlugin.h" 13 | 14 | @interface ECODeviceModel : NSObject 15 | 16 | //@property (nonatomic, strong) ECOChannelDeviceInfo *deviceInfo; 17 | @property (nonatomic, strong) NSMutableArray *projects; 18 | @property (nonatomic, strong) ECOProjectModel *selectedProject; 19 | @property (nonatomic, assign, getter=isConnected) BOOL connected; 20 | @property (nonatomic, assign) BOOL hasPackets; 21 | 22 | @property (nonatomic, copy) NSString *deviceId; 23 | @property (nonatomic, copy) NSString *deviceName; 24 | 25 | - (BOOL)updateWithDevice:(ECOChannelDeviceInfo *)deviceInfo plugin:(__kindof ECOBasePlugin *)plugin packet:(id)packetData; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Mac/Echo/Models/ECOPacketsDispatcher.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOPacketsDispatcher.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/5/16. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOChannelDeviceInfo.h" 11 | #import "ECODeviceModel.h" 12 | #import "ECOBasePlugin.h" 13 | 14 | typedef void(^ECOPacketsRefreshBlock)(BOOL refreshDevice, BOOL refreshPlugin, BOOL refreshDetail); 15 | 16 | @interface ECOPacketsDispatcher : NSObject 17 | 18 | @property (nonatomic, strong) NSMutableArray *devices; 19 | @property (nonatomic, strong) ECODeviceModel *selectedDevice; 20 | @property (nonatomic, copy) ECOPacketsRefreshBlock refreshBlock; 21 | @property (nonatomic, strong) NSMutableArray *authorizedDevices; 22 | @property (nonatomic, strong) NSMutableArray *discoverdDevices; 23 | 24 | @property (nonatomic, strong) ECOChannelDeviceInfo *hostDevice; 25 | 26 | + (instancetype)shared; 27 | 28 | //清空当前插件的数据 29 | - (void)clearCurrentPluginPackets; 30 | 31 | - (void)device:(ECOChannelDeviceInfo *)device didUpdateToState:(BOOL)isConnected; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Mac/Echo/Models/ECOPluginModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOPluginModel.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/5/15. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOBasePlugin.h" 11 | 12 | @interface ECOPluginModel : NSObject 13 | 14 | @property (nonatomic, strong) __kindof ECOBasePlugin *plugin; 15 | 16 | - (void)appendPacket:(id)packet; 17 | 18 | - (void)clear; 19 | 20 | - (NSArray *)packetList; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Mac/Echo/Models/ECOPluginModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECOPluginModel.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/5/15. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECOPluginModel.h" 10 | 11 | @interface ECOPluginModel() 12 | { 13 | dispatch_queue_t _packetQueue; 14 | } 15 | @property (nonatomic, strong) NSMutableArray *packets; 16 | @end 17 | 18 | @implementation ECOPluginModel 19 | 20 | - (instancetype)init 21 | { 22 | self = [super init]; 23 | if (self) { 24 | self.packets = @[].mutableCopy; 25 | _packetQueue = dispatch_queue_create("com.echo.packetQueue", DISPATCH_QUEUE_SERIAL); 26 | } 27 | return self; 28 | } 29 | 30 | - (void)clear { 31 | dispatch_async(_packetQueue, ^{ 32 | [self.packets removeAllObjects]; 33 | }); 34 | } 35 | 36 | - (void)appendPacket:(id)packet { 37 | if (!packet) { 38 | return; 39 | } 40 | dispatch_async(_packetQueue, ^{ 41 | [self.packets addObject:packet]; 42 | }); 43 | } 44 | 45 | - (NSArray *)packetList { 46 | __block NSArray *list = nil; 47 | dispatch_sync(_packetQueue, ^{ 48 | list = [self.packets copy]; 49 | }); 50 | return list; 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Mac/Echo/Models/ECOProjectModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOProjectModel.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/5/16. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOPluginModel.h" 11 | #import 12 | #import 13 | 14 | @interface ECOProjectModel : NSObject 15 | 16 | @property (nonatomic, strong) NSMutableArray *plugins; 17 | @property (nonatomic, strong) ECOPluginModel *selectedPlugin; 18 | @property (nonatomic, assign, getter=isSelected) BOOL selected; 19 | @property (nonatomic, strong) ECOChannelDeviceInfo *deviceInfo; 20 | 21 | - (void)appendPlugin:(ECOPluginModel *)plugin; 22 | 23 | - (BOOL)updateWithPlugin:(__kindof ECOBasePlugin *)plugin packet:(id)packetData; 24 | 25 | @end 26 | 27 | -------------------------------------------------------------------------------- /Mac/Echo/Models/ECOProjectModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECOProjectModel.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/5/16. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECOProjectModel.h" 10 | #import "ECOPacketsDispatcher.h" 11 | 12 | @implementation ECOProjectModel 13 | 14 | - (instancetype)init 15 | { 16 | self = [super init]; 17 | if (self) { 18 | self.plugins = @[].mutableCopy; 19 | } 20 | return self; 21 | } 22 | 23 | - (void)appendPlugin:(ECOPluginModel *)plugin { 24 | [self.plugins addObject:plugin]; 25 | //选中 26 | if (self.plugins.count > 0 && !self.selectedPlugin) { 27 | self.selectedPlugin = self.plugins[0]; 28 | } 29 | } 30 | 31 | - (BOOL)updateWithPlugin:(__kindof ECOBasePlugin *)plugin packet:(id)packetData { 32 | if (!plugin) { 33 | return NO; 34 | } 35 | __block ECOPluginModel *existPluginModel = nil; 36 | [self.plugins enumerateObjectsUsingBlock:^(ECOPluginModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 37 | if ([obj.plugin.name isEqualToString:plugin.name]) { 38 | existPluginModel = obj; 39 | *stop = YES; 40 | } 41 | }]; 42 | if (existPluginModel) { 43 | [existPluginModel appendPacket:packetData]; 44 | return NO; 45 | }else{ 46 | ECOPluginModel *pluginModel = [[ECOPluginModel alloc] init]; 47 | pluginModel.plugin = plugin; 48 | [pluginModel appendPacket:packetData]; 49 | [self appendPlugin:pluginModel]; 50 | return YES; 51 | } 52 | } 53 | @end 54 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/Basic/Network/ECONetworkDetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkDetailViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/3. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECONetworkDetailViewController : NSViewController 14 | 15 | @property (nonatomic, copy) NSDictionary *detailInfo; 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/Basic/Network/ECONetworkJSONViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkJSONViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/3. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECONetworkJSONViewController : NSViewController 14 | 15 | @property (nonatomic, copy) NSDictionary *jsonDict; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/Basic/Network/ECONetworkKeyValueListViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkKeyValueListViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/3. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECONetworkKeyValueListViewController : NSViewController 14 | 15 | @property (nonatomic, copy) NSArray *> *paramsList; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/Basic/Network/ECONetworkListTableCellView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkListTableCellView.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/9/29. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECONetworkListTableCellView : NSTableCellView 14 | 15 | @property (nonatomic, copy) NSString *content; 16 | @property (nonatomic, assign) BOOL isCellSelected; 17 | 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/Basic/Network/ECONetworkListTableCellView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkListTableCellView.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/9/29. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECONetworkListTableCellView.h" 10 | 11 | 12 | @interface ECONetworkListTableCellView() 13 | 14 | @property (weak) IBOutlet NSBox *bgBox; 15 | @property (weak) IBOutlet NSTextField *titleLabel; 16 | @property (weak) IBOutlet NSBox *lineView; 17 | 18 | @end 19 | 20 | @implementation ECONetworkListTableCellView 21 | 22 | - (void)setContent:(NSString *)content { 23 | _content = content; 24 | self.titleLabel.stringValue = _content ?: @""; 25 | } 26 | 27 | - (void)setIsCellSelected:(BOOL)isCellSelected { 28 | _isCellSelected = isCellSelected; 29 | self.bgBox.hidden = !_isCellSelected; 30 | } 31 | @end 32 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/Basic/Network/ECONetworkOverviewViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkOverviewViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/3. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECONetworkOverviewViewController : NSViewController 14 | 15 | @property (nonatomic, copy) NSDictionary *detailInfo; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/Basic/Network/ECONetworkRequestViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkRequestViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/3. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECONetworkRequestViewController : NSViewController 14 | 15 | @property (nonatomic, copy) NSDictionary *detailInfo; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/Basic/Network/ECONetworkResponseViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkResponseViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/3. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECONetworkResponseViewController : NSViewController 14 | 15 | @property (nonatomic, copy) NSDictionary *detailInfo; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/Basic/Network/ECONetworkScrollTextViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkScrollTextViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/3. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECONetworkScrollTextViewController : NSViewController 14 | 15 | @property (nonatomic, copy) NSString *content; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/Basic/Network/ECONetworkScrollTextViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkScrollTextViewController.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/3. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECONetworkScrollTextViewController.h" 10 | 11 | @interface ECONetworkScrollTextViewController () 12 | 13 | @property (unsafe_unretained) IBOutlet NSTextView *textView; 14 | @end 15 | 16 | @implementation ECONetworkScrollTextViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | // Do view setup here. 21 | self.textView.font = [NSFont systemFontOfSize:12]; 22 | self.textView.string = self.content ?: @""; 23 | } 24 | 25 | - (void)setContent:(NSString *)content { 26 | _content = content; 27 | self.textView.string = _content ?: @""; 28 | } 29 | @end 30 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/Basic/Network/ECONetworkViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/3. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOPluginUIProtocol.h" 11 | 12 | @interface ECONetworkViewController : NSViewController 13 | 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/ECOPluginUIProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOPluginUIProtocol.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/5/6. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #ifndef ECOPluginUIProtocol_h 10 | #define ECOPluginUIProtocol_h 11 | 12 | #import "ECOBasePlugin.h" 13 | 14 | @protocol ECOPluginUIProtocol 15 | 16 | @optional 17 | /** 18 | 刷新Tab视图 19 | 20 | @param packets 数据包列表 21 | */ 22 | - (void)refreshWithPackets:(NSArray *)packets; 23 | 24 | @property (nonatomic, weak) __kindof ECOBasePlugin *plugin; 25 | 26 | /** 27 | 模板数据 28 | */ 29 | @property (nonatomic, strong) id templateData; 30 | 31 | /** 32 | 插件是否兼容,和Plugin的version对比,如果模板版本低于plugin.version,则会显示不兼容信息 33 | 34 | @return YES为兼容,NO为不兼容 35 | */ 36 | - (BOOL)isPluginCompatible; 37 | 38 | @end 39 | 40 | #endif /* ECOPluginUIProtocol_h */ 41 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/Performance/performance.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Plugins/Performance/performance.md -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/ECOSceneView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOSceneView.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/19. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @protocol ECOSceneViewDelegate 14 | 15 | -(void)sceneView:(SCNView*)scnview didSelectedNode:(SCNNode*)node; 16 | 17 | @end 18 | 19 | @interface ECOSceneView : SCNView 20 | 21 | @property(nonatomic,weak) id delegate; 22 | 23 | -(void)selectedNode:(NSString*)uuid; 24 | 25 | @end 26 | 27 | NS_ASSUME_NONNULL_END 28 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/ECOSelectableTextView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOSelectableTextView.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/19. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECOSelectableTextView : NSTextView 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/ECOSelectableTextView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECOSelectableTextView.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/19. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECOSelectableTextView.h" 10 | 11 | @implementation ECOSelectableTextView 12 | 13 | - (void)drawRect:(NSRect)dirtyRect { 14 | [super drawRect:dirtyRect]; 15 | } 16 | 17 | - (NSView *)hitTest:(NSPoint)point 18 | { 19 | return self.superview; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/ECOViewHierarchyInfoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOViewHierarchyInfoViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/19. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @protocol ECOViewHierarchyInfoEditDelegate 14 | 15 | - (void)viewDidEditedWithInfo:(NSDictionary *)info; 16 | 17 | @end 18 | 19 | @interface ECOViewHierarchyInfoViewController : NSViewController 20 | 21 | @property (nonatomic, weak) id delegate; 22 | 23 | //刷新节点信息 24 | - (void)refreshNodeInfo:(NSDictionary *)info; 25 | 26 | @end 27 | 28 | NS_ASSUME_NONNULL_END 29 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/ECOViewHierarchyListViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOViewHierarchyListViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/19. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @protocol ECOViewHierarchyListSelectionDelegate 14 | 15 | - (void)listNodeDidSelectedWithInfo:(NSDictionary *)info; 16 | 17 | - (void)listNodeDidSelectedWithViewUUID:(NSString *)uuid; 18 | 19 | @end 20 | 21 | @interface ECOViewHierarchyListViewController : NSViewController 22 | 23 | @property (nonatomic, weak) id delegate; 24 | 25 | //刷新列表侧 26 | - (void)refreshViewTreeListWithData:(NSDictionary *)dict; 27 | 28 | //视图场景的选中节点变更了 29 | - (void)sceneNodeSelected:(NSDictionary *)nodeInfo; 30 | 31 | //更新编辑后的信息 32 | - (void)updateEditInfo:(NSDictionary *)extraInfo; 33 | 34 | @end 35 | 36 | NS_ASSUME_NONNULL_END 37 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/ECOViewHierarchySceneViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOViewHierarchySceneViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/19. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "defines.h" 11 | 12 | @protocol ECOViewHierarchySceneSelectionDelegate 13 | 14 | - (void)sceneNodeDidSelected:(NSDictionary *)node; 15 | 16 | @end 17 | 18 | @interface ECOViewHierarchySceneViewController : NSViewController 19 | 20 | @property (nonatomic, weak) id delegate; 21 | 22 | //刷新场景视图 23 | - (void)refreshViewTreeSceneWithData:(NSDictionary *)dict; 24 | 25 | //更新数据信息 26 | - (void)updateNodesInfo:(NSDictionary *)nodesInfo; 27 | 28 | //左侧列表选中节点后更新选中状态 29 | - (void)listViewDidSelectedNodeUUID:(NSString *)uuid; 30 | 31 | //切换显示模式 32 | - (void)changeDisplayMode:(YVSceneViewDisplayMode)newmode; 33 | 34 | //重置 35 | - (void)resetDisplayScene; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/ECOViewHierarchyViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOViewHierarchyViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/19. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOPluginUIProtocol.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface ECOViewHierarchyViewController : NSViewController 15 | 16 | 17 | @property (nonatomic, weak) __kindof ECOBasePlugin *plugin; 18 | 19 | @end 20 | 21 | NS_ASSUME_NONNULL_END 22 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/cell/YVRightCellBase.h: -------------------------------------------------------------------------------- 1 | // 2 | // YVRightCellBase.h 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/5/6. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef void(^ECOViewInfoEditBlock)(NSDictionary *info); 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @interface YVRightCellBase : NSTableCellView 16 | 17 | @property (nonatomic, copy) ECOViewInfoEditBlock editBlock; 18 | 19 | +(instancetype)makeView:(NSTableView*)tableView owner:(id)owner identifer:(NSString*)identifer; 20 | 21 | -(void)fillData:(id)data; 22 | 23 | @end 24 | 25 | NS_ASSUME_NONNULL_END 26 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/cell/YVRightCellBase.m: -------------------------------------------------------------------------------- 1 | // 2 | // YVRightCellBase.m 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/5/6. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "YVRightCellBase.h" 10 | 11 | @implementation YVRightCellBase 12 | 13 | -(void)awakeFromNib 14 | { 15 | self.layer.backgroundColor = [NSColor clearColor].CGColor; 16 | } 17 | 18 | +(NSView*)makeView:(NSTableView*)tableView owner:(id)owner identifer:(NSString*)identifer 19 | { 20 | YVRightCellBase * t = [tableView makeViewWithIdentifier:identifer owner:owner]; 21 | if (t == nil) { 22 | NSArray * bundleviews; 23 | [[NSBundle mainBundle]loadNibNamed:identifer owner:owner topLevelObjects:&bundleviews]; 24 | for (id object in bundleviews) { 25 | if ([object isKindOfClass:[YVRightCellBase class]]) { 26 | t = object; 27 | t.identifier = identifer; 28 | break; 29 | } 30 | } 31 | } 32 | return t; 33 | } 34 | 35 | -(void)fillData:(id)data 36 | { 37 | 38 | } 39 | 40 | - (void)drawRect:(NSRect)dirtyRect { 41 | [super drawRect:dirtyRect]; 42 | 43 | // Drawing code here. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/cell/YVRightCellViewClass.h: -------------------------------------------------------------------------------- 1 | // 2 | // YVRightCellViewFrame.h 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/5/6. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "YVRightCellBase.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface YVRightCellViewClass : YVRightCellBase 14 | 15 | @property (weak) IBOutlet NSTextField *clsInfoLabel; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/cell/YVRightCellViewClass.m: -------------------------------------------------------------------------------- 1 | // 2 | // YVRightCellViewFrame.m 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/5/6. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "YVRightCellViewClass.h" 10 | 11 | @implementation YVRightCellViewClass 12 | 13 | - (void)drawRect:(NSRect)dirtyRect { 14 | [super drawRect:dirtyRect]; 15 | 16 | // Drawing code here. 17 | } 18 | 19 | -(void)fillData:(NSDictionary*)data 20 | { 21 | NSString *inherit = data[@"inherit"] ?: @""; 22 | self.clsInfoLabel.stringValue = inherit; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/cell/YVRightCellViewFrame.h: -------------------------------------------------------------------------------- 1 | // 2 | // YVRightCellViewFrame.h 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/5/6. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "YVRightCellBase.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface YVRightCellViewFrame : YVRightCellBase 14 | 15 | @property (weak) IBOutlet NSTextField *frameX; 16 | @property (weak) IBOutlet NSTextField *frameY; 17 | @property (weak) IBOutlet NSTextField *frameW; 18 | @property (weak) IBOutlet NSTextField *frameH; 19 | 20 | @end 21 | 22 | NS_ASSUME_NONNULL_END 23 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/cell/YVRightCellViewInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // YVRightCellViewInfo.h 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/5/6. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YVRightCellBase.h" 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface YVRightCellViewInfo : YVRightCellBase 14 | 15 | @property (weak) IBOutlet NSButton *hiddenBtn; 16 | @property (weak) IBOutlet NSButton *userInteractionBtn; 17 | @property (weak) IBOutlet NSButton *masksTBBtn; 18 | @property (weak) IBOutlet NSTextField *alphaTextField; 19 | @property (weak) IBOutlet NSPopUpButton *bgColorPopupBtn; 20 | @property (weak) IBOutlet NSPopUpButton *borderPopupBtn; 21 | @property (weak) IBOutlet NSTextField *borderWidthTextField; 22 | @property (weak) IBOutlet NSTextField *radiusTextField; 23 | @property (weak) IBOutlet NSPopUpButton *shadowPopupBtn; 24 | @property (weak) IBOutlet NSTextField *shadowOpaTextField; 25 | @property (weak) IBOutlet NSTextField *shadowRadiusTextField; 26 | @property (weak) IBOutlet NSTextField *shadowOffsetWTextField; 27 | @property (weak) IBOutlet NSTextField *shadowOffsetHTextField; 28 | 29 | 30 | @end 31 | 32 | NS_ASSUME_NONNULL_END 33 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/defines.h: -------------------------------------------------------------------------------- 1 | // 2 | // defines.h 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/4/28. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #ifndef defines_h 10 | #define defines_h 11 | #import 12 | 13 | typedef enum:NSInteger { 14 | YVWindowDisplayStatusHome, 15 | YVWindowDisplayStatusInspect, 16 | }YVWindowDisplayStatus; 17 | 18 | typedef enum:NSInteger { 19 | YVSceneViewDisplayModeNone = -1, 20 | YVSceneViewDisplayModeDeepsFirst, 21 | YVSceneViewDisplayModeSmart, 22 | YVSceneViewDisplayModeFlatten, 23 | }YVSceneViewDisplayMode; 24 | 25 | static NSString * const YVViewTreeDidLoadNotificationName = @"YVViewTreeDidLoadNotificationName"; 26 | static NSString * const YVSelectionChangeMiddleToLeft = @"YVSelectionChangeMiddleToLeft"; 27 | static NSString * const YVSelectionChangeLeftToMiddle = @"YVSelectionChangeLeftToMiddle"; 28 | static NSString * const YVSelectionChangeLeftToRight = @"YVSelectionChangeLeftToRight"; 29 | static NSString * const YVNodeNamePlane = @"YVNodeNamePlane"; 30 | static NSString * const YVNodeNameIndicator = @"YVNodeNameIndicator"; 31 | static NSString * const YVNodeNameCamera = @"YVNodeNameCamera"; 32 | static NSString * const YVNodeNameBorder = @"YVNodeNameBorder"; 33 | 34 | static NSInteger const YVHitTestOptionCategoryBitMaskPlaneNode = 1<<1; 35 | static NSInteger const YVHitTestOptionCategoryBitMask2SelectedIndicator = 1<<2; 36 | static NSInteger const YVHitTestOptionCategoryBitMask3HoverBorder = 1<<3; 37 | 38 | static CGFloat const YVRectDefaultExpandThreshold = 1.0f; 39 | 40 | 41 | #endif /* defines_h */ 42 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/SCNNode+YVBorder.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCNNode+border.h 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/4/28. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface SCNNode (YVBorder) 14 | +(SCNNode*)borderNodeWithPlane:(SCNNode*)plane; 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/SCNNode+YVBorder.m: -------------------------------------------------------------------------------- 1 | // 2 | // SCNNode+border.m 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/4/28. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "SCNNode+YVBorder.h" 10 | #import "defines.h" 11 | 12 | @implementation SCNNode (YVBorder) 13 | +(SCNNode*)borderNodeWithPlane:(SCNNode*)planeNode 14 | { 15 | SCNVector3 max,min; 16 | [planeNode getBoundingBoxMin:&min max:&max]; 17 | CGFloat xx = max.x - min.x; 18 | CGFloat yy = max.y - min.y; 19 | SCNVector3 vec[] = 20 | { 21 | max, 22 | SCNVector3Make(max.x, max.y-yy, max.z), 23 | SCNVector3Make(max.x-xx, max.y-yy, max.z), 24 | SCNVector3Make(max.x-xx, max.y, max.z), 25 | }; 26 | GLubyte indexs[] ={ 27 | 0,1,1,2,2,3,3,0 28 | }; 29 | SCNGeometrySource * vecSource = [SCNGeometrySource geometrySourceWithVertices:vec count:4]; 30 | NSData * indexData = [NSData dataWithBytes:indexs length:8]; 31 | SCNGeometryElement * indexElement = [SCNGeometryElement geometryElementWithData:indexData primitiveType:SCNGeometryPrimitiveTypeLine primitiveCount:4 bytesPerIndex:sizeof(GLubyte)]; 32 | SCNGeometry * geometry = [SCNGeometry geometryWithSources:@[vecSource] elements:@[indexElement]]; 33 | geometry.firstMaterial.diffuse.contents = [NSColor colorWithRed:215.f/255.f green:215.f/255.f blue:215.f/255.f alpha:1]; 34 | geometry.firstMaterial.doubleSided = YES; 35 | SCNNode * borderNode = [SCNNode nodeWithGeometry:geometry]; 36 | borderNode.name = YVNodeNameBorder; 37 | borderNode.categoryBitMask = YVHitTestOptionCategoryBitMask3HoverBorder; 38 | return borderNode; 39 | } 40 | @end 41 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/SCNNode+YVIdentifier.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCNNode+YVIdentifier.h 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/5/5. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface SCNNode (YVIdentifier) 14 | @property (nonatomic,strong) NSString * uniqueID; 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/SCNNode+YVIdentifier.m: -------------------------------------------------------------------------------- 1 | // 2 | // SCNNode+YVIdentifier.m 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/5/5. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "SCNNode+YVIdentifier.h" 10 | #import 11 | 12 | @implementation SCNNode (YVIdentifier) 13 | -(void)setUniqueID:(NSString *)uniqueID 14 | { 15 | objc_setAssociatedObject(self, "UniqueID", uniqueID, OBJC_ASSOCIATION_RETAIN); 16 | } 17 | -(NSString *)uniqueID 18 | { 19 | return objc_getAssociatedObject(self, "UniqueID"); 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/SCNNode+YVPlane.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCNNode+plane.h 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/4/28. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface SCNNode (YVPlane) 14 | +(SCNNode*)yvplaneWithWidth:(CGFloat)width height:(CGFloat)height content:(id)content; 15 | 16 | - (void)updateContent:(id)content; 17 | 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/SCNNode+YVSelected.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCNNode+selected.h 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/4/28. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface SCNNode (YVSelected) 14 | +(SCNNode*)yvselectedNodeWithwidth:(CGFloat)width height:(CGFloat)height; 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/SCNNode+YVSelected.m: -------------------------------------------------------------------------------- 1 | // 2 | // SCNNode+selected.m 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/4/28. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "SCNNode+YVSelected.h" 10 | #import "defines.h" 11 | 12 | @implementation SCNNode (YVSelected) 13 | +(SCNNode*)yvselectedNodeWithwidth:(CGFloat)width height:(CGFloat)height 14 | { 15 | SCNPlane *planeMirror =[SCNPlane planeWithWidth:width height:height]; 16 | planeMirror.firstMaterial.diffuse.contents = [NSColor colorWithRed:206/255.f green:214/255.f blue:255/255.f alpha:1.f]; 17 | planeMirror.firstMaterial.doubleSided = YES; 18 | // planeMirror.firstMaterial.writesToDepthBuffer = NO; 19 | // planeMirror.firstMaterial.readsFromDepthBuffer = NO; 20 | SCNNode *planeMirrorNode = [SCNNode nodeWithGeometry:planeMirror]; 21 | planeMirrorNode.opacity = 0.8; 22 | planeMirrorNode.hidden = YES; 23 | planeMirrorNode.categoryBitMask = YVHitTestOptionCategoryBitMask2SelectedIndicator; 24 | planeMirrorNode.name = YVNodeNameIndicator; 25 | 26 | return planeMirrorNode; 27 | } 28 | @end 29 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/SCNNode+YVVisual.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCNNode+YVVisual.h 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/5/5. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface SCNNode (YVVisual) 14 | 15 | -(void)hover; 16 | -(void)unhover; 17 | 18 | - (void)hideBorder; 19 | - (void)showBorder; 20 | 21 | -(void)highlight; 22 | -(void)lowlight; 23 | 24 | @end 25 | 26 | NS_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/SCNNode+YVVisual.m: -------------------------------------------------------------------------------- 1 | // 2 | // SCNNode+YVVisual.m 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/5/5. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "SCNNode+YVVisual.h" 10 | #import "defines.h" 11 | 12 | @implementation SCNNode (YVVisual) 13 | -(void)hover 14 | { 15 | SCNNode * borderChild = [self childNodeWithName:YVNodeNameBorder recursively:YES]; 16 | if (borderChild) { 17 | borderChild.geometry.firstMaterial.diffuse.contents = [NSColor colorWithRed:80/255.f green:131/255.f blue:219/255.f alpha:1.f]; 18 | } 19 | } 20 | -(void)unhover 21 | { 22 | SCNNode * borderChild = [self childNodeWithName:YVNodeNameBorder recursively:YES]; 23 | if (borderChild) { 24 | borderChild.geometry.firstMaterial.diffuse.contents = [NSColor colorWithRed:218/255.f green:218/255.f blue:218/255.f alpha:1.f]; 25 | } 26 | } 27 | - (void)hideBorder { 28 | SCNNode * borderChild = [self childNodeWithName:YVNodeNameBorder recursively:YES]; 29 | if (borderChild) { 30 | borderChild.hidden = YES; 31 | } 32 | } 33 | - (void)showBorder { 34 | SCNNode * borderChild = [self childNodeWithName:YVNodeNameBorder recursively:YES]; 35 | if (borderChild) { 36 | borderChild.hidden = NO; 37 | } 38 | } 39 | 40 | 41 | -(void)highlight 42 | { 43 | SCNNode * indicator = [self childNodeWithName:YVNodeNameIndicator recursively:YES]; 44 | if (indicator) { 45 | indicator.hidden = NO; 46 | } 47 | } 48 | -(void)lowlight 49 | { 50 | SCNNode * indicator = [self childNodeWithName:YVNodeNameIndicator recursively:YES]; 51 | if (indicator) { 52 | indicator.hidden = YES; 53 | } 54 | } 55 | @end 56 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/SCNNode+YVZIndex.h: -------------------------------------------------------------------------------- 1 | // 2 | // SCNNode+zstorage.h 3 | // revealY 4 | // 5 | // Created by bliss_ddo on 2019/4/23. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YVDisplayControl.h" 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface SCNNode (YVZindex) 14 | -(void)reloadZ:(YVDisplayControl*)displayControl; 15 | @property (nonatomic,strong) NSNumber * ZSmart; 16 | @property (nonatomic,strong) NSNumber * ZSmartWihtoutOffScreenItem; 17 | @property (nonatomic,strong) NSNumber * ZDeepsFirst; 18 | @property (nonatomic,strong) NSNumber * ZDeepsFirstWithoutOffScreenItem; 19 | @property (nonatomic,strong) NSNumber * ZFlatten; 20 | @property (nonatomic,strong) NSNumber * ZFlattenWithoutOffScreenItem; 21 | @property (nonatomic,strong) NSNumber * isOffScreen; 22 | 23 | @property (nonatomic,strong) NSDictionary *nodeInfo; 24 | 25 | @end 26 | 27 | NS_ASSUME_NONNULL_END 28 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/TravseralContext.h: -------------------------------------------------------------------------------- 1 | // 2 | // TravseralContext.h 3 | // revealY 4 | // 5 | // Created by bliss_ddo on 2019/4/22. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface TravseralContext : NSObject 14 | @property (nonatomic,assign,readonly) NSInteger objectCounter; 15 | @property (nonatomic,assign,readonly) NSInteger objectCounterWithoutOffScreenObject; 16 | -(void)stepin; 17 | -(void)stepinOffScreen:(BOOL)isoffScreen; 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/TravseralContext.m: -------------------------------------------------------------------------------- 1 | // 2 | // TravseralContext.m 3 | // revealY 4 | // 5 | // Created by bliss_ddo on 2019/4/22. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "TravseralContext.h" 10 | 11 | @implementation TravseralContext 12 | -(instancetype)init 13 | { 14 | if (self = [super init]) { 15 | _objectCounter = -1; 16 | _objectCounterWithoutOffScreenObject = -1; 17 | } 18 | return self; 19 | } 20 | -(void)stepin 21 | { 22 | _objectCounter++; 23 | } 24 | -(void)stepinOffScreen:(BOOL)isoffScreen 25 | { 26 | _objectCounter++; 27 | if (!isoffScreen) { 28 | _objectCounterWithoutOffScreenObject++; 29 | } 30 | } 31 | @end 32 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/YVCGRectHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // YVCGRectHelper.h 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/4/28. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface YVCGRectHelper : NSObject 14 | +(CGRect)CGRectExpand:(CGRect)rect; 15 | +(CGRect)UIKitRectTransformToSceneRect:(CGRect)UIKitRect withScreenSize:(CGSize)screenSize; 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/YVCGRectHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // YVCGRectHelper.m 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/4/28. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "YVCGRectHelper.h" 10 | #import "defines.h" 11 | 12 | @implementation YVCGRectHelper 13 | +(CGRect)CGRectExpand:(CGRect)rect 14 | { 15 | return [self CGRectExpand:rect threashold:YVRectDefaultExpandThreshold]; 16 | } 17 | 18 | +(CGRect)CGRectExpand:(CGRect)rect threashold:(CGFloat)threshold 19 | { 20 | CGFloat x = rect.origin.x - threshold / 2; 21 | CGFloat y = rect.origin.y - threshold / 2; 22 | CGFloat w = rect.size.width + threshold; 23 | CGFloat h = rect.size.height + threshold; 24 | return CGRectMake(x, y, w, h); 25 | } 26 | 27 | +(CGRect)UIKitRectTransformToSceneRect:(CGRect)UIKitRect withScreenSize:(CGSize)screenSize; 28 | { 29 | CGFloat x = UIKitRect.origin.x; 30 | CGFloat y = UIKitRect.origin.y; 31 | CGFloat w = UIKitRect.size.width; 32 | CGFloat h = UIKitRect.size.height; 33 | CGFloat xOffSet = -screenSize.width / 2; 34 | CGFloat yOffSet = screenSize.height / 2; 35 | CGFloat x_transformed = (x + w / 2 + xOffSet) ; 36 | CGFloat y_transformed = (-(y + h / 2) + yOffSet) ; 37 | return CGRectMake(x_transformed, y_transformed, w, h); 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/YVDisplayControl.h: -------------------------------------------------------------------------------- 1 | // 2 | // YVDisplayControl.h 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/4/28. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "defines.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface YVDisplayControl : NSObject 15 | @property (nonatomic,assign)YVSceneViewDisplayMode displayMode; 16 | @property (nonatomic,assign)BOOL displayHiddenObject; 17 | @property (nonatomic,assign)CGFloat defaultDisplayFactor; 18 | @property (nonatomic,assign)CGFloat defaultDisplayZFactor; 19 | @property (nonatomic,assign)CGSize screenSize; 20 | 21 | @property (nonatomic,assign)NSInteger maxZDFS; 22 | @property (nonatomic,assign)NSInteger maxZDFSOffScreen; 23 | @property (nonatomic,assign)NSInteger maxZFlatten; 24 | @property (nonatomic,assign)NSInteger maxZFlattenOffScreen; 25 | @property (nonatomic,assign)NSInteger maxZSmart; 26 | @property (nonatomic,assign)NSInteger maxZSmartOoffScreen; 27 | 28 | @end 29 | 30 | NS_ASSUME_NONNULL_END 31 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/YVDisplayControl.m: -------------------------------------------------------------------------------- 1 | // 2 | // YVDisplayControl.m 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/4/28. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "YVDisplayControl.h" 10 | 11 | @implementation YVDisplayControl 12 | -(instancetype)init 13 | { 14 | if (self = [super init]) { 15 | _displayMode = YVSceneViewDisplayModeSmart; 16 | _displayHiddenObject = NO; 17 | _defaultDisplayFactor = 0.01; 18 | _defaultDisplayZFactor = 0.3; 19 | _maxZDFS = 0; 20 | _maxZDFSOffScreen = 0; 21 | _maxZFlatten = 0; 22 | _maxZFlattenOffScreen = 0; 23 | _maxZSmart = 0; 24 | _maxZSmartOoffScreen = 0; 25 | 26 | } 27 | return self; 28 | } 29 | @end 30 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/YVNodeBackTracking.h: -------------------------------------------------------------------------------- 1 | // 2 | // YVNodeBackTracking.h 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/4/28. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface YVNodeBackTracking : NSObject 14 | +(NSInteger)findBestZFromlevelDict:(NSMutableDictionary*)levelDict minDepth:(NSInteger)minDeepth maxDepth:(NSInteger)maxDeepth frame:(CGRect)crect; 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/helper/YVNodeBackTracking.m: -------------------------------------------------------------------------------- 1 | // 2 | // YVNodeBackTracking.m 3 | // YourView 4 | // 5 | // Created by bliss_ddo on 2019/4/28. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "YVNodeBackTracking.h" 10 | #import "YVCGRectHelper.h" 11 | 12 | @implementation YVNodeBackTracking 13 | +(NSInteger)findBestZFromlevelDict:(NSMutableDictionary*)levelDict minDepth:(NSInteger)minDeepth maxDepth:(NSInteger)maxDeepth frame:(CGRect)crect 14 | { 15 | CGRect crect_expand = [YVCGRectHelper CGRectExpand:crect]; 16 | NSInteger bestZ = 0; 17 | while (YES) { 18 | if (maxDeepth < 0 || maxDeepth < minDeepth) { 19 | break; 20 | } 21 | NSMutableArray * levelArray = levelDict[@(maxDeepth)]; 22 | if (levelArray == nil) { 23 | bestZ = maxDeepth--; 24 | }else{ 25 | BOOL hit = NO; 26 | for (NSValue * eachValue in levelArray) { 27 | CGRect eachFrame; 28 | [eachValue getValue:&eachFrame size:sizeof(CGRect)]; 29 | if (CGRectIntersectsRect(crect_expand, eachFrame)) { 30 | hit = YES; 31 | break; 32 | } 33 | } 34 | if (hit) { 35 | break; 36 | } 37 | bestZ = maxDeepth--; 38 | } 39 | } 40 | NSMutableArray * levelArray = levelDict[@(bestZ)]; 41 | if (!levelArray) { 42 | levelArray = [NSMutableArray array]; 43 | levelDict[@(bestZ)] = levelArray; 44 | } 45 | [levelArray addObject:[NSValue valueWithRect:crect]]; 46 | return bestZ; 47 | } 48 | @end 49 | -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/img/cellimage_view@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Plugins/UI/ViewHierarchy/img/cellimage_view@2x.png -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/img/empty.scn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Plugins/UI/ViewHierarchy/img/empty.scn -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/img/left_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Plugins/UI/ViewHierarchy/img/left_blue.png -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/img/left_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Plugins/UI/ViewHierarchy/img/left_gray.png -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/img/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Plugins/UI/ViewHierarchy/img/refresh.png -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/img/right_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Plugins/UI/ViewHierarchy/img/right_blue.png -------------------------------------------------------------------------------- /Mac/Echo/Plugins/UI/ViewHierarchy/img/right_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/didi/echo/b8a1c1fd6e85534ae2548aed1d9b2a8fd18259f2/Mac/Echo/Plugins/UI/ViewHierarchy/img/right_gray.png -------------------------------------------------------------------------------- /Mac/Echo/Template/H5/ECOTemplateH5ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOTemplateH5ViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/8/6. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOPluginUIProtocol.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface ECOTemplateH5ViewController : NSViewController 15 | 16 | 17 | @property (nonatomic, weak) __kindof ECOBasePlugin *plugin; 18 | 19 | - (void)receivedJSMessage:(id)result; 20 | 21 | @end 22 | 23 | NS_ASSUME_NONNULL_END 24 | -------------------------------------------------------------------------------- /Mac/Echo/Template/H5/echoJS.js: -------------------------------------------------------------------------------- 1 | function echoSend(params) { 2 | window.webkit.messageHandlers.echoSend.postMessage(params) 3 | } 4 | -------------------------------------------------------------------------------- /Mac/Echo/Template/List/ECOTemplateListDetailCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOTemplateListDetailCell.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/8/15. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECOTemplateListDetailCell : NSTableCellView 14 | 15 | @property (nonatomic, copy) NSString *title; 16 | @property (nonatomic, assign) BOOL selectedMark; 17 | 18 | /// 控制 title 文字的裁切 19 | @property (nonatomic) NSLineBreakMode titleLineBreak; 20 | 21 | @end 22 | 23 | NS_ASSUME_NONNULL_END 24 | -------------------------------------------------------------------------------- /Mac/Echo/Template/List/ECOTemplateListDetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOTemplateListDetailViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/5/28. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOPluginUIProtocol.h" 11 | 12 | typedef BOOL(^ECOFilterBlock)(NSDictionary *item, NSString *filter); 13 | typedef NSString *(^ECOColumnCellTitleBlock)(NSInteger columnIndex, NSDictionary *dict); 14 | typedef NSString *(^ECODetailContentBlock)(NSDictionary *dict); 15 | 16 | @interface ECOTemplateListDetailViewController : NSViewController 17 | 18 | 19 | @property (nonatomic, weak) __kindof ECOBasePlugin *plugin; 20 | 21 | @property (weak) IBOutlet NSSplitView *splitView; 22 | @property (nonatomic, copy) NSString *firstColumnTitle; 23 | @property (nonatomic, copy) NSString *secondColumnTitle; 24 | 25 | @property (nonatomic, strong) id templateData; 26 | 27 | /** 28 | 过滤内容处理block 29 | */ 30 | @property (nonatomic, copy) ECOFilterBlock filterBlock; 31 | 32 | /** 33 | Cell标题处理block 34 | */ 35 | @property (nonatomic, copy) ECOColumnCellTitleBlock cellTitleBlock; 36 | 37 | /** 38 | 详情展示内容block 39 | */ 40 | @property (nonatomic, copy) ECODetailContentBlock contentBlock; 41 | 42 | @end 43 | 44 | -------------------------------------------------------------------------------- /Mac/Echo/Template/List/ECOTemplateTableHeaderCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOTemplateTableHeaderCell.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/5/23. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | @interface ECOTemplateTableHeaderCell : NSTableHeaderCell 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Mac/Echo/Template/List/ECOTemplateTableHeaderCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECOTemplateTableHeaderCell.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/5/23. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECOTemplateTableHeaderCell.h" 10 | 11 | @interface ECOTemplateTableHeaderCell() 12 | 13 | @end 14 | 15 | @implementation ECOTemplateTableHeaderCell 16 | 17 | 18 | - (instancetype)initTextCell:(NSString *)string { 19 | self = [super initTextCell:string]; 20 | if (self) { 21 | 22 | } 23 | return self; 24 | } 25 | - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 26 | [self drawInteriorWithFrame:cellFrame inView:controlView]; 27 | } 28 | 29 | - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 30 | NSColor *fillColor = [NSColor colorNamed:@"listDetail_header"]; 31 | NSColor *titleColor = [NSColor colorNamed:@"listDetail_headerTitle"]; 32 | [fillColor setFill]; 33 | NSRectFill(cellFrame); 34 | NSRange range = NSMakeRange(0, self.stringValue.length); 35 | NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:self.stringValue]; 36 | [attributedString addAttribute:NSForegroundColorAttributeName value:titleColor range:range]; 37 | [attributedString addAttribute:NSFontAttributeName value:[NSFont boldSystemFontOfSize:13] range:range]; 38 | self.attributedStringValue = attributedString; 39 | 40 | [super drawInteriorWithFrame:NSMakeRect(cellFrame.origin.x + 5, cellFrame.origin.y + 4, cellFrame.size.width, cellFrame.size.height) inView:controlView]; 41 | } 42 | - (void)highlight:(BOOL)flag withFrame:(NSRect)cellFrame inView:(NSView *)controlView { 43 | [self drawInteriorWithFrame:cellFrame inView:controlView]; 44 | } 45 | @end 46 | -------------------------------------------------------------------------------- /Mac/Echo/Template/Outline/ECOOlNodeFactory.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOOlNodeFactory.h 3 | // Echo 4 | // 5 | // Created by Lux on 2019/8/2. 6 | // Copyright © 2019 陈爱彬. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ECOOlNode.h" 11 | 12 | #define NodeType NSString *, ECOOlNode * 13 | 14 | typedef NSDictionary ECONodeDict; 15 | 16 | NS_ASSUME_NONNULL_BEGIN 17 | 18 | @interface ECOOlNodeFactory : NSObject 19 | 20 | /*! 21 | 工厂将数据结构都做成字典并以 ECOOlNode 对象存储, data 只支持 NSArray 和 NSDictionary 22 | @warning 数组也会转成字典,key 值特殊处理成 @"[index]",可以使用 keyWithIndex: 和 arrayIndexWithKey: 两个方法对 index 进行转化 23 | */ 24 | + (ECONodeDict *)nodeInfosFromData:(id)data; 25 | 26 | /*! 27 | 获得被排序后的 key 值队列 28 | */ 29 | + (NSArray *)sortKeysFromDictionary:(NSDictionary *)dict; 30 | 31 | /*! 32 | 工厂加工数组对应的 (NSInteger)index 为 key : @"[index]" 33 | */ 34 | + (NSString *)keyWithIndex:(NSInteger)index; 35 | 36 | /*! 37 | 工厂将字符串 key : @"[index]" 转换为 (NSInteger)index 38 | #warning 如果返回 NSNotFound 表示从 key 中获取 index 失败; 39 | */ 40 | + (NSInteger)arrayIndexWithKey:(NSString *)key; 41 | 42 | @end 43 | 44 | NS_ASSUME_NONNULL_END 45 | -------------------------------------------------------------------------------- /Mac/Echo/Template/Outline/ECOString.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOUIString.h 3 | // 4 | // Created by Lux on 2019/3/11. 5 | // Copyright © 2019 Lux. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface ECOString : NSObject 11 | 12 | 13 | + (NSAttributedString *)attributedWithValue:(id)value 14 | highlightText:(NSString *)highlightText; 15 | 16 | + (NSAttributedString *)attributedWithValue:(id)value 17 | highlightText:(NSString *)highlightText 18 | highlightColor:(NSColor *)color; 19 | 20 | @end 21 | 22 | -------------------------------------------------------------------------------- /Mac/Echo/Template/Outline/ECOTemplateOutlineCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOTemplateOutlineCell.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/9/16. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECOTemplateOutlineCell : NSTableCellView 14 | 15 | @property (nonatomic, assign) BOOL selectedMark; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Mac/Echo/Template/Outline/ECOTemplateOutlineCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECOTemplateOutlineCell.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/9/16. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECOTemplateOutlineCell.h" 10 | 11 | @interface ECOTemplateOutlineCell() 12 | 13 | @property (weak) IBOutlet NSBox *bgBox; 14 | @end 15 | 16 | @implementation ECOTemplateOutlineCell 17 | 18 | - (void)drawRect:(NSRect)dirtyRect { 19 | [super drawRect:dirtyRect]; 20 | 21 | // Drawing code here. 22 | } 23 | 24 | - (void)setSelectedMark:(BOOL)selectedMark { 25 | _selectedMark = selectedMark; 26 | self.bgBox.hidden = !_selectedMark; 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Mac/Echo/Template/Outline/ECOTemplateOutlineViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOTemplateOutlineViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/21. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOPluginUIProtocol.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface ECOTemplateOutlineViewController : NSViewController 15 | 16 | 17 | @property (nonatomic, weak) __kindof ECOBasePlugin *plugin; 18 | 19 | @end 20 | 21 | NS_ASSUME_NONNULL_END 22 | -------------------------------------------------------------------------------- /Mac/Echo/Tools/DarkMode/ECODarkModeHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECODarkModeHelper.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/7/12. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECODarkModeHelper : NSObject 14 | 15 | + (instancetype)shared; 16 | 17 | /** 18 | 注册Dark Mode变更回调 19 | 20 | @param obj 要注册的对象,可以是ViewController或view,这里是弱引用 21 | @param eventHandler 变更时的回调,这里是强引用 22 | @param flag 是否立即回调eventHandler 23 | */ 24 | - (void)subscribeDarkModeChangedEvent:(id)obj 25 | handler:(void(^)(BOOL isDarkMode))eventHandler 26 | immediately:(BOOL)flag; 27 | 28 | 29 | /** 30 | 取消注册Dark Mode变更回调,可在dealloc里调用该方法 31 | 32 | @param obj 之前注册的对象 33 | */ 34 | - (void)unsubscribeDarkModeChangedEvent:(id)obj; 35 | 36 | 37 | /** 38 | 是否是Dark Mode 39 | 40 | @return 当前系统是否为深色模式 41 | */ 42 | - (BOOL)isDarkMode; 43 | 44 | @end 45 | 46 | NS_ASSUME_NONNULL_END 47 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECOCustomWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOCustomWindowController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/29. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECOCustomWindowController : NSWindowController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECOCustomWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECOCustomWindowController.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/29. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECOCustomWindowController.h" 10 | 11 | @interface ECOCustomWindowController () 12 | 13 | @end 14 | 15 | @implementation ECOCustomWindowController 16 | 17 | - (void)windowDidLoad { 18 | [super windowDidLoad]; 19 | 20 | // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. 21 | self.window.titleVisibility = NSWindowTitleHidden; 22 | self.window.titlebarAppearsTransparent = YES; 23 | self.window.styleMask |= NSWindowStyleMaskFullSizeContentView; 24 | 25 | self.window.backgroundColor = [NSColor colorNamed:@"deviceBgColor"]; 26 | 27 | [self.window center]; 28 | } 29 | @end 30 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECODeviceConnectView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECODeviceConnectView.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/9/24. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOProjectModel.h" 11 | 12 | typedef void(^ECOAuthorizeConnectBlock)(ECOProjectModel *project); 13 | 14 | @interface ECODeviceConnectView : NSView 15 | 16 | @property (nonatomic, strong) ECOProjectModel *projectInfo; 17 | @property (nonatomic, copy) ECOAuthorizeConnectBlock connectBlock; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECODeviceTableCellView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECODeviceTableCellView.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/5/15. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | @interface ECODeviceTableCellView : NSTableCellView 12 | 13 | @property (nonatomic, assign, getter=isSelected) BOOL selected; 14 | @property (nonatomic, copy) NSString *deviceName; 15 | @property (nonatomic, assign) BOOL isConnected; 16 | 17 | @property (nonatomic, assign) BOOL isDevice; 18 | @property (nonatomic, assign) BOOL isAuthorized; 19 | 20 | - (void)refreshView; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECODevicesListViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECODevicesListViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/5/14. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOChannelDeviceInfo.h" 11 | 12 | @class ECODeviceModel; 13 | typedef void(^ECODeviceSelectedChangedBlock)(void); 14 | typedef void(^ECODeviceConnectedBlock)(ECODeviceModel *deviceInfo); 15 | 16 | @interface ECODevicesListViewController : NSViewController 17 | 18 | @property (nonatomic, copy) ECODeviceSelectedChangedBlock selectedBlock; 19 | @property (nonatomic, copy) ECODeviceConnectedBlock connectBlock; 20 | 21 | - (void)refresh; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECONoTriangleOutlineView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONoTriangleOutlineView.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/8/5. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | //移除NSOutlineView的disclosure triangle 14 | @interface ECONoTriangleOutlineView : NSOutlineView 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECONoTriangleOutlineView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECONoTriangleOutlineView.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/8/5. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECONoTriangleOutlineView.h" 10 | 11 | @implementation ECONoTriangleOutlineView 12 | 13 | - (NSRect)frameOfOutlineCellAtRow:(NSInteger)row { 14 | return NSZeroRect; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECOPluginDetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOPluginDetailViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/29. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOBasePlugin.h" 11 | 12 | @class ECOProjectModel; 13 | @interface ECOPluginDetailViewController : NSTabViewController 14 | 15 | - (void)appendPlugin:(__kindof ECOBasePlugin *)plugin; 16 | 17 | - (void)selectPlugin:(__kindof ECOBasePlugin *)plugin; 18 | 19 | - (void)refreshWithFlag:(BOOL)refreshDetail; 20 | 21 | - (void)showConnectViewWithProject:(ECOProjectModel *)project; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECOPluginItemsOutlineView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOPluginItemsOutlineView.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/11/4. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECOPluginItemsOutlineView : NSOutlineView 14 | 15 | @property (nonatomic, assign) NSInteger menuRow; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECOPluginItemsOutlineView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECOPluginItemsOutlineView.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/11/4. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECOPluginItemsOutlineView.h" 10 | 11 | @implementation ECOPluginItemsOutlineView 12 | 13 | - (NSMenu *)menuForEvent:(NSEvent *)event { 14 | NSPoint pt = [self convertPoint:[event locationInWindow] fromView:nil]; 15 | NSInteger row = [self rowAtPoint:pt]; 16 | if (row < 0 || [event type] != NSEventTypeRightMouseDown) { 17 | return [super menuForEvent:event]; 18 | } 19 | self.menuRow = row; 20 | return self.menu; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECOPluginItemsViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOPluginItemsViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/30. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOBasePlugin.h" 11 | 12 | typedef void(^ECOPluginItemSelectedBlock)(void); 13 | 14 | @interface ECOPluginItemsViewController : NSViewController 15 | 16 | @property (nonatomic, copy) ECOPluginItemSelectedBlock selectedBlock; 17 | 18 | - (void)refresh; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECOPluginTableCellView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOPluginTableCellView.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/30. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | @interface ECOPluginTableCellView : NSTableCellView 12 | 13 | @property (nonatomic, copy) NSString *title; 14 | @property (nonatomic, copy) NSString *appIcon; 15 | @property (nonatomic, copy) NSString *pluginDefaultIcon; 16 | @property (nonatomic, copy) NSString *pluginSelectedIcon; 17 | @property (nonatomic, assign) BOOL rootNode; 18 | @property (nonatomic, assign) BOOL isSelected; 19 | @property (nonatomic, assign) BOOL showTriangle; 20 | 21 | - (void)refreshView; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECOSplitView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOSplitView.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/8/20. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECOSplitView : NSSplitView 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECOSplitView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECOSplitView.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/8/20. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECOSplitView.h" 10 | 11 | @implementation ECOSplitView 12 | 13 | - (void)drawRect:(NSRect)dirtyRect { 14 | [super drawRect:dirtyRect]; 15 | 16 | // Drawing code here. 17 | } 18 | 19 | - (void)drawDividerInRect:(NSRect)rect { 20 | 21 | } 22 | 23 | - (CGFloat)dividerThickness { 24 | return 0.f; 25 | } 26 | @end 27 | -------------------------------------------------------------------------------- /Mac/Echo/UI/ECOSplitViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOSplitViewController.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/29. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECOSplitViewController : NSSplitViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Mac/Echo/jsonViewer/json-viewer-dark-theme.css: -------------------------------------------------------------------------------- 1 | .json-container { 2 | color: #adadad; 3 | font-size: 13px; 4 | line-height: 1.2; 5 | font-family: monospace; 6 | padding-left: 0; 7 | margin-left: 20px; 8 | } 9 | .json-container, 10 | .json-container ul{ 11 | list-style: none !important; 12 | } 13 | .json-container ul{ 14 | padding: 0px !important; 15 | padding-left: 20px !important; 16 | margin: 0px !important; 17 | } 18 | 19 | .json-container li { 20 | position: relative; 21 | } 22 | 23 | .json-container > li > .key, 24 | .json-container .array .key{ 25 | display: none; 26 | } 27 | 28 | .json-container .array .object .key{ 29 | display: inline; 30 | } 31 | 32 | .json-container li:after { 33 | content: ","; 34 | } 35 | 36 | .json-container li:last-child:after { 37 | content: ""; 38 | } 39 | 40 | .json-container .null{ 41 | color: #49a7fc; 42 | } 43 | .json-container .string{ 44 | color: #00ff88; 45 | } 46 | .json-container .number{ 47 | color: #ff4040; 48 | } 49 | .json-container .boolean{ 50 | color: #ff8048; 51 | } 52 | .json-container .key{ 53 | color: #bababa; 54 | } 55 | .json-container .expanded{ 56 | cursor: pointer; 57 | } 58 | 59 | .json-container .expanded:before{ 60 | content: "-"; 61 | font-size: 16px; 62 | width: 13px; 63 | text-align: center; 64 | line-height: 13px; 65 | font-family: sans-serif; 66 | color: #bababa; 67 | position: absolute; 68 | left: -15px; 69 | top: 3px; 70 | } 71 | 72 | .json-container .collapsed:before{ 73 | content: "+"; 74 | font-size: 14px; 75 | color: #bababa; 76 | top: 1px; 77 | } 78 | 79 | .json-container li .collapsed ~ .close:before { 80 | content: "... "; 81 | color: #bababa; 82 | } 83 | 84 | .json-container .hidden ~ ul { 85 | display: none; 86 | } 87 | -------------------------------------------------------------------------------- /Mac/Echo/jsonViewer/json-viewer-light-theme.css: -------------------------------------------------------------------------------- 1 | .json-container { 2 | font-size: 13px; 3 | line-height: 1.2; 4 | font-family: monospace; 5 | padding-left: 0; 6 | margin-left: 20px; 7 | } 8 | .json-container, 9 | .json-container ul{ 10 | list-style: none !important; 11 | } 12 | .json-container ul{ 13 | padding: 0px !important; 14 | padding-left: 20px !important; 15 | margin: 0px !important; 16 | } 17 | 18 | .json-container li { 19 | position: relative; 20 | } 21 | 22 | .json-container > li > .key, 23 | .json-container .array .key{ 24 | display: none; 25 | } 26 | 27 | .json-container .array .object .key{ 28 | display: inline; 29 | } 30 | 31 | .json-container li:after { 32 | content: ","; 33 | } 34 | 35 | .json-container li:last-child:after { 36 | content: ""; 37 | } 38 | 39 | .json-container .null{ 40 | color: #999; 41 | } 42 | .json-container .string{ 43 | color: #4e9a06; 44 | } 45 | .json-container .number{ 46 | color: #a40000; 47 | } 48 | .json-container .boolean{ 49 | color: #c4a000; 50 | } 51 | .json-container .key{ 52 | color: #204a87; 53 | } 54 | .json-container .expanded{ 55 | cursor: pointer; 56 | } 57 | 58 | .json-container .expanded:before{ 59 | content: "-"; 60 | font-size: 16px; 61 | width: 13px; 62 | text-align: center; 63 | line-height: 13px; 64 | font-family: sans-serif; 65 | color: #933; 66 | position: absolute; 67 | left: -15px; 68 | top: 3px; 69 | } 70 | 71 | .json-container .collapsed:before{ 72 | content: "+"; 73 | font-size: 14px; 74 | color: #000; 75 | top: 1px; 76 | } 77 | 78 | .json-container li .collapsed ~ .close:before { 79 | content: "... "; 80 | color: #999; 81 | } 82 | 83 | .json-container .hidden ~ ul { 84 | display: none; 85 | } -------------------------------------------------------------------------------- /Mac/Echo/jsonViewer/jsonviewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 36 | -------------------------------------------------------------------------------- /Mac/Echo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/15. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) { 12 | return NSApplicationMain(argc, argv); 13 | } 14 | -------------------------------------------------------------------------------- /Mac/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'Echo' do 5 | # Uncomment the next line if you're using Swift or would like to use dynamic frameworks 6 | # use_frameworks! 7 | 8 | pod 'EchoSDK', :path => '../', :subspecs => ['Core'] 9 | pod 'Masonry' 10 | 11 | end 12 | -------------------------------------------------------------------------------- /Mac/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - CocoaAsyncSocket (7.6.5) 3 | - EchoSDK/Core (0.0.8): 4 | - CocoaAsyncSocket 5 | - Masonry (1.1.0) 6 | 7 | DEPENDENCIES: 8 | - EchoSDK/Core (from `../`) 9 | - Masonry 10 | 11 | SPEC REPOS: 12 | trunk: 13 | - CocoaAsyncSocket 14 | - Masonry 15 | 16 | EXTERNAL SOURCES: 17 | EchoSDK: 18 | :path: "../" 19 | 20 | SPEC CHECKSUMS: 21 | CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 22 | EchoSDK: b3395f8a1b26289b556722a069e40ba368a0b022 23 | Masonry: 678fab65091a9290e40e2832a55e7ab731aad201 24 | 25 | PODFILE CHECKSUM: 0b91a250fb76a58eb333235430d240604b1c8589 26 | 27 | COCOAPODS: 1.10.1 28 | -------------------------------------------------------------------------------- /Sources/Client/ECOClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOClient.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/29. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOClientConfig.h" 11 | 12 | @interface ECOClient : NSObject 13 | 14 | /** 15 | EchoSDK配置 16 | */ 17 | @property (nonatomic, strong, readonly) ECOClientConfig *config; 18 | 19 | + (instancetype)sharedClient; 20 | 21 | /** 22 | 启动服务 23 | */ 24 | - (void)start; 25 | 26 | - (void)startWithConfig:(ECOClientConfig *)config; 27 | 28 | /** 29 | 停止服务 30 | */ 31 | - (void)stop; 32 | 33 | /** 34 | 注册插件 35 | 36 | @param plugin 插件Class 37 | */ 38 | - (void)registerPlugin:(Class)plugin; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Sources/Client/ECOClientConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOClientConfig.h 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/10/28. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface ECOClientConfig : NSObject 13 | 14 | /** 15 | * 默认获取CFBundleIdentifier作为appId,你也可以自己修改它 16 | */ 17 | @property (nonatomic, copy) NSString *appId; 18 | 19 | /** 20 | * 默认获取CFBundleDisplayName作为appName,你也可以自己修改它 21 | */ 22 | @property (nonatomic, copy) NSString *appName; 23 | 24 | @end 25 | 26 | NS_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /Sources/Client/ECOClientConfig.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECOClientConfig.m 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/10/28. 6 | // 7 | 8 | #import "ECOClientConfig.h" 9 | 10 | @implementation ECOClientConfig 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /Sources/Client/EchoSDKDefines.h: -------------------------------------------------------------------------------- 1 | // 2 | // EchoSDKDefines.h 3 | // EchoSDK 4 | // 5 | // Created by 陈爱彬 on 2019/8/8. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #ifndef EchoSDKDefines_h 10 | #define EchoSDKDefines_h 11 | 12 | #define EchoBundleName @"EchoSDKResource" 13 | 14 | #define EchoBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:EchoBundleName ofType:@"bundle"]] 15 | 16 | #define EchoHTMLKey @"html" 17 | #define EchoJSParams @"jsParams" 18 | #define EchoJSResult @"jsResult" 19 | 20 | 21 | #endif /* EchoSDKDefines_h */ 22 | -------------------------------------------------------------------------------- /Sources/Core/Access/ECOCoreManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOCoreManager.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/24. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOChannelDeviceInfo.h" 11 | #import "ECOBasePlugin.h" 12 | #import "ECOPacketClient.h" 13 | 14 | typedef void(^ECOManagerConnectDeviceBlock)(ECOChannelDeviceInfo *device, BOOL isConnected); 15 | 16 | typedef void(^ECOManagerAuthStateChangedBlock)(ECOChannelDeviceInfo *device, BOOL authState); 17 | typedef void(^ECOManagerRequestAuthStateBlock)(ECOChannelDeviceInfo *device, BOOL authState); 18 | 19 | @interface ECOCoreManager : NSObject 20 | 21 | @property (nonatomic, copy) ECOManagerConnectDeviceBlock deviceBlock; 22 | @property (nonatomic, copy) ECOManagerAuthStateChangedBlock authStateChangedBlock; 23 | @property (nonatomic, copy) ECOManagerRequestAuthStateBlock requestAuthBlock; 24 | 25 | + (instancetype)shared; 26 | 27 | - (void)start; 28 | 29 | - (void)stop; 30 | 31 | /** 32 | 发送数据,内部做统一的结构封装 33 | 34 | @param data 要发送的数据,NSDictionary或者NSArray结构体 35 | @param type 数据类型,json或者普通数据内容 36 | @param plugin 插件 37 | @param device 要接收消息的设备,如果传入nil,则对所有已授权连接的设备发送消息 38 | */ 39 | - (void)sendPacketData:(id)data 40 | type:(ECOPacketDataType)type 41 | plugin:(__kindof ECOBasePlugin *)plugin 42 | toDevice:(ECOChannelDeviceInfo *)device; 43 | 44 | //发送授权数据 45 | - (void)sendAuthorizationMessageToDevice:(ECOChannelDeviceInfo *)device 46 | state:(ECOAuthorizeResponseType)responseType 47 | showAuthAlert:(BOOL)showAuthAlert; 48 | 49 | //链接IP地址的主机 50 | - (void)connectToClientIPAddress:(NSString *)ipAddress; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /Sources/Core/Access/ECOPluginsManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOPluginsManager.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/23. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOBasePlugin.h" 11 | #import "ECOChannelDeviceInfo.h" 12 | 13 | typedef void(^ECOPluginReceivedDataBlock)(ECOChannelDeviceInfo *device, __kindof ECOBasePlugin *plugin, id packetData); 14 | 15 | @interface ECOPluginsManager : NSObject 16 | 17 | @property (nonatomic, copy) ECOPluginReceivedDataBlock receivedBlock; 18 | 19 | + (instancetype)shared; 20 | 21 | - (void)clearPlugins; 22 | 23 | - (void)registerPlugin:(__kindof ECOBasePlugin *)plugin; 24 | 25 | //分发数据给对应的插件 26 | - (void)dispatchDevice:(ECOChannelDeviceInfo *)device 27 | plugin:(__kindof ECOBasePlugin *)plugin 28 | packet:(id)packetData; 29 | 30 | //设备授权状态发生变更 31 | - (void)device:(ECOChannelDeviceInfo *)device didChangedAuthState:(BOOL)isAuthed; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Sources/Core/Channel/Bonjour/ECONetServiceBrowser.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetServiceBrowser.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/17. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | typedef void(^ECONetServiceBrowserResolvedAddressesBlock)(NSArray *addresses, NSString *hostName); 12 | 13 | @interface ECONetServiceBrowser : NSObject 14 | 15 | @property (nonatomic, copy) ECONetServiceBrowserResolvedAddressesBlock addressesBlock; 16 | 17 | - (void)startBrowsing; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Sources/Core/Channel/Bonjour/ECONetServicePublisher.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetServicePublisher.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/17. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | @interface ECONetServicePublisher : NSObject 12 | 13 | - (void)startPublish; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Sources/Core/Channel/ECOBaseChannel.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECOBaseChannel.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/18. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECOBaseChannel.h" 10 | 11 | @implementation ECOBaseChannel 12 | 13 | - (instancetype)initWithDelegate:(id)delegate { 14 | self = [super init]; 15 | if (self) { 16 | self.delegate = delegate; 17 | //目前使用授权连接机制,如果想自动连接已发现的设备,将该值改为ECOChannelConnectType_Auto 18 | self.connectType = ECOChannelConnectType_Authorization; 19 | [self setupChannel]; 20 | } 21 | return self; 22 | } 23 | 24 | //初始化Channel,供子类调用,该方法会在初始化后自动被调用 25 | - (void)setupChannel { 26 | 27 | } 28 | 29 | // 是否已连接到Mac客户端 30 | - (BOOL)isConnected { 31 | return NO; 32 | } 33 | @end 34 | -------------------------------------------------------------------------------- /Sources/Core/Channel/ECOChannelAppInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOChannelAppInfo.h 3 | // EchoSDK 4 | // 5 | // Created by 陈爱彬 on 2019/10/30. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | @interface ECOChannelAppInfo : NSObject 12 | 13 | @property (nonatomic, copy) NSString *appId; 14 | @property (nonatomic, copy) NSString *appName; 15 | @property (nonatomic, copy) NSString *appShortVersion; 16 | @property (nonatomic, copy) NSString *appVersion; 17 | @property (nonatomic, copy) NSString *appIcon; 18 | 19 | - (instancetype)initWithDictionary:(NSDictionary *)dict; 20 | 21 | - (NSDictionary *)toDictionary; 22 | 23 | //由外部设置通用的appid和appname 24 | + (void)setUniqueAppId:(NSString *)appId 25 | appName:(NSString *)appName; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Sources/Core/Channel/ECOChannelDeviceInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOChannelDeviceInfo.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/17. Maintain by 陈爱彬 6 | // Description 设备信息 7 | // 8 | 9 | #import 10 | #import "ECOChannelAppInfo.h" 11 | 12 | typedef NS_ENUM(NSInteger, ECODeviceType) { 13 | ECODeviceType_Simulator = 0, //模拟器 14 | ECODeviceType_Device, //真机 15 | ECODeviceType_MacApp, //Mac客户端 16 | }; 17 | 18 | typedef NS_ENUM(NSInteger, ECOAuthorizeResponseType) { 19 | ECOAuthorizeResponseType_Deny = 0, //拒绝连接 20 | // ECOAuthorizeResponseType_AllowOnce, //允许本次 21 | ECOAuthorizeResponseType_AllowAlways, //始终允许 22 | }; 23 | 24 | @interface ECOChannelDeviceInfo : NSObject 25 | 26 | @property (nonatomic, copy) NSString *hostName; 27 | @property (nonatomic, copy, readonly) NSString *ipAddress; 28 | @property (nonatomic, copy, readonly) NSString *uuid; 29 | @property (nonatomic, copy, readonly) NSString *deviceName; 30 | @property (nonatomic, copy, readonly) NSString *systemVersion; 31 | @property (nonatomic, copy, readonly) NSString *deviceModel; 32 | @property (nonatomic, assign, readonly) ECODeviceType deviceType; 33 | @property (nonatomic, assign) ECOAuthorizeResponseType authorizedType; 34 | @property (nonatomic, assign) BOOL showAuthAlert; 35 | @property (nonatomic, assign) BOOL isConnected; 36 | @property (nonatomic, strong, readonly) ECOChannelAppInfo *appInfo; 37 | 38 | /** 39 | 透传数据 40 | */ 41 | @property (nonatomic, copy) NSDictionary *extraData; 42 | 43 | //解析网络信息传输过来的设备信息 44 | - (instancetype)initWithData:(NSData *)data; 45 | 46 | - (NSDictionary *)toJSONObject; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /Sources/Core/Channel/ECOUSBChannel.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOUSBChannel.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/16. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECOBaseChannel.h" 10 | 11 | typedef NS_ENUM(NSInteger, ECOUSBChannelType) { 12 | ECOUSBChannelType_Command = 100, 13 | ECOUSBChannelType_TextMessage = 101, 14 | ECOUSBChannelType_Ping = 102, 15 | ECOUSBChannelType_Pong = 103, 16 | }; 17 | 18 | typedef struct _ECOUSBChannelTextFrame { 19 | uint32_t length; 20 | uint8_t utf8text[0]; 21 | } ECOUSBChannelTextFrame; 22 | 23 | typedef void(^ECOUSBChannelDidAttachBlock)(NSString *ipAddress); 24 | 25 | @interface ECOUSBChannel : ECOBaseChannel 26 | 27 | @property (nonatomic, copy) ECOUSBChannelDidAttachBlock attachBlock; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Sources/Core/Channel/PeerTalk/PTPrivate.h: -------------------------------------------------------------------------------- 1 | #if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && (!defined(__IPHONE_6_0) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_6_0)) || \ 2 | (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && (!defined(__MAC_10_8) || __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_8)) 3 | #define PT_DISPATCH_RETAIN_RELEASE 1 4 | #else 5 | #define PT_DISPATCH_RETAIN_RELEASE 0 6 | #endif 7 | 8 | #if PT_DISPATCH_RETAIN_RELEASE 9 | #define PT_PRECISE_LIFETIME 10 | #define PT_PRECISE_LIFETIME_UNUSED 11 | #else 12 | #define PT_PRECISE_LIFETIME __attribute__((objc_precise_lifetime)) 13 | #define PT_PRECISE_LIFETIME_UNUSED __attribute__((objc_precise_lifetime, unused)) 14 | #endif 15 | -------------------------------------------------------------------------------- /Sources/Core/ECOCoreDefines.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOCoreDefines.h 3 | // EchoSDK 4 | // 5 | // Created by 陈爱彬 on 2019/8/14. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #ifndef ECOCoreDefines_h 10 | #define ECOCoreDefines_h 11 | 12 | typedef NS_ENUM(NSInteger, ECOPacketDataType) { 13 | ECOPacketDataType_JSON = 0, //json结构,默认值 14 | ECOPacketDataType_Data, //普通NSData数据 15 | }; 16 | 17 | #endif /* ECOCoreDefines_h */ 18 | -------------------------------------------------------------------------------- /Sources/Core/Service/ECOPacketClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOPacketClient.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/4/24. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOChannelDeviceInfo.h" 11 | #import "ECOChannelManager.h" 12 | #import "ECOBasePlugin.h" 13 | 14 | typedef void(^ECOPacketClientReceivedBlock)(ECOChannelDeviceInfo *device, NSData *data, NSDictionary *extraInfo); 15 | typedef void(^ECOPacketClientDeviceConnectedBlock)(ECOChannelDeviceInfo *device, BOOL isConnected); 16 | 17 | typedef void(^ECOPacketClientAuthStateChangedBlock)(ECOChannelDeviceInfo *device, BOOL authState); 18 | typedef void(^ECOPacketClientRequestAuthStateBlock)(ECOChannelDeviceInfo *device, BOOL authState); 19 | 20 | @interface ECOPacketClient : NSObject 21 | 22 | @property (nonatomic, copy) ECOPacketClientReceivedBlock receivedBlock; 23 | @property (nonatomic, copy) ECOPacketClientDeviceConnectedBlock deviceBlock; 24 | 25 | @property (nonatomic, copy) ECOPacketClientAuthStateChangedBlock authStateChangedBlock; 26 | @property (nonatomic, copy) ECOPacketClientRequestAuthStateBlock requestAuthBlock; 27 | 28 | //发送数据,data数据由接入层传入 29 | - (void)sendPacket:(NSData *)packet 30 | type:(ECOPacketDataType)type 31 | extraInfo:(NSDictionary *)extraInfo 32 | plugin:(__kindof ECOBasePlugin *)plugin 33 | toDevice:(ECOChannelDeviceInfo *)device; 34 | 35 | //发送授权数据 36 | - (void)sendAuthorizationMessageToDevice:(ECOChannelDeviceInfo *)device 37 | state:(ECOAuthorizeResponseType)responseType 38 | showAuthAlert:(BOOL)showAuthAlert; 39 | 40 | //链接IP地址的主机 41 | - (void)connectToClientIPAddress:(NSString *)ipAddress; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Sources/Plugins/Basic/ECOSwizzle.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOSwizzle.h 3 | // Pods 4 | // 5 | // Created by zhanghe on 2019/8/7. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface ECOSwizzle : NSObject 13 | 14 | + (void)swizzleInstanceMethodWithClass:(Class)classObject fromSelector:(SEL)fromSelector toSelector:(SEL)toSelector; 15 | + (void)swizzleClassMethodWithClass:(Class)classObject fromSelector:(SEL)fromSelector toSelector:(SEL)toSelector; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Sources/Plugins/Basic/ECOSwizzle.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECOSwizzle.m 3 | // Pods 4 | // 5 | // Created by zhanghe on 2019/8/7. 6 | // 7 | 8 | #import "ECOSwizzle.h" 9 | #import 10 | 11 | @implementation ECOSwizzle 12 | 13 | + (void)swizzleInstanceMethodWithClass:(Class)class fromSelector:(SEL)fromSelector toSelector:(SEL)toSelector { 14 | Method fromMethod = class_getInstanceMethod(class, fromSelector); 15 | Method toMethod = class_getInstanceMethod(class, toSelector); 16 | 17 | if (class_addMethod(class, fromSelector, method_getImplementation(toMethod), method_getTypeEncoding(toMethod))) { 18 | class_replaceMethod(class, toSelector, method_getImplementation(fromMethod), method_getTypeEncoding(fromMethod)); 19 | } else { 20 | method_exchangeImplementations(fromMethod, toMethod); 21 | } 22 | } 23 | 24 | + (void)swizzleClassMethodWithClass:(Class)class fromSelector:(SEL)fromSelector toSelector:(SEL)toSelector { 25 | Method fromMethod = class_getClassMethod(class, fromSelector); 26 | Method toMethod = class_getClassMethod(class, toSelector); 27 | class = object_getClass((id)class); 28 | 29 | if (class_addMethod(class, fromSelector, method_getImplementation(toMethod), method_getTypeEncoding(toMethod))) { 30 | class_replaceMethod(class, toSelector, method_getImplementation(fromMethod), method_getTypeEncoding(fromMethod)); 31 | } else { 32 | method_exchangeImplementations(fromMethod, toMethod); 33 | } 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Sources/Plugins/Crash/ECOCrashFileInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOCrashFileInfo.h 3 | // EchoSDK 4 | // 5 | // Created by Lux on 2019/11/4. 6 | // 7 | 8 | #import 9 | 10 | /*! 11 | 崩溃类型 12 | 参考: 13 | https://juejin.im/post/5d76184ce51d4561d106cc65 14 | */ 15 | typedef NS_ENUM(NSInteger, ECOCrashType) { 16 | /*! 17 | 系统异常 18 | */ 19 | ECOCrashTypeUncaught, 20 | 21 | /*! 22 | 内核异常 23 | */ 24 | ECOCrashTypeSignal, 25 | }; 26 | 27 | NS_ASSUME_NONNULL_BEGIN 28 | 29 | @interface ECOCrashFileInfo : NSObject 30 | 31 | /*! 32 | 文件名,文件名由 creatDate 和 crashType 决定 33 | */ 34 | @property (nonatomic, copy, readonly) NSString *fileName; 35 | 36 | /*! 37 | 文件存储路径 38 | */ 39 | @property (nonatomic, copy, readonly) NSString *filePath; 40 | 41 | /*! 42 | 文件目录 43 | */ 44 | @property (nonatomic, copy) NSString *fileDirctory; 45 | 46 | /*! 47 | 崩溃详情 48 | */ 49 | @property (nonatomic, copy) NSString *crashInfo; 50 | 51 | /*! 52 | 文件的创建日期,会在调用 newWithContent 时创建 53 | */ 54 | @property (nonatomic, copy, readonly) NSDate *crashDate; 55 | @property (nonatomic, copy, readonly) NSString *crashDateString; 56 | 57 | /*! 58 | 崩溃类型 59 | */ 60 | @property (nonatomic, assign) ECOCrashType crashType; 61 | @property (nonatomic, copy) NSString *crashTypeString; 62 | 63 | /*! 64 | 通过文件类型和崩溃信息创建一个崩溃日志对象(本地还未写入) 65 | */ 66 | - (instancetype)initWithCrashInfo:(NSString *)crashInfo type:(ECOCrashType)type; 67 | 68 | /*! 69 | 通过读取文件路径创建一个崩溃日志文件对象; 70 | */ 71 | - (instancetype)initWithFilePath:(NSString *)filePath; 72 | 73 | 74 | @end 75 | 76 | NS_ASSUME_NONNULL_END 77 | -------------------------------------------------------------------------------- /Sources/Plugins/Crash/ECOCrashFileManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOCrashFileManager.h 3 | // EchoSDK 4 | // 5 | // Created by Lux on 2019/11/4. 6 | // 7 | 8 | #import 9 | #import "ECOCrashFileInfo.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECOCrashFileManager : NSObject 14 | 15 | /*! 16 | 用于崩溃时本地写入一个崩溃文本 17 | */ 18 | + (void)saveCrashType:(ECOCrashType)type info:(NSString *)info; 19 | 20 | /*! 21 | 获得已缓存的崩溃日志 22 | @param isSortedByDate : 是否根据日期进行排序 23 | */ 24 | + (NSArray *)crashFiles:(BOOL)isSortedByDate ; 25 | 26 | @end 27 | 28 | NS_ASSUME_NONNULL_END 29 | -------------------------------------------------------------------------------- /Sources/Plugins/Crash/ECOCrashPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOCrashPlugin.h 3 | // EchoSDK 4 | // 5 | // Created by Lux on 2019/8/26. 6 | // 7 | 8 | #import "ECOBasePlugin.h" 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface ECOCrashPlugin : ECOBasePlugin 13 | 14 | @end 15 | 16 | NS_ASSUME_NONNULL_END 17 | -------------------------------------------------------------------------------- /Sources/Plugins/Crash/ECOCrashSignalExceptionHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOCrashSignalExceptionHandler.h 3 | // EchoSDK 4 | // 5 | // Created by Lux on 2019/8/26. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface ECOCrashSignalExceptionHandler : NSObject 13 | 14 | + (void)registerHandler; 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Sources/Plugins/Crash/ECOCrashUncaughtExceptionHandler.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOCrashUncaughtExceptionHandler.h 3 | // EchoSDK 4 | // 5 | // Created by Lux on 2019/8/26. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface ECOCrashUncaughtExceptionHandler : NSObject 13 | 14 | + (void)registerHandler; 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Sources/Plugins/GeneralLog/ECOGeneralLogManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOGeneralLogManager.h 3 | // EchoSDK 4 | // 5 | // Created by yxj on 2019/8/6. 6 | // 7 | 8 | #import 9 | 10 | typedef void(^ECORecvDictBlock)(NSDictionary * _Nullable recDict); 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface ECOGeneralLogManager : NSObject 15 | 16 | @property (nonatomic, copy, nullable) ECORecvDictBlock addBlock; 17 | 18 | + (instancetype)sharedManager; 19 | 20 | ///> {logType: error/warn/..., log:str } 21 | - (void)addRecord:(NSDictionary *)rec; 22 | ///> {logType: general, log:str } 23 | - (void)addGeneralLog:(NSString *)log; 24 | - (void)addVerboseLog:(NSString *)log; 25 | - (void)addDebugLog:(NSString *)log; 26 | - (void)addInfoLog:(NSString *)log; 27 | - (void)addWarnLog:(NSString *)log; 28 | - (void)addErrorLog:(NSString *)log; 29 | - (void)addLog:(NSString *)log customType:(NSString *)type; 30 | 31 | @end 32 | 33 | NS_ASSUME_NONNULL_END 34 | -------------------------------------------------------------------------------- /Sources/Plugins/GeneralLog/ECOGeneralLogPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOGeneralLogPlugin.h 3 | // EchoSDK 4 | // 5 | // Created by yxj on 2019/8/6. 6 | // 7 | 8 | #import "ECOBasePlugin.h" 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface ECOGeneralLogPlugin : ECOBasePlugin 13 | 14 | @end 15 | 16 | NS_ASSUME_NONNULL_END 17 | -------------------------------------------------------------------------------- /Sources/Plugins/MemoryLeak/ECOMLeaksMessenger.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOMLeaksMessenger.h 3 | // EchoSDK 4 | // 5 | // Created by 陈爱彬 on 2020/1/7. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECOMLeaksMessenger : NSObject 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Sources/Plugins/MemoryLeak/ECOMemoryLeakManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOMemoryLeakManager.h 3 | // Echo 4 | // 5 | // Created by yxj on 2019/7/31. 6 | // 7 | 8 | #import 9 | 10 | typedef void(^EchoReceivedMemoryLeakRecBlock)(NSDictionary *recDict); 11 | 12 | 13 | 14 | @interface ECOMemoryLeakManager : NSObject 15 | 16 | @property (nonatomic, copy) EchoReceivedMemoryLeakRecBlock addBlock; 17 | 18 | + (instancetype)sharedManager; 19 | 20 | - (void)addRecord:(NSDictionary *)rec; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Sources/Plugins/MemoryLeak/ECOMemoryLeakManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECOMemoryLeakManager.m 3 | // Echo 4 | // 5 | // Created by yxj on 2019/7/31. 6 | // 7 | 8 | #import "ECOMemoryLeakManager.h" 9 | 10 | @interface ECOMemoryLeakManager() 11 | 12 | @property (nonatomic, strong) NSDateFormatter *dateFormatter; 13 | 14 | @end 15 | 16 | @implementation ECOMemoryLeakManager 17 | 18 | + (instancetype)sharedManager { 19 | static ECOMemoryLeakManager *_manager = nil; 20 | static dispatch_once_t onceToken; 21 | dispatch_once(&onceToken, ^{ 22 | _manager = [[ECOMemoryLeakManager alloc] init]; 23 | }); 24 | return _manager; 25 | } 26 | 27 | - (instancetype)init { 28 | self = [super init]; 29 | if (self) { 30 | 31 | } 32 | return self; 33 | } 34 | 35 | - (void)addRecord:(NSDictionary *)rec { 36 | if (self.addBlock) { 37 | NSMutableDictionary *dictM = [NSMutableDictionary dictionary]; 38 | [dictM addEntriesFromDictionary:rec]; 39 | NSDate *date = [NSDate date]; 40 | NSString *time = [self.dateFormatter stringFromDate:date]; 41 | [dictM setValue:time forKey:@"time"]; 42 | self.addBlock(dictM); 43 | } 44 | } 45 | 46 | 47 | - (NSDateFormatter *)dateFormatter { 48 | if (!_dateFormatter) { 49 | _dateFormatter = [[NSDateFormatter alloc] init]; 50 | _dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss"; 51 | } 52 | return _dateFormatter; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /Sources/Plugins/MemoryLeak/ECOMemoryLeakPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOMemoryLeakPlugin.h 3 | // Echo 4 | // 5 | // Created by yxj on 2019/7/31. 6 | // 7 | 8 | #import "ECOBasePlugin.h" 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface ECOMemoryLeakPlugin : ECOBasePlugin 13 | 14 | @end 15 | 16 | NS_ASSUME_NONNULL_END 17 | -------------------------------------------------------------------------------- /Sources/Plugins/MockGPS/CLLocationManager+ECHO.h: -------------------------------------------------------------------------------- 1 | // 2 | // CLLocationManager+ECHO.h 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/8/22. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface CLLocationManager (ECHO) 13 | 14 | - (void)echo_setDelegate:(id)delegate; 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Sources/Plugins/MockGPS/CLLocationManager+ECHO.m: -------------------------------------------------------------------------------- 1 | // 2 | // CLLocationManager+ECHO.m 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/8/22. 6 | // 7 | 8 | #import "CLLocationManager+ECHO.h" 9 | #import "ECOMockGPSManager.h" 10 | 11 | @implementation CLLocationManager (ECHO) 12 | 13 | - (void)echo_setDelegate:(id)delegate { 14 | [self echo_setDelegate:[ECOMockGPSManager sharedInstance]]; 15 | [[ECOMockGPSManager sharedInstance] addLocationManager:self delegate:delegate]; 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Sources/Plugins/MockGPS/ECOMockGPSManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOMockGPSManager.h 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/8/22. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface ECOMockGPSManager : NSObject 13 | 14 | + (instancetype)sharedInstance; 15 | - (void)addLocationManager:(id)manager delegate:(id)delegate; 16 | - (void)mockLocation:(CLLocation *)location; 17 | 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /Sources/Plugins/MockGPS/ECOMockGPSPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOMockGPSPlugin.h 3 | // EchoSDK 4 | // 5 | // Created by 陈爱彬 on 2019/8/6. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECOBasePlugin.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECOMockGPSPlugin : ECOBasePlugin 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Sources/Plugins/NSLog/ECONSLogManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONSLogManager.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/5/29. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | typedef void(^EchoReceivedNSLogBlock)(NSDictionary *logDict); 12 | 13 | @interface ECONSLogManager : NSObject 14 | 15 | @property (nonatomic, copy) EchoReceivedNSLogBlock addBlock; 16 | 17 | + (instancetype)shared; 18 | 19 | - (void)addNSLog:(NSString *)log; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Sources/Plugins/NSLog/ECONSLogPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCEagleLogPlugin.h 3 | // DCAppDevTool 4 | // 5 | // Created by 陈爱彬 on 2019/5/29. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | #import "ECOBasePlugin.h" 11 | 12 | @interface ECONSLogPlugin : ECOBasePlugin 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Sources/Plugins/NSUserDefaults/ECONSUserDefaultsPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONSUserDefaultsPlugin.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/21. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECOBasePlugin.h" 10 | 11 | /*! 12 | NSUserDefaultsPlugin 插件 13 | 可接受的命令为: 14 | 1、修改数据: 15 | @{ 16 | @"cmd" : @"set", 17 | @"info" : @{ 18 | @"key" : @"key", 19 | @"value" : value 20 | } 21 | } 22 | 23 | 2、删除数据: 24 | @{ 25 | @"cmd" : @"del", 26 | @"info" : @{ 27 | @"key" : @"key", 28 | } 29 | } 30 | 31 | 3、更新数据 32 | @{ 33 | @"cmd" : @"refresh" 34 | } 35 | */ 36 | NS_ASSUME_NONNULL_BEGIN 37 | @interface ECONSUserDefaultsPlugin : ECOBasePlugin 38 | @end 39 | NS_ASSUME_NONNULL_END 40 | -------------------------------------------------------------------------------- /Sources/Plugins/Network/ECONSURLProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONSURLProtocol.h 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/8/5. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface ECONSURLProtocol : NSURLProtocol 13 | 14 | @end 15 | 16 | NS_ASSUME_NONNULL_END 17 | -------------------------------------------------------------------------------- /Sources/Plugins/Network/ECONetworkInterceptor.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkInterceptor.h 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/8/7. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @protocol ECONetworkInterceptorDelegate 13 | 14 | - (void)interceptedWithRequest:(NSURLRequest *)request 15 | data:(NSData *)data 16 | response:(NSURLResponse *)response 17 | error:(NSError *)error 18 | startTime:(NSDate *)startTime; 19 | 20 | @end 21 | 22 | @interface ECONetworkInterceptor : NSObject 23 | 24 | @property (nonatomic, weak) id delegate; 25 | 26 | + (instancetype)sharedInstance; 27 | 28 | - (void)interceptWithRequest:(NSURLRequest *)request 29 | data:(NSData *)data 30 | response:(NSURLResponse *)response 31 | error:(NSError *)error 32 | startTime:(NSDate *)startTime; 33 | 34 | 35 | @end 36 | 37 | NS_ASSUME_NONNULL_END 38 | -------------------------------------------------------------------------------- /Sources/Plugins/Network/ECONetworkInterceptor.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkInterceptor.m 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/8/7. 6 | // 7 | 8 | #import "ECONetworkInterceptor.h" 9 | 10 | static ECONetworkInterceptor *instance = nil; 11 | 12 | @implementation ECONetworkInterceptor 13 | 14 | + (instancetype)sharedInstance { 15 | static dispatch_once_t once; 16 | dispatch_once(&once, ^{ 17 | instance = [[ECONetworkInterceptor alloc] init]; 18 | }); 19 | return instance; 20 | } 21 | 22 | - (void)interceptWithRequest:(NSURLRequest *)request data:(NSData *)data response:(NSURLResponse *)response error:(nonnull NSError *)error startTime:(nonnull NSDate *)startTime { 23 | [self.delegate interceptedWithRequest:request data:data response:response error:error startTime:startTime]; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Sources/Plugins/Network/ECONetworkModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkModel.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/4. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECONetworkModel : NSObject 14 | 15 | /** 16 | 请求url 17 | */ 18 | @property (nonatomic, copy) NSString *urlString; 19 | /** 20 | cell标题 21 | */ 22 | @property (nonatomic, copy) NSString *title; 23 | /** 24 | 请求baseURL 25 | */ 26 | @property (nonatomic, copy) NSString *baseURL; 27 | /** 28 | 请求path 29 | */ 30 | @property (nonatomic, copy) NSString *path; 31 | /** 32 | 请求类型,GET或POST 33 | */ 34 | @property (nonatomic, copy) NSString *httpMethod; 35 | /** 36 | 配置的请求超时 37 | */ 38 | @property (nonatomic, copy) NSString *timeout; 39 | /** 40 | httpcode码,成功为200 41 | */ 42 | @property (nonatomic, assign) NSInteger code; 43 | /** 44 | 请求header 45 | */ 46 | @property (nonatomic, copy) NSDictionary *headers; 47 | /** 48 | 请求参数 49 | */ 50 | @property (nonatomic, copy) NSDictionary *urlParams; 51 | /** 52 | 回调header 53 | */ 54 | @property (nonatomic, copy) NSDictionary *responseHeader; 55 | /** 56 | 回调结果 57 | */ 58 | @property (nonatomic, copy) NSDictionary *content; 59 | /** 60 | body数据 61 | */ 62 | @property (nonatomic, strong) NSData *requestBody; 63 | /** 64 | 请求开始时间 65 | */ 66 | @property (nonatomic, strong) NSDate *startDate; 67 | /** 68 | 请求时间 69 | */ 70 | @property (nonatomic, strong) NSDate *endDate; 71 | /** 72 | 失败时error 73 | */ 74 | @property (nonatomic, strong) NSError *error; 75 | 76 | - (NSDictionary *)toDictionary; 77 | 78 | @end 79 | 80 | NS_ASSUME_NONNULL_END 81 | -------------------------------------------------------------------------------- /Sources/Plugins/Network/ECONetworkModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkModel.m 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/4. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECONetworkModel.h" 10 | 11 | @implementation ECONetworkModel 12 | 13 | - (NSDictionary *)toDictionary { 14 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 15 | [dict setValue:self.urlString forKey:@"url"]; 16 | [dict setValue:self.title forKey:@"title"]; 17 | [dict setValue:self.baseURL forKey:@"baseURL"]; 18 | [dict setValue:self.path forKey:@"path"]; 19 | [dict setValue:self.httpMethod forKey:@"method"]; 20 | [dict setValue:self.timeout forKey:@"timeout"]; 21 | [dict setValue:@(self.code).stringValue forKey:@"code"]; 22 | [dict setValue:self.headers forKey:@"headers"]; 23 | [dict setValue:self.urlParams forKey:@"urlParams"]; 24 | [dict setValue:self.responseHeader forKey:@"responseHeader"]; 25 | [dict setValue:self.content forKey:@"content"]; 26 | [dict setValue:self.requestBody forKey:@"body"]; 27 | [dict setValue:self.startDate forKey:@"startDate"]; 28 | [dict setValue:[NSDate date] forKey:@"endDate"]; 29 | if (self.error) { 30 | [dict setValue:self.error.description forKey:@"error"]; 31 | } 32 | return dict; 33 | } 34 | @end 35 | -------------------------------------------------------------------------------- /Sources/Plugins/Network/ECONetworkPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONetworkPlugin.h 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/8/2. 6 | // 7 | 8 | #import "ECOBasePlugin.h" 9 | #import "ECONetworkInterceptor.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECONetworkPlugin : ECOBasePlugin 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Sources/Plugins/Network/NSURLSessionConfiguration+ECHO.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSURLSessionConfiguration+ECHO.h 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/8/7. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface NSURLSessionConfiguration (ECHO) 13 | 14 | @end 15 | 16 | NS_ASSUME_NONNULL_END 17 | -------------------------------------------------------------------------------- /Sources/Plugins/Network/NSURLSessionConfiguration+ECHO.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSURLSessionConfiguration+ECHO.m 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/8/7. 6 | // 7 | 8 | #import "NSURLSessionConfiguration+ECHO.h" 9 | #import "ECOSwizzle.h" 10 | #import "ECONSURLProtocol.h" 11 | 12 | @implementation NSURLSessionConfiguration (ECHO) 13 | 14 | + (void)load { 15 | [ECOSwizzle swizzleClassMethodWithClass:[self class] fromSelector:@selector(defaultSessionConfiguration) toSelector:@selector(echo_defaultSessionConfiguration)]; 16 | [ECOSwizzle swizzleClassMethodWithClass:[self class] fromSelector:@selector(ephemeralSessionConfiguration) toSelector:@selector(echo_ephemeralSessionConfiguration)]; 17 | } 18 | 19 | + (NSURLSessionConfiguration *)echo_defaultSessionConfiguration { 20 | NSURLSessionConfiguration *configuration = [self echo_defaultSessionConfiguration]; 21 | [configuration addEchoNSURLProtocol]; 22 | return configuration; 23 | } 24 | 25 | + (NSURLSessionConfiguration *)echo_ephemeralSessionConfiguration { 26 | NSURLSessionConfiguration *configuration = [self echo_ephemeralSessionConfiguration]; 27 | [configuration addEchoNSURLProtocol]; 28 | return configuration; 29 | } 30 | 31 | - (void)addEchoNSURLProtocol { 32 | if ([self respondsToSelector:@selector(protocolClasses)] && [self respondsToSelector:@selector(setProtocolClasses:)]) { 33 | NSMutableArray *urlProtocolClasses = [NSMutableArray arrayWithArray:self.protocolClasses]; 34 | Class protoCls = ECONSURLProtocol.class; 35 | if (![urlProtocolClasses containsObject:protoCls]) { 36 | [urlProtocolClasses insertObject:protoCls atIndex:0]; 37 | } 38 | self.protocolClasses = urlProtocolClasses; 39 | } 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Sources/Plugins/Notification/ECONotificationInterceptor.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONotificationInterceptor.h 3 | // Pods 4 | // 5 | // Created by zhanghe on 2019/8/12. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @protocol ECONotificationInterceptorDelegate 13 | 14 | - (void)notificationTitle:(NSString *)title detail:(NSString *)detail; 15 | 16 | @end 17 | 18 | @interface ECONotificationInterceptor : NSObject 19 | 20 | @property (nonatomic, weak) id delegate; 21 | 22 | + (instancetype)sharedInstance; 23 | - (void)notificationTitle:(NSString *)title detail:(NSString *)detail; 24 | 25 | @end 26 | 27 | NS_ASSUME_NONNULL_END 28 | -------------------------------------------------------------------------------- /Sources/Plugins/Notification/ECONotificationPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECONotificationPlugin.h 3 | // Pods 4 | // 5 | // Created by zhanghe on 2019/8/12. 6 | // 7 | 8 | #import "ECOBasePlugin.h" 9 | #import "ECONotificationInterceptor.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECONotificationPlugin : ECOBasePlugin 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Sources/Plugins/UI/ViewHierarchy/ECOViewHierarchyPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOViewHierarchyPlugin.h 3 | // Echo 4 | // 5 | // Created by 陈爱彬 on 2019/6/19. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "ECOBasePlugin.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECOViewHierarchyPlugin : ECOBasePlugin 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Sources/Plugins/UI/ViewHierarchy/manager/YVObjectManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // YVObjectManager.h 3 | // libyourview 4 | // 5 | // Created by bliss_ddo on 2019/5/5. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YVTraversalContext.h" 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface YVObjectManager : NSObject 14 | +(YVObjectManager *)sharedInstance; 15 | @property (nonatomic,strong) YVTraversalContext * context; 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Sources/Plugins/UI/ViewHierarchy/manager/YVObjectManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // YVObjectManager.m 3 | // libyourview 4 | // 5 | // Created by bliss_ddo on 2019/5/5. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "YVObjectManager.h" 10 | 11 | @implementation YVObjectManager 12 | static YVObjectManager * _signleton; 13 | +(YVObjectManager *)sharedInstance 14 | { 15 | static dispatch_once_t oneToken; 16 | dispatch_once(&oneToken, ^{ 17 | _signleton = [[YVObjectManager alloc]init]; 18 | }); 19 | return _signleton; 20 | } 21 | @end 22 | -------------------------------------------------------------------------------- /Sources/Plugins/UI/ViewHierarchy/serializer/NSObject+YVNodeInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+YVNodeInfo.h 3 | // libyourview 4 | // 5 | // Created by bliss_ddo on 2019/4/24. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NSObject (YVNodeInfo) 14 | -(NSDictionary*)nodeInfo; 15 | -(NSString*)ecoNodeAddress; 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Sources/Plugins/UI/ViewHierarchy/serializer/NSObject+YVNodeInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+YVNodeInfo.m 3 | // libyourview 4 | // 5 | // Created by bliss_ddo on 2019/4/24. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "NSObject+YVNodeInfo.h" 10 | 11 | @implementation NSObject (YVNodeInfo) 12 | -(NSDictionary*)nodeInfo 13 | { 14 | NSString * _class = [self _class]; 15 | NSString * _address = [self _address]; 16 | NSString * _inherit = [self _inherit]; 17 | 18 | return @{ 19 | @"class":_class, 20 | @"address":_address, 21 | @"inherit":_inherit, 22 | }; 23 | } 24 | 25 | -(NSString*)_class 26 | { 27 | return NSStringFromClass(self.class); 28 | } 29 | 30 | -(NSString*)_inherit 31 | { 32 | NSString * inherit = @""; 33 | Class c = self.class; 34 | while (c) { 35 | inherit = [NSString stringWithFormat:@"%@ : %@",inherit,NSStringFromClass(c.class)]; 36 | c = c.superclass; 37 | } 38 | return [inherit substringFromIndex:3]; 39 | } 40 | 41 | -(NSString*)_address 42 | { 43 | return [NSString stringWithFormat:@"%p",self]; 44 | } 45 | -(NSString*)ecoNodeAddress { 46 | return [self _address]; 47 | } 48 | @end 49 | -------------------------------------------------------------------------------- /Sources/Plugins/UI/ViewHierarchy/serializer/UIView+YVNodeInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+YVNodeInfo.h 3 | // libyourview 4 | // 5 | // Created by bliss_ddo on 2019/4/24. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "NSObject+YVNodeInfo.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface UIView (YVNodeInfo) 15 | - (NSDictionary*)nodeInfo; 16 | 17 | - (NSDictionary *)ecoUpdateInfo; 18 | 19 | - (NSString *)_ecoColorRGBA:(UIColor *)color; 20 | 21 | @end 22 | 23 | NS_ASSUME_NONNULL_END 24 | -------------------------------------------------------------------------------- /Sources/Plugins/UI/ViewHierarchy/serializer/UIView+YVTraversal.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+YVTraversal.h 3 | // libyourview 4 | // 5 | // Created by bliss_ddo on 2019/4/24. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YVTraversalStepin.h" 11 | #import "YVTraversalContext.h" 12 | #import "UIView+YVNodeInfo.h" 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | @interface UIView (YVTraversal) 17 | 18 | -(NSDictionary*)traversal:(YVTraversalStepin*)stepIn context:(YVTraversalContext*)context; 19 | 20 | @end 21 | 22 | NS_ASSUME_NONNULL_END 23 | -------------------------------------------------------------------------------- /Sources/Plugins/UI/ViewHierarchy/serializer/UIView+YVTraversal.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+YVTraversal.m 3 | // libyourview 4 | // 5 | // Created by bliss_ddo on 2019/4/24. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "UIView+YVTraversal.h" 10 | 11 | 12 | @implementation UIView (YVTraversal) 13 | -(NSDictionary*)traversal:(YVTraversalStepin*)stepIn context:(YVTraversalContext*)context 14 | { 15 | [context updateFromView:self]; 16 | YVTraversalStepin * stepined = [YVTraversalStepin stepInWithView:self parentInfo:stepIn]; 17 | NSMutableDictionary * resDict = [NSMutableDictionary dictionary]; 18 | NSMutableArray * children = [NSMutableArray array]; 19 | for (UIView * each in self.subviews) { 20 | //只显示隐藏的视图 21 | [children addObject:[each traversal:stepined context:context]]; 22 | } 23 | resDict[@"children"] = children.copy; 24 | [resDict addEntriesFromDictionary:[stepined stepinfo]]; 25 | [resDict addEntriesFromDictionary:[self nodeInfo]]; 26 | return resDict.copy; 27 | } 28 | @end 29 | -------------------------------------------------------------------------------- /Sources/Plugins/UI/ViewHierarchy/serializer/UIView+YVViewTree.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+YVViewTree.h 3 | // libyourview 4 | // 5 | // Created by bliss_ddo on 2019/4/24. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface UIView (YVViewTree) 13 | +(NSString*)rootViewTreeString; 14 | +(NSDictionary*)rootViewTreeDictionary; 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Sources/Plugins/UI/ViewHierarchy/serializer/UIView+YVViewTree.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+YVViewTree.m 3 | // libyourview 4 | // 5 | // Created by bliss_ddo on 2019/4/24. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "UIView+YVViewTree.h" 10 | #import "UIView+YVTraversal.h" 11 | #import "YVTraversalStepin.h" 12 | #import "YVTraversalContext.h" 13 | #import "YVObjectManager.h" 14 | 15 | @implementation UIView (YVViewTree) 16 | 17 | + (UIView*)_defaultRootView { 18 | return [UIApplication sharedApplication].keyWindow; 19 | } 20 | 21 | + (NSString*)rootViewTreeString { 22 | NSData *viewtreedata = [NSJSONSerialization dataWithJSONObject:[self rootViewTreeDictionary] options:0 error:nil]; 23 | return [[NSString alloc]initWithData:viewtreedata encoding:NSUTF8StringEncoding]; 24 | } 25 | 26 | + (NSDictionary*)rootViewTreeDictionary { 27 | YVTraversalStepin * stepIn = [[YVTraversalStepin alloc]init]; 28 | YVTraversalContext * context = [[YVTraversalContext alloc]init]; 29 | NSDictionary * viewtree = [[UIView _defaultRootView]traversal:stepIn context:context]; 30 | NSDictionary * extraInfo = [context contextDict]; 31 | [YVObjectManager sharedInstance].context = context; 32 | return @{ 33 | @"viewtree":viewtree, 34 | @"extrainfo":extraInfo, 35 | }; 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /Sources/Plugins/UI/ViewHierarchy/serializer/YVTraversalContext.h: -------------------------------------------------------------------------------- 1 | // 2 | // YVTraversalContext.h 3 | // libyourview 4 | // 5 | // Created by bliss_ddo on 2019/4/24. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface YVTraversalContext : NSObject 15 | -(void)updateFromView:(UIView*)v; 16 | @property (nonatomic,assign,readonly) NSInteger objectCounter ; 17 | @property (nonatomic,assign,readonly) NSInteger hidenObjectCounter; 18 | @property (nonatomic,assign,readonly) NSInteger notHidenObjectCounter; 19 | @property (nonatomic,strong,readonly) NSDictionary * contextDict; 20 | @property (nonatomic,strong,readonly) NSMapTable * viewMap; 21 | @end 22 | 23 | NS_ASSUME_NONNULL_END 24 | -------------------------------------------------------------------------------- /Sources/Plugins/UI/ViewHierarchy/serializer/YVTraversalContext.m: -------------------------------------------------------------------------------- 1 | // 2 | // YVTraversalContext.m 3 | // libyourview 4 | // 5 | // Created by bliss_ddo on 2019/4/24. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import "YVTraversalContext.h" 10 | 11 | 12 | 13 | @implementation YVTraversalContext 14 | @synthesize objectCounter = _objectCounter; 15 | @synthesize hidenObjectCounter = _hidenObjectCounter; 16 | @synthesize notHidenObjectCounter = _notHidenObjectCounter; 17 | 18 | -(instancetype)init 19 | { 20 | if (self = [super init]) { 21 | _objectCounter = 0; 22 | _hidenObjectCounter = 0; 23 | _notHidenObjectCounter = 0; 24 | _viewMap = [NSMapTable mapTableWithKeyOptions:NSMapTableCopyIn valueOptions:NSMapTableWeakMemory]; 25 | } 26 | return self; 27 | } 28 | 29 | -(NSInteger)objectCounter 30 | { 31 | return _objectCounter; 32 | } 33 | 34 | -(NSInteger)hidenObjectCounter 35 | { 36 | return _hidenObjectCounter; 37 | } 38 | 39 | -(NSInteger)notHidenObjectCounter 40 | { 41 | return _notHidenObjectCounter; 42 | } 43 | 44 | -(void)updateFromView:(UIView*)v 45 | { 46 | _objectCounter++; 47 | if (v.hidden) { 48 | _hidenObjectCounter++; 49 | }else{ 50 | _notHidenObjectCounter++; 51 | } 52 | NSString * memoryKey = [NSString stringWithFormat:@"%p",v]; 53 | [self.viewMap setObject:v forKey:memoryKey]; 54 | } 55 | 56 | -(NSDictionary *)contextDict 57 | { 58 | 59 | return @{ 60 | @"screeninfo":NSStringFromCGRect([UIScreen mainScreen].bounds), 61 | @"totalcount":@(_objectCounter), 62 | }; 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /Sources/Plugins/UI/ViewHierarchy/serializer/YVTraversalStepin.h: -------------------------------------------------------------------------------- 1 | // 2 | // YVTraversalStepin.h 3 | // libyourview 4 | // 5 | // Created by bliss_ddo on 2019/4/24. 6 | // Copyright © 2019 bliss_ddo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface YVTraversalStepin : NSObject 15 | +(YVTraversalStepin*)stepInWithView:(UIView*)b parentInfo:(YVTraversalStepin*)parent; 16 | -(NSDictionary*)stepinfo; 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Sources/Plugins/ViewBorder/ECOViewBorderInspector.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOViewBorderInspector.h 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/8/28. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface ECOViewBorderInspector : NSObject 13 | 14 | @property (nonatomic, assign) BOOL showViewBorder; 15 | 16 | + (instancetype)sharedInstance; 17 | 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /Sources/Plugins/ViewBorder/ECOViewBorderInspector.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECOViewBorderInspector.m 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/8/28. 6 | // 7 | 8 | #import "ECOViewBorderInspector.h" 9 | #import "UIView+ECOViewBorder.h" 10 | #import "ECOSwizzle.h" 11 | 12 | @implementation ECOViewBorderInspector 13 | 14 | + (instancetype)sharedInstance { 15 | static ECOViewBorderInspector *instance = nil; 16 | 17 | static dispatch_once_t once; 18 | dispatch_once(&once, ^{ 19 | instance = [[ECOViewBorderInspector alloc] init]; 20 | }); 21 | return instance; 22 | } 23 | 24 | - (instancetype)init 25 | { 26 | self = [super init]; 27 | if (self) { 28 | 29 | } 30 | return self; 31 | } 32 | 33 | - (void)setShowViewBorder:(BOOL)showViewBorder { 34 | if (_showViewBorder != showViewBorder) { 35 | _showViewBorder = showViewBorder; 36 | [[NSNotificationCenter defaultCenter] postNotificationName:ECHOToggleViewBorderNotification object:nil]; 37 | } 38 | } 39 | 40 | 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Sources/Plugins/ViewBorder/ECOViewBorderPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOViewBorderPlugin.h 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/8/28. 6 | // 7 | 8 | #import "ECOBasePlugin.h" 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface ECOViewBorderPlugin : ECOBasePlugin 13 | 14 | @end 15 | 16 | NS_ASSUME_NONNULL_END 17 | -------------------------------------------------------------------------------- /Sources/Plugins/ViewBorder/ECOViewBorderPlugin.m: -------------------------------------------------------------------------------- 1 | // 2 | // ECOViewBorderPlugin.m 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/8/28. 6 | // 7 | 8 | #import "ECOViewBorderPlugin.h" 9 | #import "EchoSDKDefines.h" 10 | #import "ECOClient.h" 11 | #import "ECOViewBorderInspector.h" 12 | 13 | @implementation ECOViewBorderPlugin 14 | 15 | + (void)load { 16 | [[ECOClient sharedClient] registerPlugin:[self class]]; 17 | } 18 | 19 | - (instancetype)init 20 | { 21 | self = [super init]; 22 | if (self) { 23 | self.name = @"视图边框线"; 24 | [self registerTemplate:ECOUITemplateType_H5 data:nil]; 25 | [ECOViewBorderInspector sharedInstance]; 26 | } 27 | return self; 28 | } 29 | 30 | - (void)device:(ECOChannelDeviceInfo *)device didChangedAuthState:(BOOL)isAuthed { 31 | if (isAuthed) { 32 | NSString *htmlPath = [EchoBundle pathForResource:@"ECOViewBorder" ofType:@"html"]; 33 | if (!htmlPath) { 34 | return; 35 | } 36 | NSURL *fileURL = [NSURL fileURLWithPath:htmlPath]; 37 | NSString *htmlString = [[NSString alloc] initWithContentsOfURL:fileURL encoding:NSUTF8StringEncoding error:nil]; 38 | if (htmlString && [htmlString length]) { 39 | !self.deviceSendBlock ?: self.deviceSendBlock(device, @{EchoHTMLKey: htmlString}); 40 | } 41 | !self.deviceSendBlock ?: self.deviceSendBlock(device, @{EchoJSParams: @([ECOViewBorderInspector sharedInstance].showViewBorder)}); 42 | } 43 | } 44 | 45 | - (void)didReceivedPacketData:(id)data fromDevice:(ECOChannelDeviceInfo *)device { 46 | NSDictionary *dict = (NSDictionary *)data; 47 | NSNumber *result = dict[EchoJSResult]; 48 | [[ECOViewBorderInspector sharedInstance] setShowViewBorder:[result boolValue]]; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /Sources/Plugins/ViewBorder/UIView+ECOViewBorder.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+ECOViewBorder.h 3 | // EchoSDK 4 | // 5 | // Created by zhanghe on 2019/8/28. 6 | // 7 | 8 | #import 9 | 10 | #define ECHOToggleViewBorderNotification @"ECHOToggleViewBorderNotification" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface UIView (ECOViewBorder) 15 | 16 | @property (nonatomic, assign) CGColorRef previousBorderColor; 17 | @property (nonatomic, assign) CGFloat previousBorderWidth;; 18 | 19 | 20 | @end 21 | 22 | NS_ASSUME_NONNULL_END 23 | -------------------------------------------------------------------------------- /Sources/Plugins/Watchdog/ECOWatchdog.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOWatchdog.h 3 | // Pods 4 | // 5 | // Created by zhanghe on 2019/8/16. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @protocol ECOWatchdogDelegate 13 | 14 | - (void)onReportReceived:(NSString *)report; 15 | 16 | @end 17 | 18 | @interface ECOWatchdog : NSObject 19 | 20 | @property (nonatomic, weak) id delegate; 21 | 22 | + (instancetype)sharedInstance; 23 | 24 | @end 25 | 26 | NS_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /Sources/Plugins/Watchdog/ECOWatchdogPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // ECOWatchdogPlugin.h 3 | // Pods 4 | // 5 | // Created by zhanghe on 2019/8/16. 6 | // 7 | 8 | #import "ECOBasePlugin.h" 9 | #import "ECOWatchdog.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ECOWatchdogPlugin : ECOBasePlugin 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Sources/Resources/ECOViewBorder.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 |
12 | 13 |
14 | 15 | 16 | 29 | 30 | -------------------------------------------------------------------------------- /iOS/Example/EchoDemo/EchoAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // EchoAppDelegate.h 3 | // Echo 4 | // 5 | // Created by 136998328@qq.com on 04/15/2019. 6 | // Copyright (c) 2019 136998328@qq.com. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface EchoAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /iOS/Example/EchoDemo/EchoDemo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | #endif 17 | -------------------------------------------------------------------------------- /iOS/Example/EchoDemo/EchoTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // EchoTableViewCell.h 3 | // EchoDemo 4 | // 5 | // Created by 陈爱彬 on 2019/11/28. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface EchoTableViewCell : UITableViewCell 14 | 15 | @property (nonatomic, strong) NSDictionary *content; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /iOS/Example/EchoDemo/EchoTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // EchoTableViewCell.m 3 | // EchoDemo 4 | // 5 | // Created by 陈爱彬 on 2019/11/28. Maintain by 陈爱彬 6 | // Description 7 | // 8 | 9 | #import "EchoTableViewCell.h" 10 | 11 | @interface EchoTableViewCell() 12 | 13 | @property (weak, nonatomic) IBOutlet UILabel *ecoTitleLabel; 14 | @property (weak, nonatomic) IBOutlet UILabel *ecoDetailLabel; 15 | @end 16 | 17 | @implementation EchoTableViewCell 18 | 19 | - (void)awakeFromNib { 20 | [super awakeFromNib]; 21 | // Initialization code 22 | } 23 | 24 | - (void)setContent:(NSDictionary *)content { 25 | _content = content; 26 | NSString *title = _content[@"title"]; 27 | self.ecoTitleLabel.text = title; 28 | NSString *detail = _content[@"detail"]; 29 | self.ecoDetailLabel.text = detail; 30 | } 31 | 32 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 33 | [super setSelected:selected animated:animated]; 34 | 35 | // Configure the view for the selected state 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /iOS/Example/EchoDemo/EchoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // EchoViewController.h 3 | // Echo 4 | // 5 | // Created by 136998328@qq.com on 04/15/2019. 6 | // Copyright (c) 2019 136998328@qq.com. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface EchoViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /iOS/Example/EchoDemo/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /iOS/Example/EchoDemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /iOS/Example/EchoDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Echo 4 | // 5 | // Created by 136998328@qq.com on 04/15/2019. 6 | // Copyright (c) 2019 136998328@qq.com. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | #import "EchoAppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) 13 | { 14 | @autoreleasepool { 15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([EchoAppDelegate class])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /iOS/Example/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '9.0' 2 | 3 | target 'EchoDemo' do 4 | # use_frameworks! 5 | pod 'EchoSDK', :path => '../../' 6 | # pod 'RSSwizzle' 7 | # pod 'MLeaksFinder', :git => "https://github.com/Tencent/MLeaksFinder.git" 8 | 9 | end 10 | -------------------------------------------------------------------------------- /iOS/Example/Tests/Tests-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 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /iOS/Example/Tests/Tests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // The contents of this file are implicitly included at the beginning of every test case source file. 2 | 3 | #ifdef __OBJC__ 4 | 5 | 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /iOS/Example/Tests/Tests.m: -------------------------------------------------------------------------------- 1 | // 2 | // EchoTests.m 3 | // EchoTests 4 | // 5 | // Created by 136998328@qq.com on 04/15/2019. 6 | // Copyright (c) 2019 136998328@qq.com. All rights reserved. 7 | // 8 | 9 | @import XCTest; 10 | 11 | @interface Tests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Tests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | 36 | -------------------------------------------------------------------------------- /iOS/Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | --------------------------------------------------------------------------------