├── .githooks ├── pre-push └── pre-push.d │ ├── 01-protect-master │ ├── 02-verify-projects │ └── 03-check-swiftlint ├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .gitmodules ├── .swiftlint.yml ├── Configuration ├── App.xcconfig ├── Module.xcconfig ├── Project-Debug.xcconfig ├── Project-Release.xcconfig ├── Project.xcconfig ├── Tests.xcconfig └── UITests.xcconfig ├── LICENSE ├── Libraries ├── DeviceList │ ├── DeviceList.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── xcschemes │ │ │ │ ├── DeviceList.xcscheme │ │ │ │ └── DeviceListDemo.xcscheme │ │ └── xcuserdata │ │ │ └── yong.xcuserdatad │ │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ ├── DeviceList │ │ ├── Coordinators │ │ │ └── DeviceListCoordinatorImpl.swift │ │ ├── DataStore │ │ │ ├── DeviceListDataAPI.swift │ │ │ ├── DeviceListDataNetwork.swift │ │ │ ├── DeviceListDataProvider.swift │ │ │ ├── DevicePingAPI.swift │ │ │ ├── DevicePingProvider.swift │ │ │ └── SwiftyPing.swift │ │ ├── DeviceList.h │ │ ├── DeviceList.swift │ │ ├── Info.plist │ │ ├── Mock │ │ │ ├── DeviceList+Mock.swift │ │ │ └── DevicePing+Mock.swift │ │ ├── Models │ │ │ └── NetworkListModel.swift │ │ ├── ViewModels │ │ │ └── DeviceListViewModel.swift │ │ └── Views │ │ │ └── DeviceListView.swift │ ├── DeviceListDemo │ │ ├── Assets.xcassets │ │ │ ├── AccentColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── ContentView.swift │ │ ├── DeviceListDemoApp.swift │ │ ├── Info.plist │ │ └── Preview Content │ │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ ├── DeviceListTests │ │ ├── DeviceListTests.swift │ │ └── Info.plist │ └── Setting │ │ ├── ViewModels │ │ └── SettingViewModel.swift │ │ └── Views │ │ └── SettingView.swift ├── Login │ ├── Login.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── swiftpm │ │ │ │ └── Package.resolved │ │ ├── xcshareddata │ │ │ └── xcschemes │ │ │ │ ├── Login.xcscheme │ │ │ │ └── LoginDemo.xcscheme │ │ └── xcuserdata │ │ │ └── yong.xcuserdatad │ │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ ├── Login │ │ ├── Coordinator │ │ │ └── LoginCoordinatorImpl.swift │ │ ├── DataStore │ │ │ ├── LoginDataStoreAPI.swift │ │ │ ├── LoginDataStoreImpl.swift │ │ │ ├── LoginDataStoreMock.swift │ │ │ └── LoginNetworkProvider.swift │ │ ├── Info.plist │ │ ├── Login.h │ │ ├── Login.swift │ │ ├── Mock │ │ │ └── LoginDataStoreMock.swift │ │ ├── Model │ │ │ └── LoginModel.swift │ │ ├── ViewModels │ │ │ ├── LoginViewModel.swift │ │ │ └── Validation.swift │ │ └── Views │ │ │ ├── InvalidEntryView.swift │ │ │ ├── LoginCommonView.swift │ │ │ ├── LoginView.swift │ │ │ ├── RegisterView.swift │ │ │ └── ResetPasswordView.swift │ ├── LoginDemo │ │ ├── Assets.xcassets │ │ │ ├── AccentColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── ContentView.swift │ │ ├── Info.plist │ │ ├── LoginDemoApp.swift │ │ └── Preview Content │ │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ └── LoginTests │ │ ├── Info.plist │ │ └── LoginTests.swift └── OEPlatform │ ├── OEPlatform.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── swiftpm │ │ │ └── Package.resolved │ └── xcuserdata │ │ └── yong.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist │ ├── OEPlatform │ ├── Config │ │ └── OmniEdgeConfigProvider.swift │ ├── Coordinator │ │ └── Coordinator.swift │ ├── Extensions │ │ └── Tattoo+Platform.swift │ ├── Info.plist │ ├── JWT │ │ └── JWTUtil.swift │ ├── ModulesAPI │ │ ├── .keep │ │ ├── ConfigAPI.swift │ │ ├── DeviceListAPI.swift │ │ ├── LoginAPI.swift │ │ ├── PlatformModule.swift │ │ ├── ProductionModule.swift │ │ ├── SessionAPI.swift │ │ ├── TunnelAPI.swift │ │ └── UserAPI.swift │ ├── OEPlatform.h │ ├── Routing │ │ ├── OMEInterceptRouter.swift │ │ ├── OMENavigationRouter.swift │ │ ├── OMERouterManager.swift │ │ ├── OMERoutingAPI.swift │ │ ├── OMERoutingManagerImpl.swift │ │ └── Views │ │ │ ├── NAVControllerWrapper.swift │ │ │ ├── OMENavigationView.swift │ │ │ └── SHNavigationPreferences.swift │ └── SessionManager │ │ ├── SessionManager.swift │ │ └── UserManager.swift │ └── OEPlatformTests │ ├── Info.plist │ └── OEPlatformTests.swift ├── Makefile ├── Omniedge.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ ├── WorkspaceSettings.xcsettings │ │ └── swiftpm │ │ └── Package.resolved └── xcshareddata │ └── xcschemes │ ├── Omniedge.xcscheme │ ├── OmniedgeTests.xcscheme │ └── Tunnel.xcscheme ├── Omniedge ├── AppDelegate.swift ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── AppIcon.png │ │ ├── AppIcon120-1.png │ │ ├── AppIcon120.png │ │ ├── AppIcon180.png │ │ ├── AppIcon40x40.png │ │ ├── AppIcon58.png │ │ ├── AppIcon60.png │ │ ├── AppIcon80.png │ │ ├── AppIcon87.png │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── OmniEdgeManager.swift ├── Omniedge.entitlements ├── SceneDelegate.swift └── SwiftUI │ ├── AlertButton.swift │ ├── ListView.swift │ ├── MainView.swift │ ├── MainViewModel.swift │ └── UIView+Keyboard.swift ├── OmniedgeDylib ├── Info.plist ├── OmniEdgeConfig.swift ├── OmniEdgeLog.swift ├── OmniedgeDylib.h └── OmniedgeDylib.xcodeproj │ ├── project.pbxproj │ └── xcuserdata │ └── yong.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── OmniedgeDylibTests ├── Info.plist └── OmniedgeDylibTests.swift ├── OmniedgeNew ├── AllTests.xctestplan ├── OmniedgeNew.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── xcshareddata │ │ └── xcschemes │ │ │ ├── OmniedgeNew.xcscheme │ │ │ └── Tunnel.xcscheme │ └── xcuserdata │ │ └── yong.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── OmniedgeNew.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ │ └── Package.resolved │ └── xcuserdata │ │ └── yong.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── OmniedgeNew │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── icon1024.png │ │ │ ├── icon20@1x.png │ │ │ ├── icon20@2x.png │ │ │ ├── icon29@1x.png │ │ │ ├── icon29@2x-1.png │ │ │ ├── icon29@2x.png │ │ │ ├── icon29@3x.png │ │ │ ├── icon40.png │ │ │ ├── icon40@1x.png │ │ │ ├── icon40@2x-1.png │ │ │ ├── icon40@2x.png │ │ │ ├── icon40@3x.png │ │ │ ├── icon60.png │ │ │ ├── icon60@2x.png │ │ │ ├── icon60@3x.png │ │ │ ├── icon76@1x.png │ │ │ ├── icon76@2x.png │ │ │ └── icon83.5@2x.png │ │ └── Contents.json │ ├── ContentView.swift │ ├── Coordinator │ │ └── AppCoordinator.swift │ ├── Info.plist │ ├── OmniedgeNew.entitlements │ ├── OmniedgeNewApp.swift │ ├── OmniedgeNewRelease.entitlements │ ├── Preview Content │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ └── TunnelProvider.swift ├── OmniedgeNewTests │ ├── Info.plist │ └── OmniedgeNewTests.swift ├── OmniedgeNewUITests │ ├── Info.plist │ └── OmniedgeNewUITests.swift └── Tunnel │ ├── Info.plist │ ├── OmniEdgeUDP.swift │ ├── PacketTunnelEngine.swift │ ├── PacketTunnelProvider.swift │ ├── Tunnel-Bridging-Header.h │ └── Tunnel.entitlements ├── OmniedgeTests ├── Info.plist └── OmniedgeTests.swift ├── OmniedgeUITests ├── Info.plist └── OmniedgeUITests.swift ├── Packages ├── OEDI │ ├── .gitignore │ ├── Package.swift │ ├── README.md │ ├── Sources │ │ └── OEDI │ │ │ └── OEDI.swift │ └── Tests │ │ └── OEDITests │ │ └── OEDITests.swift ├── OENetwork │ ├── .gitignore │ ├── Package.swift │ ├── README.md │ ├── Sources │ │ └── OENetwork │ │ │ ├── OENetwork.swift │ │ │ ├── OENetworkDispatch.swift │ │ │ └── OERequest.swift │ └── Tests │ │ └── OENetworkTests │ │ └── OENetworkTests.swift ├── OEUIKit │ ├── .gitignore │ ├── Package.swift │ ├── README.md │ ├── Sources │ │ └── OEUIKit │ │ │ ├── BottomSheetView.swift │ │ │ ├── Buttons.swift │ │ │ ├── Colors.swift │ │ │ ├── Fonts.swift │ │ │ ├── Images.swift │ │ │ ├── Resources │ │ │ └── Media.xcassets │ │ │ │ ├── Colors │ │ │ │ ├── Background.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ ├── ErrorRed.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Gray.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Gray20.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Gray50.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Gray60.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── OnPrimary.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Primary.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Slate.colorset │ │ │ │ │ └── Contents.json │ │ │ │ └── SuccessGreen.colorset │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ └── Images │ │ │ │ ├── Contents.json │ │ │ │ ├── Google.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── logo googleg 48dp.png │ │ │ │ ├── logo googleg 48dp@2x.png │ │ │ │ └── logo googleg 48dp@3x.png │ │ │ │ ├── PrimaryIcon.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── Icon.png │ │ │ │ ├── Icon@2x.png │ │ │ │ └── Icon@3x.png │ │ │ │ ├── TextLogoIcon.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── TextLogoIcon.png │ │ │ │ ├── TextLogoIcon@2x.png │ │ │ │ └── TextLogoIcon@3x.png │ │ │ │ └── TextLogoText.imageset │ │ │ │ ├── Contents.json │ │ │ │ ├── TextLogoText.png │ │ │ │ ├── TextLogoText@2x.png │ │ │ │ └── TextLogoText@3x.png │ │ │ ├── Searchbar.swift │ │ │ ├── Spinner.swift │ │ │ ├── TextFields.swift │ │ │ ├── Texts.swift │ │ │ └── Views.swift │ └── Tests │ │ └── OEUIKitTests │ │ └── OEUIKitTests.swift └── Tattoo │ ├── .gitignore │ ├── .swiftpm │ └── xcode │ │ └── package.xcworkspace │ │ └── contents.xcworkspacedata │ ├── Package.swift │ ├── Sources │ └── Tattoo │ │ ├── APICenter.swift │ │ ├── APIModule.swift │ │ ├── APIQualifier.swift │ │ └── DIManager.swift │ └── Tests │ └── TattooTests │ └── XCTestManifests.swift ├── README.md ├── Tunnel-Bridging-Header.h ├── Tunnel ├── Info.plist ├── OmniEdgeUDP.swift ├── PacketTunnelEngine.swift ├── PacketTunnelProvider.swift └── Tunnel.entitlements ├── docs ├── Architecture.md └── Network.md ├── resource ├── androidmodule.png ├── androidrunloop.png ├── end2site.png ├── iosrunloop.png ├── iosstartup.png ├── p2pvpn.png ├── site2site.png ├── tap.png ├── tun.png └── tuntap1.png ├── scripts ├── clean_projects.sh ├── configure_workspace.rb ├── git-add-matches.sh ├── setup_devtools.sh ├── setup_module.sh ├── setup_swiftlint.sh ├── setup_templates.sh ├── setup_xcodegen.sh ├── swiftlint ├── verify_projects.sh └── xUnique.py └── templates ├── MvvMC.xctemplate ├── TemplateInfo.plist └── ___FILEBASENAME___ │ ├── Coordinators │ └── ___FILEBASENAME___Coordinator.swift │ ├── DataStores │ └── ___FILEBASENAME___DataStore.swift │ ├── Models │ └── ___FILEBASENAME___Model.swift │ ├── ViewModels │ └── ___FILEBASENAME___ViewModel.swift │ └── Views │ └── ___FILEBASENAME___View.swift ├── module-starter ├── ___FILEBASENAME___ │ ├── ___FILEBASENAME___.h │ └── ___FILEBASENAME___.swift ├── ___FILEBASENAME___Demo │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── ContentView.swift │ ├── Preview Content │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ └── ___FILEBASENAME___DemoApp.swift ├── ___FILEBASENAME___Tests │ └── ___FILEBASENAME___Tests.swift └── module.yml └── platform-injection └── ___FILEBASENAME___API.swift /.githooks/pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Pre-push checks in progress..." 4 | 5 | cd "$(dirname "$0")/pre-push.d" 6 | 7 | for hook in *; do 8 | bash $hook 9 | RESULT=$? 10 | if [ $RESULT != 0 ]; then 11 | echo "pre-push.d/$hook returned non-zero: $RESULT, abort commit" 12 | exit $RESULT 13 | fi 14 | done 15 | 16 | exit 0 17 | 18 | -------------------------------------------------------------------------------- /.githooks/pre-push.d/01-protect-master: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Called by "git push" after it has checked the remote status, 4 | # but before anything has been pushed. 5 | # 6 | # If this script exits with a non-zero status nothing will be pushed. 7 | # 8 | # Steps to install, from the root directory of your repo... 9 | # 1. Copy the file into your repo at `.git/hooks/pre-push` 10 | # 2. Set executable permissions, run `chmod +x .git/hooks/pre-push` 11 | # 3. Or, use `rake hooks:pre_push` to install 12 | # 13 | # Try a force push to master, you should get a message `*** [Policy] never force push...` 14 | # 15 | # The commands below will not be allowed... 16 | # `git push --force origin master` 17 | # `git push --delete origin master` 18 | # `git push origin :master` 19 | # 20 | # Nor will a force push while on the master branch be allowed... 21 | # `git co master` 22 | # `git push --force origin` 23 | # 24 | # Requires git 1.8.2 or newer 25 | # 26 | # Git 1.8.2 release notes cover the new pre-push hook: 27 | # 28 | # 29 | # See Sample pre-push script: 30 | # 31 | 32 | 33 | protected_branch='master' 34 | 35 | policy='[Policy] Never push directly to the '$protected_branch' branch! (Prevented with pre-push hook.)' 36 | 37 | current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,') 38 | 39 | do_exit(){ 40 | echo $policy 41 | exit 1 42 | } 43 | 44 | if [ $current_branch = $protected_branch ]; then 45 | do_exit 46 | fi 47 | 48 | unset do_exit 49 | 50 | exit 0 51 | -------------------------------------------------------------------------------- /.githooks/pre-push.d/02-verify-projects: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Called by "git push" after it has checked the remote status, 4 | # but before anything has been pushed. 5 | # 6 | # If this script exits with a non-zero status nothing will be pushed. 7 | # 8 | # Steps to install, from the root directory of your repo... 9 | # 1. Copy the file into your repo at `.git/hooks/pre-push` 10 | # 2. Set executable permissions, run `chmod +x .git/hooks/pre-push` 11 | # 3. Or, use `rake hooks:pre_push` to install 12 | # 13 | # Requires git 1.8.2 or newer 14 | # 15 | # Git 1.8.2 release notes cover the new pre-push hook: 16 | # 17 | # 18 | # See Sample pre-push script: 19 | # 20 | 21 | root=`git rev-parse --show-toplevel` 22 | cd $root 23 | ./scripts/verify_projects.sh 24 | success=$? 25 | if [ $success != 0 ]; then 26 | tput setaf 2 27 | echo "Project files need to be sorted. Please run ./scripts/clean_projects.sh and commit the changes." 28 | tput sgr0 29 | exit 1 30 | fi 31 | -------------------------------------------------------------------------------- /.githooks/pre-push.d/03-check-swiftlint: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Called by "git push" after it has checked the remote status, 4 | # but before anything has been pushed. 5 | # 6 | # If this script exits with a non-zero status nothing will be pushed. 7 | # 8 | # Steps to install, from the root directory of your repo... 9 | # 1. Copy the file into your repo at `.git/hooks/pre-push` 10 | # 2. Set executable permissions, run `chmod +x .git/hooks/pre-push` 11 | # 3. Or, use `rake hooks:pre_push` to install 12 | # 13 | # Requires git 1.8.2 or newer 14 | # 15 | # Git 1.8.2 release notes cover the new pre-push hook: 16 | # 17 | # 18 | # See Sample pre-push script: 19 | # 20 | 21 | root=`git rev-parse --show-toplevel` 22 | cd $root 23 | ./scripts/swiftlint 24 | success=$? 25 | if [ $success != 0 ]; then 26 | tput setaf 3 27 | echo "Project contains swiftlint errors. Please fix before pushing :)" 28 | tput sgr0 29 | exit 1 30 | fi 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please go to omniedge github disscussions for help and support: 2 | 3 | https://github.com/omniedgeio/omniedge/discussions 4 | 5 | # Expected Behavior 6 | 7 | Please describe the behavior you are expecting 8 | 9 | # Current Behavior 10 | 11 | What is the current behavior? 12 | 13 | # Failure Information (for bugs) 14 | 15 | Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template. 16 | 17 | ## Steps to Reproduce 18 | 19 | Please provide detailed steps for reproducing the issue. 20 | 21 | 1. step 1 22 | 2. step 2 23 | 3. you get it... 24 | 25 | ## Context 26 | 27 | Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions. 28 | 29 | - **OmniEdge Version**: 30 | - **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: 31 | - **Mobile device (e.g. iPhone XR, Pixel 5, Huawei,Xiaomi)**: 32 | - **Macbook device (e.g. Intel Mac, M1 Mac)**: 33 | 34 | ## Failure Logs 35 | 36 | Please include any relevant log snippets or files here. 37 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. 4 | 5 | Fixes # (issue) 6 | 7 | # How Has This Been Tested? 8 | 9 | Please describe the tests that you ran to verify your changes. Please also note any relevant details for your test configuration. 10 | 11 | - [ ] Test A 12 | - [ ] Test B 13 | 14 | # Checklist: 15 | 16 | - [ ] My code follows the style guidelines of this project 17 | - [ ] I have performed a self-review of my own code 18 | - [ ] I have commented my code, particularly in hard-to-understand areas 19 | - [ ] I have made corresponding changes to the documentation 20 | - [ ] My changes generate no new warnings 21 | - [ ] Any dependent changes have been merged and published in downstream modules 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Omniedge.xcodeproj/project.xcworkspace/xcuserdata/samuel.xcuserdatad 2 | Packages/OEUIKit/build/* 3 | Libraries/OEPlatform/build/* 4 | Libraries/Login/build/* 5 | OmniedgeNew/build/* 6 | Packages/Build 7 | Libraries/DeviceList/Build 8 | Libraries/DeviceList/DeviceList.xcodeproj/xcuserdata 9 | Libraries/Login/Login.xcodeproj/project.xcworkspace/xcuserdata 10 | Libraries/Login/Login.xcodeproj/xcuserdata 11 | Libraries/OEPlatform/OEPlatform.xcodeproj/project.xcworkspace/xcuserdata 12 | Libraries/OEPlatform/OEPlatform.xcodeproj/xcuserdata 13 | Libraries/.DS_Store 14 | Omniedge.xcodeproj/project.xcworkspace/xcuserdata 15 | Omniedge.xcodeproj/xcuserdata 16 | OmniedgeDylib/OmniedgeDylib.xcodeproj/xcuserdata 17 | OmniedgeNew/OmniedgeNew.xcworkspace/xcuserdata 18 | .DS_Store 19 | OmniedgeNew/OmniedgeNew.xcodeproj/xcuserdata 20 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "n2n"] 2 | path = n2n 3 | url = https://github.com/omniedgeio/n2n-Mobile 4 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | # Swiftlint rules reference: https://realm.github.io/SwiftLint/rule-directory.html 2 | 3 | # We would want to pin the version to avoid these repeating issues 4 | swiftlint_version: 0.41.0 5 | 6 | disabled_rules: # rule identifiers to exclude from running 7 | - orphaned_doc_comment 8 | - large_tuple 9 | - todo 10 | excluded: 11 | # Dependency Management directories 12 | - Carthage 13 | # Code from 3rd party tool in module 14 | - Libraries/BuyExperience/Carthage 15 | - Pods 16 | - "**/.build/checkouts" # swift packages 17 | # Code from 3rd party in BuildTools 18 | # https://github.com/apollographql/iOSCodegenTemplate 19 | - BuildTools/Sources/BuildTools/ApolloCodegen 20 | - BuildTools/.build 21 | # Exclude generated graphql folders 22 | - Libraries/SearchModule/SearchModule/API/Generated 23 | # Exclude our templates which use invalid placeholders 24 | - templates 25 | opt_in_rules: 26 | - expiring_todo 27 | - empty_count 28 | - explicit_init 29 | - closure_spacing 30 | - overridden_super_call 31 | - redundant_nil_coalescing 32 | - private_outlet 33 | - nimble_operator 34 | - attributes 35 | - operator_usage_whitespace 36 | - closure_end_indentation 37 | - first_where 38 | - sorted_imports 39 | - object_literal 40 | - number_separator 41 | - prohibited_super_call 42 | - fatal_error_message 43 | - vertical_parameter_alignment_on_call 44 | - force_unwrapping 45 | identifier_name: 46 | excluded: 47 | - id 48 | - ID 49 | line_length: 160 50 | function_body_length: 50 51 | type_body_length: 500 52 | number_separator: 53 | minimum_length: 5 54 | -------------------------------------------------------------------------------- /Configuration/App.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // App.xcconfig 3 | // StubHub 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/17. 6 | // 7 | 8 | // Configuration settings file format documentation can be found at: 9 | // https://help.apple.com/xcode/#/dev745c5c974 10 | 11 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks 12 | 13 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon 14 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor 15 | 16 | ENABLE_PREVIEWS = YES 17 | -------------------------------------------------------------------------------- /Configuration/Module.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Module.xcconfig 3 | // StubHub 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/17. 6 | // 7 | 8 | // Configuration settings file format documentation can be found at: 9 | // https://help.apple.com/xcode/#/dev745c5c974 10 | 11 | // SwiftUI previews don't work for static lib 12 | 13 | MACH_O_TYPE[config=Debug] = mh_dylib 14 | MACH_O_TYPE[config=Release] = staticlib 15 | 16 | SKIP_INSTALL = YES 17 | 18 | DEFINES_MODULE = YES 19 | 20 | CLANG_ENABLE_MODULES = YES 21 | 22 | SUPPORTS_MACCATALYST = NO 23 | 24 | SWIFT_INSTALL_OBJC_HEADER = NO 25 | 26 | INSTALL_PATH = $(LOCAL_LIBRARY_DIR)/Frameworks 27 | 28 | DYLIB_COMPATIBILITY_VERSION = 1 29 | DYLIB_CURRENT_VERSION = 1 30 | DYLIB_INSTALL_NAME_BASE = @rpath 31 | 32 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks 33 | -------------------------------------------------------------------------------- /Configuration/Project-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Project-Debug.xcconfig 3 | // StubHub 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/17. 6 | // 7 | 8 | // Configuration settings file format documentation can be found at: 9 | // https://help.apple.com/xcode/#/dev745c5c974 10 | 11 | #include "Project.xcconfig" 12 | 13 | ONLY_ACTIVE_ARCH = YES 14 | 15 | DEBUG_INFORMATION_FORMAT = dwarf 16 | 17 | ENABLE_TESTABILITY = YES 18 | 19 | GCC_OPTIMIZATION_LEVEL = 0 20 | 21 | GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 $(inherited) 22 | 23 | SWIFT_OPTIMIZATION_LEVEL = -Onone 24 | 25 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG 26 | 27 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE 28 | -------------------------------------------------------------------------------- /Configuration/Project-Release.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Project-Release.xcconfig 3 | // StubHub 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/17. 6 | // 7 | 8 | // Configuration settings file format documentation can be found at: 9 | // https://help.apple.com/xcode/#/dev745c5c974 10 | 11 | #include "Project.xcconfig" 12 | 13 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 14 | 15 | VALIDATE_PRODUCT = YES 16 | 17 | ENABLE_NS_ASSERTIONS = NO 18 | 19 | SWIFT_COMPILATION_MODE = wholemodule 20 | 21 | SWIFT_OPTIMIZATION_LEVEL = -O 22 | 23 | MTL_ENABLE_DEBUG_INFO = NO 24 | -------------------------------------------------------------------------------- /Configuration/Project.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Project.xcconfig 3 | // StubHub 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/17. 6 | // 7 | 8 | // Configuration settings file format documentation can be found at: 9 | // https://help.apple.com/xcode/#/dev745c5c974 10 | 11 | IPHONEOS_DEPLOYMENT_TARGET = 14.1 12 | TARGETED_DEVICE_FAMILY = 1,2 13 | 14 | CODE_SIGN_STYLE = Automatic 15 | DEVELOPMENT_TEAM = SQDGL9TDH9 // Stubhub 16 | 17 | PRODUCT_NAME = $(TARGET_NAME) 18 | 19 | SWIFT_VERSION = 5.0 20 | 21 | SWIFT_TREAT_WARNINGS_AS_ERRORS = YES 22 | 23 | GCC_TREAT_WARNINGS_AS_ERRORS = YES 24 | 25 | SDKROOT = iphoneos 26 | 27 | OTHER_LDFLAGS = -ObjC 28 | 29 | COPY_PHASE_STRIP = NO 30 | 31 | ALWAYS_SEARCH_USER_PATHS = NO 32 | 33 | GCC_DYNAMIC_NO_PIC = NO 34 | GCC_NO_COMMON_BLOCKS = YES 35 | 36 | GCC_C_LANGUAGE_STANDARD = gnu11 37 | 38 | CLANG_CXX_LANGUAGE_STANDARD = gnu++14 39 | CLANG_CXX_LIBRARY = libc++ 40 | 41 | CLANG_ENABLE_MODULES = YES 42 | 43 | CLANG_ENABLE_OBJC_ARC = YES 44 | CLANG_ENABLE_OBJC_WEAK = YES 45 | 46 | ENABLE_STRICT_OBJC_MSGSEND = YES 47 | 48 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES 49 | 50 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES 51 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES 52 | CLANG_WARN_EMPTY_BODY = YES 53 | CLANG_WARN_BOOL_CONVERSION = YES 54 | CLANG_WARN_CONSTANT_CONVERSION = YES 55 | CLANG_WARN_ENUM_CONVERSION = YES 56 | CLANG_WARN_INT_CONVERSION = YES 57 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES 58 | CLANG_WARN_INFINITE_RECURSION = YES 59 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR 60 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES 61 | CLANG_WARN_STRICT_PROTOTYPES = YES 62 | CLANG_WARN_COMMA = YES 63 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 64 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE 65 | CLANG_WARN_UNREACHABLE_CODE = YES 66 | GCC_WARN_UNUSED_FUNCTION = YES 67 | GCC_WARN_UNUSED_VARIABLE = YES 68 | 69 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES 70 | CLANG_WARN_SUSPICIOUS_MOVE = YES 71 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR 72 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 73 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES 74 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES 75 | GCC_WARN_UNDECLARED_SELECTOR = YES 76 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR 77 | 78 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 79 | 80 | CLANG_ANALYZER_NONNULL = YES 81 | 82 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE 83 | 84 | MTL_FAST_MATH = YES 85 | -------------------------------------------------------------------------------- /Configuration/Tests.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Tests.xcconfig 3 | // StubHub 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/17. 6 | // 7 | 8 | // Configuration settings file format documentation can be found at: 9 | // https://help.apple.com/xcode/#/dev745c5c974 10 | 11 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks 12 | -------------------------------------------------------------------------------- /Configuration/UITests.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // UITests.xcconfig 3 | // StubHub 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/17. 6 | // 7 | 8 | // Configuration settings file format documentation can be found at: 9 | // https://help.apple.com/xcode/#/dev745c5c974 10 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceList.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceList.xcodeproj/xcuserdata/yong.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | DeviceList.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | DeviceListDemo.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceList/DataStore/DeviceListDataAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DeviceListDataAPI.swift 3 | // DeviceList 4 | // 5 | // Created by samuelsong on 2021/11/6. 6 | // 7 | 8 | import Combine 9 | import Foundation 10 | 11 | struct NetworkListRequest { 12 | let token: String 13 | } 14 | 15 | struct DeviceListRequest { 16 | let token: String 17 | } 18 | 19 | struct JoinRequest { 20 | let uuid: String //network uuid 21 | let deviceID: String 22 | let token: String 23 | } 24 | 25 | protocol DeviceListDataStoreAPI { 26 | func fetchNetworkList(_ request: NetworkListRequest) -> AnyPublisher 27 | func fetchDeviceList(_ request: DeviceListRequest) -> AnyPublisher 28 | func joinNetwork(_ request: JoinRequest) -> AnyPublisher 29 | } 30 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceList/DataStore/DeviceListDataNetwork.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DeviceListDataNetwork.swift 3 | // DeviceList 4 | // 5 | // Created by samuelsong on 2021/11/6. 6 | // 7 | 8 | import OENetwork 9 | 10 | struct DataNetworkResult: Codable { 11 | var message: String 12 | var data: [String: String]? 13 | } 14 | 15 | struct DataNetworkListResult: Codable { 16 | var code: Int? 17 | var data: [NetworkModel]? 18 | } 19 | 20 | struct FetchNetworkListRequst: Request { 21 | typealias ReturnType = DataNetworkListResult 22 | var token: String? 23 | var method = HTTPMethod.get 24 | var path: String = "/virtual-networks" 25 | } 26 | 27 | struct FetchDeviceListRequst: Request { 28 | typealias ReturnType = DataNetworkResult 29 | var token: String? 30 | var method = HTTPMethod.get 31 | var path: String = "/devices" 32 | } 33 | 34 | struct JoinNetworkResult: Codable { 35 | var data: N2NModel? 36 | } 37 | 38 | struct JoinNetworkRequst: Request { 39 | typealias ReturnType = JoinNetworkResult 40 | var token: String? 41 | var uuid: String 42 | var deviceUUID: String 43 | 44 | var path: String { 45 | return "/virtual-networks/\(uuid)/devices/\(deviceUUID)/join" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceList/DataStore/DeviceListDataProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DeviceListDataProvider.swift 3 | // DeviceList 4 | // 5 | // Created by samuelsong on 2021/11/6. 6 | // 7 | 8 | import Combine 9 | import OENetwork 10 | 11 | class DeviceListDataProvider: DeviceListDataStoreAPI { 12 | private var cancellables = [AnyCancellable]() 13 | #if false 14 | private let network = OENetwork(baseURL: "https://dev-api.omniedge.io/api/v1") 15 | #else 16 | private let network = OENetwork(baseURL: "https://api.omniedge.io/api/v1") 17 | #endif 18 | 19 | func fetchNetworkList(_ request: NetworkListRequest) -> AnyPublisher { 20 | return network.dispatch(FetchNetworkListRequst(token: request.token)) 21 | .compactMap({ [weak self] result in 22 | return self?.createNetworkList(result.data) 23 | }) 24 | .mapError { error in 25 | return DataError.fail(message: error.localizedDescription) 26 | } 27 | .eraseToAnyPublisher() 28 | } 29 | 30 | private func createNetworkList(_ data: [NetworkModel]?) -> NetworkListModel { 31 | if let list = data { 32 | return NetworkListModel(list: list) 33 | } else { 34 | return NetworkListModel(list: []) 35 | } 36 | } 37 | 38 | func fetchDeviceList(_ request: DeviceListRequest) -> AnyPublisher { 39 | return network.dispatch(FetchDeviceListRequst(token: request.token)) 40 | .compactMap({ [weak self] result in 41 | return self?.createDeviceList(message: result.message, dict: result.data) 42 | }) 43 | .mapError { error in 44 | return DataError.fail(message: error.localizedDescription) 45 | } 46 | .eraseToAnyPublisher() 47 | } 48 | 49 | private func createDeviceList(message: String, dict: [String: String]?) -> DeviceListModel { 50 | return DeviceListModel(list: []) 51 | } 52 | 53 | func joinNetwork(_ request: JoinRequest) -> AnyPublisher { 54 | return network.dispatch(JoinNetworkRequst(token: request.token, uuid: request.uuid, deviceUUID: request.deviceID)) 55 | .compactMap({ result in 56 | return result.data 57 | }) 58 | .mapError { error in 59 | return DataError.fail(message: error.localizedDescription) 60 | } 61 | .eraseToAnyPublisher() 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceList/DataStore/DevicePingAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DevicePingAPI.swift 3 | // DeviceList 4 | // 5 | // Created by samuelsong on 2021/12/26. 6 | // 7 | 8 | import Foundation 9 | 10 | protocol DevicePingAPI: AnyObject { 11 | func ping(_ ip: String, _ complete: @escaping (Double, Error?) -> Void) 12 | } 13 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceList/DataStore/DevicePingProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DevicePingProvider.swift 3 | // DeviceList 4 | // 5 | // Created by samuelsong on 2022/1/2. 6 | // 7 | 8 | import Foundation 9 | 10 | class DevicePingProvider: DevicePingAPI { 11 | func ping(_ ip: String, _ complete: @escaping (Double, Error?) -> Void) { 12 | // Ping once 13 | let once = try? SwiftyPing(host: ip, configuration: PingConfiguration(interval: 1.0, with: 3), queue: DispatchQueue.global()) 14 | once?.observer = { (response) in 15 | var duration = response.duration * 1000.0 16 | #if false 17 | if response.error != nil { 18 | duration = -1 19 | } 20 | #endif 21 | complete(duration, response.error) 22 | } 23 | once?.targetCount = 1 24 | try? once?.startPinging() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceList/DeviceList.h: -------------------------------------------------------------------------------- 1 | // 2 | // DeviceList.h 3 | // DeviceList 4 | // 5 | // 6 | 7 | #import 8 | 9 | //! Project version number for DeviceList. 10 | FOUNDATION_EXPORT double DeviceListVersionNumber; 11 | 12 | //! Project version string for DeviceList. 13 | FOUNDATION_EXPORT const unsigned char DeviceListVersionString[]; 14 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceList/DeviceList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DeviceList.swift 3 | // DeviceList 4 | // 5 | // 6 | 7 | import Foundation 8 | import OEPlatform 9 | import Tattoo 10 | 11 | /// Document your module purpose 12 | public class DeviceList: DeviceListAPI, ProductionModule { 13 | private let scope: APICenter 14 | 15 | public init(scope: APICenter) { 16 | self.scope = scope 17 | } 18 | 19 | public func createHomeCoordinator(router: RoutingAPI, user: User, token: String) -> DeviceListCoordinator { 20 | return DeviceListCoordinatorImpl(scope: scope, router: router, user: user, token: token) 21 | } 22 | 23 | public func addProductionServices(_ scope: APICenter) { 24 | scope.registerService(DeviceListDataStoreAPI.self, DeviceListDataProvider.init) 25 | scope.registerService(DevicePingAPI.self, DevicePingProvider.init) 26 | } 27 | } 28 | 29 | extension APICenter { 30 | var pingProvider: DevicePingAPI { 31 | self.getService(DevicePingAPI.self) 32 | } 33 | var deviceListProvider: DeviceListDataStoreAPI { 34 | self.getService(DeviceListDataStoreAPI.self) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceList/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceList/Mock/DeviceList+Mock.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DeviceList+Mock.swift 3 | // DeviceList 4 | // 5 | // Created by samuelsong on 2021/11/29. 6 | // 7 | 8 | #if DEBUG 9 | 10 | import Foundation 11 | import OEPlatform 12 | 13 | extension User { 14 | static var mocked: User = User(email: "123@omniedge.com", name: "MyiPhone") 15 | } 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceList/Mock/DevicePing+Mock.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DevicePing+Mock.swift 3 | // DeviceList 4 | // 5 | // Created by samuelsong on 2021/12/26. 6 | // 7 | 8 | #if DEBUG 9 | 10 | import Tattoo 11 | 12 | class DevicePingProviderMock: DevicePingAPI { 13 | init(scope: APICenter) {} 14 | 15 | func ping(_ ip: String, _ complete: @escaping (Double) -> Void) { 16 | let delay = Double.random(in: 0..<10) 17 | DispatchQueue.main.asyncAfter(deadline: .now() + delay) { 18 | let time = Double.random(in: 0..<600) 19 | complete(time) 20 | } 21 | } 22 | } 23 | 24 | #endif 25 | 26 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceList/Models/NetworkListModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkListModel.swift 3 | // DeviceList 4 | // 5 | // Created by samuelsong on 2021/11/6. 6 | // 7 | 8 | import Foundation 9 | 10 | /* 11 | //list network 12 | { 13 | "message": "List virtual network successfully", 14 | "data": [ 15 | { 16 | "uuid": "935ab516-8bf3-440a-b32e-002ce3bf7771", 17 | "name": "My omni network", 18 | "ip_range": "100.100.0.0/24", 19 | "role": "admin", 20 | "devices": [] 21 | } 22 | ] 23 | } 24 | */ 25 | struct NetworkListModel { 26 | var list: [NetworkModel] 27 | } 28 | 29 | struct NetworkModel: Codable { 30 | var name: String 31 | var id: String 32 | var ip_range: String 33 | var devices: [DeviceModel?] 34 | } 35 | 36 | struct DeviceListModel: Codable { 37 | var list: [DeviceModel] 38 | } 39 | 40 | struct DeviceModel: Codable { 41 | var id: String 42 | var name: String 43 | var platform: String 44 | var virtual_ip: String 45 | var last_seen: String? 46 | } 47 | 48 | /* 49 | //join network 50 | { 51 | "message": "Join virtual network successfully", 52 | "data": { 53 | "community_name": "20d3a397ecec0f", 54 | "secret_key": "32bdf7e3cbcbd5", 55 | "virtual_ip": "100.100.0.81", 56 | "subnet_mask": "255.255.255.0", 57 | "server": { 58 | "name": "China", 59 | "country": "CN", 60 | "host": "prod-cn.edgecomputing.network:7787" 61 | } 62 | } 63 | } 64 | */ 65 | struct N2NModel: Codable { 66 | var community_name: String 67 | var secret_key: String 68 | var virtual_ip: String 69 | var subnet_mask: String 70 | var server: Server 71 | 72 | struct Server: Codable { 73 | var name: String 74 | var country: String 75 | var host: String 76 | } 77 | } 78 | 79 | enum DataError: Error, Hashable { 80 | case success(message: String) 81 | case fail(message: String) 82 | case none 83 | } 84 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceListDemo/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceListDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceListDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceListDemo/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // DeviceListDemo 4 | // 5 | // 6 | 7 | import SwiftUI 8 | 9 | struct ContentView: View { 10 | var body: some View { 11 | Text("Hello, world!") 12 | .padding() 13 | } 14 | } 15 | 16 | struct ContentView_Previews: PreviewProvider { 17 | static var previews: some View { 18 | ContentView() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceListDemo/DeviceListDemoApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DeviceListDemoApp.swift 3 | // DeviceListDemo 4 | // 5 | // 6 | 7 | import SwiftUI 8 | 9 | @main 10 | struct DeviceListDemoApp: App { 11 | var body: some Scene { 12 | WindowGroup { 13 | ContentView() 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceListDemo/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | 28 | UIApplicationSupportsIndirectInputEvents 29 | 30 | UILaunchScreen 31 | 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceListDemo/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceListTests/DeviceListTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DeviceListTests.swift 3 | // DeviceListTests 4 | // 5 | // 6 | 7 | @testable import DeviceList 8 | import XCTest 9 | 10 | class DeviceListTests: XCTestCase { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Libraries/DeviceList/DeviceListTests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Libraries/DeviceList/Setting/ViewModels/SettingViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingViewModel.swift 3 | // DeviceList 4 | // 5 | // Created by samuelsong on 2021/11/28. 6 | // 7 | 8 | import Foundation 9 | import Combine 10 | 11 | protocol SettingDelegate: AnyObject { 12 | func logout() 13 | func reset() 14 | } 15 | 16 | class SettingViewModel: ObservableObject { 17 | weak var delegate: SettingDelegate? = nil 18 | 19 | func logout() { 20 | delegate?.logout() 21 | } 22 | 23 | func reset() { 24 | delegate?.reset() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Libraries/DeviceList/Setting/Views/SettingView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SettingView.swift 3 | // DeviceList 4 | // 5 | // Created by samuelsong on 2021/11/28. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct SettingView: View { 11 | @ObservedObject var viewModel: SettingViewModel 12 | 13 | var body: some View { 14 | ZStack { 15 | Color.OME.background.edgesIgnoringSafeArea(.all) 16 | List { 17 | logout 18 | reset 19 | }.background(Color.OME.background) 20 | } 21 | } 22 | 23 | @ViewBuilder 24 | var dashBoard: some View { 25 | Button(action: {}, label: { 26 | HStack { 27 | Image(systemName: "gearshape") 28 | Text("Dashboard") 29 | } 30 | }) 31 | } 32 | 33 | @ViewBuilder 34 | var support: some View { 35 | Button(action: {}, label: { 36 | HStack { 37 | Image(systemName: "questionmark.circle") 38 | Text("Support") 39 | } 40 | }) 41 | } 42 | 43 | @ViewBuilder 44 | var logout: some View { 45 | Button(action: { 46 | viewModel.logout() 47 | }, label: { 48 | HStack { 49 | Image(systemName: "rectangle.portrait.and.arrow.right.fill") 50 | Text("Logout") 51 | } 52 | }) 53 | } 54 | 55 | @ViewBuilder 56 | var reset: some View { 57 | Button(action: { 58 | viewModel.reset() 59 | }, label: { 60 | HStack { 61 | Image(systemName: "trash.slash.fill") 62 | Text("Reset") 63 | } 64 | }) 65 | } 66 | 67 | } 68 | 69 | struct SettingView_Previews: PreviewProvider { 70 | static var previews: some View { 71 | SettingView(viewModel: SettingViewModel()) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Libraries/Login/Login.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Libraries/Login/Login.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Libraries/Login/Login.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "KeychainAccess", 6 | "repositoryURL": "https://github.com/kishikawakatsumi/KeychainAccess.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "84e546727d66f1adc5439debad16270d0fdd04e7", 10 | "version": "4.2.2" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /Libraries/Login/Login.xcodeproj/xcuserdata/yong.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Login.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 2 11 | 12 | LoginDemo.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 3 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Libraries/Login/Login/DataStore/LoginDataStoreAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginDataStoreAPI.swift 3 | // Login 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/24. 6 | // 7 | // 8 | 9 | import Combine 10 | 11 | protocol LoginDataStoreAPI { 12 | func login(_ model: LoginModel) -> AnyPublisher 13 | func register(_ model: RegisterModel) -> AnyPublisher 14 | func reset(_ model: ResetPasswordModel) -> AnyPublisher 15 | func registerDevice(_ token: String) -> AnyPublisher 16 | } 17 | -------------------------------------------------------------------------------- /Libraries/Login/Login/DataStore/LoginDataStoreMock.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginDataStoreMock.swift 3 | // Login 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/24. 6 | // 7 | // 8 | 9 | import Combine 10 | 11 | class LoginDataStoreMock: LoginDataStoreAPI { 12 | func login(_ model: LoginModel) -> Future { 13 | let result = LoginResult(message: "Login successfully", data: "hi") 14 | return Future { promise in 15 | DispatchQueue.main.asyncAfter(deadline: .now() + 2) { 16 | promise(Result.success(result)) 17 | } 18 | } 19 | } 20 | 21 | func register(_ model: RegisterModel) -> Future { 22 | let result = LoginResult(message: "Register successfully", data: "hi") 23 | return Future { promise in 24 | DispatchQueue.main.asyncAfter(deadline: .now() + 2) { 25 | promise(Result.success(result)) 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Libraries/Login/Login/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /Libraries/Login/Login/Login.h: -------------------------------------------------------------------------------- 1 | // 2 | // Login.h 3 | // Login 4 | // 5 | // 6 | 7 | #import 8 | 9 | //! Project version number for Login. 10 | FOUNDATION_EXPORT double LoginVersionNumber; 11 | 12 | //! Project version string for Login. 13 | FOUNDATION_EXPORT const unsigned char LoginVersionString[]; 14 | -------------------------------------------------------------------------------- /Libraries/Login/Login/Login.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Login.swift 3 | // Login 4 | // 5 | // 6 | 7 | import Foundation 8 | import OEPlatform 9 | import Tattoo 10 | 11 | public class Login: LoginAPI { 12 | private let scope: APICenter 13 | 14 | public init(scope: APICenter) { 15 | self.scope = scope 16 | } 17 | 18 | public func createLoginCoordinator(router: RoutingAPI) -> LoginCoordinator { 19 | return LoginCoordinatorImpl(scope: scope, router: router) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Libraries/Login/Login/Mock/LoginDataStoreMock.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginDataStoreMock.swift 3 | // Login 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/24. 6 | // 7 | // 8 | 9 | import Combine 10 | 11 | #if DEBUG 12 | 13 | class LoginDataStoreMock: LoginDataStoreAPI { 14 | func registerDevice(_ token: String) -> AnyPublisher { 15 | let result = RegisterDeviceResult(id: "sfsd") 16 | return Deferred { 17 | Future { promise in 18 | DispatchQueue.main.asyncAfter(deadline: .now() + 2) { 19 | promise(Result.success(result)) 20 | } 21 | } 22 | }.eraseToAnyPublisher() 23 | } 24 | 25 | func login(_ model: LoginModel) -> AnyPublisher { 26 | let result = LoginResult(token: "sdufifjsf&6sfsSFsljfsdlkj112@3kjflj", refreshToken: "123", expires_at: "34") 27 | return Deferred { 28 | Future { promise in 29 | DispatchQueue.main.asyncAfter(deadline: .now() + 2) { 30 | promise(Result.success(result)) 31 | } 32 | } 33 | }.eraseToAnyPublisher() 34 | } 35 | 36 | func register(_ model: RegisterModel) -> AnyPublisher { 37 | let result = RegisterResult(id: "234") 38 | return Deferred { 39 | Future { promise in 40 | DispatchQueue.main.asyncAfter(deadline: .now() + 2) { 41 | promise(Result.success(result)) 42 | } 43 | } 44 | }.eraseToAnyPublisher() 45 | } 46 | 47 | func reset(_ model: ResetPasswordModel) -> AnyPublisher { 48 | let result = ResetResult(id: "sfs") 49 | return Deferred { 50 | Future { promise in 51 | DispatchQueue.main.asyncAfter(deadline: .now() + 2) { 52 | promise(Result.success(result)) 53 | } 54 | } 55 | }.eraseToAnyPublisher() 56 | } 57 | } 58 | 59 | #endif //DEBUG 60 | -------------------------------------------------------------------------------- /Libraries/Login/Login/Model/LoginModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginModel.swift 3 | // Login 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/24. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | struct RegisterModel { 12 | var name: String 13 | var email: String 14 | var password: String 15 | } 16 | 17 | struct LoginModel { 18 | var email: String 19 | var password: String 20 | } 21 | 22 | struct ResetPasswordModel { 23 | var email: String 24 | } 25 | 26 | struct LoginResult { 27 | var token: String? 28 | var refreshToken: String? 29 | var expires_at: String? 30 | } 31 | 32 | struct RegisterResult { 33 | var id: String? 34 | } 35 | 36 | struct ResetResult { 37 | var id: String? 38 | } 39 | 40 | struct RegisterDeviceResult { 41 | var id: String? 42 | } 43 | 44 | enum AuthError: Error, Hashable { 45 | case success(message: String) 46 | case fail(message: String) 47 | case none 48 | } 49 | -------------------------------------------------------------------------------- /Libraries/Login/Login/ViewModels/Validation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Validation.swift 3 | // Login 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/9/4. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | class Validation { 12 | //validate both password and email 13 | static func checkEmailAndPassword(_ email: String, _ password: String) -> Bool { 14 | return checkEmail(email) && checkPasswordLength(password) && checkPasswordCharacterSet(password) 15 | } 16 | //validate a formal email address 17 | static func checkEmail(_ email: String) -> Bool { 18 | let emailRegex = 19 | "(?:[a-z0-9!#$%\\&'*+/=?\\^_`{|}~-]+(?:\\.[a-z0-9!#$%\\&'*+/=?\\^_`{|}" + 20 | "~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\" + 21 | "x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-" + 22 | "z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5" + 23 | "]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-" + 24 | "9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21" + 25 | "-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])" 26 | 27 | let result = email.range(of: emailRegex, options: .regularExpression) 28 | return result != nil ? true : false 29 | } 30 | //validate a password has a number at least 31 | static func checkPasswordCharacterSet(_ password: String) -> Bool { 32 | var rules = 0 33 | if password.rangeOfCharacter(from: CharacterSet.decimalDigits)?.isEmpty == false { 34 | rules += 1 35 | } 36 | if password.rangeOfCharacter(from: CharacterSet.lowercaseLetters)?.isEmpty == false { 37 | rules += 1 38 | } 39 | if password.rangeOfCharacter(from: CharacterSet.uppercaseLetters)?.isEmpty == false { 40 | rules += 1 41 | } 42 | if password.rangeOfCharacter(from: CharacterSet.symbols)?.isEmpty == false || 43 | password.rangeOfCharacter(from: CharacterSet.punctuationCharacters)?.isEmpty == false { 44 | rules += 1 45 | } 46 | return rules >= 4 ? true : false 47 | } 48 | //validate a password is between 8 and 20 characters long inclusive 49 | static func checkPasswordLength(_ password: String) -> Bool { 50 | //length is 8 to 20 long 51 | return password.count >= 8 && password.count <= 20 ? true : false 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Libraries/Login/Login/Views/InvalidEntryView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InvalidEntryView.swift 3 | // Login 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/9/4. 6 | // 7 | // 8 | 9 | import OEUIKit 10 | import SwiftUI 11 | 12 | struct InvalidEntryView: View { 13 | var isInvalid: Bool 14 | var message: String 15 | var body: some View { 16 | if isInvalid { 17 | HStack { 18 | Image(systemName: "x.circle") 19 | .imageColorAppearance(color: Color.OME.error) 20 | Text(message) 21 | .font(.system(size: 11)) 22 | } 23 | } else { 24 | HStack { 25 | Image(systemName: "checkmark.circle") 26 | .imageColorAppearance(color: Color.OME.successGreen) 27 | Text(message) 28 | .font(.system(size: 11)) 29 | } 30 | 31 | } 32 | } 33 | } 34 | 35 | struct InvalidEntryView_Previews: PreviewProvider { 36 | static var previews: some View { 37 | HStack { 38 | VStack(alignment: .leading) { 39 | InvalidEntryView(isInvalid: true, message: "Invalid password") 40 | InvalidEntryView(isInvalid: false, message: "Good password") 41 | } 42 | Spacer() 43 | }.padding() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Libraries/Login/Login/Views/LoginCommonView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginCommonView.swift 3 | // Login 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/9/5. 6 | // 7 | // 8 | 9 | import OEUIKit 10 | import SwiftUI 11 | 12 | struct GoogleLoginView: View { 13 | var login: () -> Void 14 | public var body: some View { 15 | Button(action: { 16 | withAnimation { 17 | login() 18 | } 19 | }, label: { 20 | HStack { 21 | Image.OME.google 22 | Spacer().frame(width: 20) 23 | Text("Continue with Google") 24 | .foregroundColor(Color(.black.withAlphaComponent(0.54))) 25 | .font(Font.OME.buttonSecondary) 26 | } 27 | }) 28 | .buttonStyle(SecondaryButtonStyle()) 29 | .disabled(true) 30 | .padding(.top, 5) 31 | } 32 | } 33 | 34 | struct LoginCommonView_Previews: PreviewProvider { 35 | static var previews: some View { 36 | GoogleLoginView { 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Libraries/Login/Login/Views/ResetPasswordView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ForgetPasswordView.swift 3 | // Login 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/16. 6 | // 7 | // 8 | 9 | import OEUIKit 10 | import SwiftUI 11 | 12 | struct ResetPasswordView: View { 13 | @ObservedObject var viewModel: LoginViewModel 14 | @State var email: String = "" 15 | 16 | init(email: String, viewModel: LoginViewModel) { 17 | self.email = email 18 | self.viewModel = viewModel 19 | configureBackground() 20 | } 21 | 22 | public var body: some View { 23 | ZStack { 24 | Color.OME.background.onTapGesture { 25 | hideKeyboard() 26 | }.edgesIgnoringSafeArea(.all) 27 | VStack(alignment: .center) { 28 | //Spacer().frame(maxHeight: 40) 29 | Image.OME.primary 30 | Text.OME.slogon.padding() 31 | Text("- forget passowrd -") 32 | .font(Font.OME.subTitle25) 33 | .foregroundColor(Color.OME.primary) 34 | .padding() 35 | VStack(alignment: .leading) { 36 | TextField("Email", text: $email) 37 | .inputButtonAppearance() 38 | .textContentType(.emailAddress) 39 | .keyboardType(.emailAddress) 40 | } 41 | .padding(.top, 5) 42 | 43 | Button(action: { 44 | withAnimation { 45 | self.viewModel.resetPassword(email: email) 46 | } 47 | }, label: { 48 | Text("Send Instruction") 49 | .foregroundColor(.white) 50 | }) 51 | .buttonStyle(PrimaryButtonStyle()) 52 | //.disabled(valid) 53 | .padding(.top, 30) 54 | Spacer() 55 | }.padding() 56 | //sinner 57 | if viewModel.loading { 58 | Spinner.forever 59 | .frame(width: 30) 60 | } 61 | } 62 | //.border(Color.black, width: 1) 63 | .navigationBarTitleDisplayMode(.inline) 64 | } 65 | } 66 | 67 | #if DEBUG 68 | 69 | struct ForgetPasswordView_Previews: PreviewProvider { 70 | static let dataStore = LoginDataStoreMock() 71 | static var previews: some View { 72 | ResetPasswordView(email: "samuel@omniedge.com", viewModel: LoginViewModel(dataStore)) 73 | } 74 | } 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /Libraries/Login/LoginDemo/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Libraries/Login/LoginDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Libraries/Login/LoginDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Libraries/Login/LoginDemo/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // LoginDemo 4 | // 5 | // 6 | 7 | @testable import Login 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | var body: some View { 12 | NavigationView { 13 | LoginView(viewModel: LoginViewModel(LoginDataStoreMock())) 14 | } 15 | } 16 | } 17 | 18 | struct ContentView_Previews: PreviewProvider { 19 | static var previews: some View { 20 | ContentView() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Libraries/Login/LoginDemo/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | 28 | UIApplicationSupportsIndirectInputEvents 29 | 30 | UILaunchScreen 31 | 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Libraries/Login/LoginDemo/LoginDemoApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginDemoApp.swift 3 | // LoginDemo 4 | // 5 | // 6 | 7 | import SwiftUI 8 | 9 | @main 10 | struct LoginDemoApp: App { 11 | var body: some Scene { 12 | WindowGroup { 13 | ContentView() 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Libraries/Login/LoginDemo/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Libraries/Login/LoginTests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Libraries/Login/LoginTests/LoginTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginTests.swift 3 | // LoginTests 4 | // 5 | // 6 | 7 | @testable import Login 8 | import XCTest 9 | 10 | class LoginTests: XCTestCase { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "KeychainAccess", 6 | "repositoryURL": "https://github.com/kishikawakatsumi/KeychainAccess.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "84e546727d66f1adc5439debad16270d0fdd04e7", 10 | "version": "4.2.2" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform.xcodeproj/xcuserdata/yong.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | OEPlatform.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 8 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/Config/OmniEdgeConfigProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OmniEdgeConfigProvider.swift 3 | // OEPlatform 4 | // 5 | // Created by samuelsong on 2021/11/22. 6 | // 7 | 8 | import Foundation 9 | import OmniedgeDylib 10 | import Tattoo 11 | 12 | public class OmniEdgeConfigProvider: ConfigAPI { 13 | public init(scope: APICenter) {} 14 | public func save(config: N2NConfig) { 15 | let writter = OmniEdgeConfig(host: config.host, port: config.port, network: config.networkName, key: config.key, ipAddr: config.ip) 16 | writter.sync() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/Coordinator/Coordinator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Coordinator.swift 3 | // OEPlatform 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/19. 6 | // 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol Coordinator: AnyObject { 12 | } 13 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/Extensions/Tattoo+Platform.swift: -------------------------------------------------------------------------------- 1 | 2 | import Tattoo 3 | 4 | fileprivate class APICenterSalt { 5 | } 6 | 7 | public extension APICenter { 8 | func getService(_ type: Service.Type) -> Service { 9 | return get(type, self) 10 | } 11 | 12 | func registerService(_ type: Service.Type, _ block: @escaping (APICenter) -> Service) { 13 | singleton(type, self) { scope -> AnyObject in 14 | return block(scope) as AnyObject 15 | } 16 | } 17 | 18 | func registerService(_ type: Service.Type, _ block: @escaping () -> Service) { 19 | singleton(type, self) { _ -> AnyObject in 20 | return block() as AnyObject 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/JWT/JWTUtil.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JWTUtil.swift 3 | // OEPlatform 4 | // 5 | // Created by samuelsong on 2021/11/1. 6 | // 7 | 8 | import Foundation 9 | 10 | public class JWTUtil { 11 | public static func decode(jwtToken jwt: String) -> [String: Any] { 12 | let segments = jwt.components(separatedBy: ".") 13 | return decodeJWTPart(segments[1]) ?? [:] 14 | } 15 | 16 | private static func base64UrlDecode(_ value: String) -> Data? { 17 | var base64 = value 18 | .replacingOccurrences(of: "-", with: "+") 19 | .replacingOccurrences(of: "_", with: "/") 20 | 21 | let length = Double(base64.lengthOfBytes(using: String.Encoding.utf8)) 22 | let requiredLength = 4 * ceil(length / 4.0) 23 | let paddingLength = requiredLength - length 24 | if paddingLength > 0 { 25 | let padding = "".padding(toLength: Int(paddingLength), withPad: "=", startingAt: 0) 26 | base64 += padding 27 | } 28 | return Data(base64Encoded: base64, options: .ignoreUnknownCharacters) 29 | } 30 | 31 | private static func decodeJWTPart(_ value: String) -> [String: Any]? { 32 | guard let bodyData = base64UrlDecode(value), 33 | let json = try? JSONSerialization.jsonObject(with: bodyData, options: []), 34 | let payload = json as? [String: Any] else { 35 | return nil 36 | } 37 | 38 | return payload 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/ModulesAPI/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Libraries/OEPlatform/OEPlatform/ModulesAPI/.keep -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/ModulesAPI/ConfigAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConfigAPI.swift 3 | // OEPlatform 4 | // 5 | // Created by samuelsong on 2021/11/22. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct N2NConfig { 11 | public var host: String /// server ip 12 | public var port: String /// server port 13 | public var networkName: String 14 | 15 | public var ip: String 16 | public var key: String 17 | 18 | public init(host: String, port: String, networkName: String, ip: String, key: String) { 19 | self.host = host 20 | self.port = port 21 | self.networkName = networkName 22 | self.ip = ip 23 | self.key = key 24 | } 25 | } 26 | 27 | public protocol ConfigAPI { 28 | func save(config: N2NConfig) 29 | } 30 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/ModulesAPI/DeviceListAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DeviceListAPI.swift 3 | // OEPlatform 4 | // 5 | // 6 | 7 | import Foundation 8 | import SwiftUI 9 | import Tattoo 10 | 11 | public protocol DeviceListCoordinator: Coordinator { 12 | func createHomePage() -> AnyView 13 | } 14 | 15 | public protocol DeviceListAPI { 16 | func createHomeCoordinator(router: RoutingAPI, user: User, token: String) -> DeviceListCoordinator 17 | } 18 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/ModulesAPI/LoginAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LoginAPI.swift 3 | // OEPlatform 4 | // 5 | // 6 | 7 | import Foundation 8 | import SwiftUI 9 | 10 | /// The Login public APIs to be used by other modules 11 | public protocol LoginCoordinator: Coordinator { 12 | func createLoginView() -> AnyView 13 | } 14 | 15 | public protocol LoginAPI { 16 | // TODO - add the public APIs here 17 | func createLoginCoordinator(router: RoutingAPI) -> LoginCoordinator 18 | } 19 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/ModulesAPI/PlatformModule.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import Tattoo 4 | 5 | public extension APICenter { 6 | 7 | func addSalt() { 8 | } 9 | 10 | func setupPlatformRouting() { 11 | registerService(RoutingManager.self, RoutingManagerImpl.init) 12 | } 13 | 14 | func notificationCenter() -> NotificationCenter { 15 | getService(NotificationCenter.self) 16 | } 17 | 18 | func setupPlatformNotificationCenter() { 19 | registerService(NotificationCenter.self, { NotificationCenter.default }) 20 | } 21 | 22 | func userDefaults() -> UserDefaults { 23 | getService(UserDefaults.self) 24 | } 25 | 26 | func setupPlatformUserDefaults() { 27 | registerService(UserDefaults.self, { UserDefaults.standard }) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/ModulesAPI/ProductionModule.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import Tattoo 4 | 5 | 6 | public protocol ProductionModule { 7 | func addProductionServices(_ scope: APICenter) 8 | } 9 | 10 | private class ProductionModuleSalt { 11 | } 12 | 13 | public extension APICenter { 14 | func registerModule(_ type: Module.Type, 15 | _ block: @escaping (APICenter) -> Module) { 16 | singleton(type, self) { scope -> AnyObject in 17 | let result = block(scope) 18 | if let module = result as? ProductionModule { 19 | module.addProductionServices(scope) 20 | } 21 | return result as AnyObject 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/ModulesAPI/SessionAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SessionAPI.swift 3 | // OEPlatform 4 | // 5 | // Created by samuelsong on 2021/10/31. 6 | // 7 | 8 | import Foundation 9 | 10 | public protocol SessionAPI { 11 | func login(token: String) -> Bool 12 | func logout() 13 | var token: String? { get } 14 | } 15 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/ModulesAPI/TunnelAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TunnelAPI.swift 3 | // OEPlatform 4 | // 5 | // Created by samuelsong on 2021/11/22. 6 | // 7 | 8 | import Foundation 9 | 10 | public protocol TunnelAPI { 11 | func start(_ complete: @escaping (Error?) -> Void) 12 | func stop() 13 | } 14 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/ModulesAPI/UserAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserAPI.swift 3 | // OEPlatform 4 | // 5 | // Created by samuelsong on 2021/11/21. 6 | // 7 | 8 | import Foundation 9 | 10 | public class User: Codable { 11 | /// from token 12 | public var email: String 13 | public var name: String 14 | public var picture: String? 15 | public var deviceUUID: String? /// from register 16 | public var network: OENetworkInfo? 17 | 18 | public init(email: String, name: String) { 19 | self.email = email 20 | self.name = name 21 | } 22 | } 23 | 24 | public struct OENetworkInfo: Codable { 25 | public var networkUUID: String /// from list network 26 | public var ip: String /// from join network 27 | public init(networkUUID: String, ip: String) { 28 | self.networkUUID = networkUUID 29 | self.ip = ip 30 | } 31 | } 32 | 33 | public protocol UserAPI { 34 | func createUser(token: String) -> User? 35 | func user(email: String) -> User? 36 | func setUser(_ user: User, for email: String) 37 | func clear() 38 | } 39 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/OEPlatform.h: -------------------------------------------------------------------------------- 1 | // 2 | // OEPlatform.h 3 | // OEPlatform 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for OEPlatform. 12 | FOUNDATION_EXPORT double OEPlatformVersionNumber; 13 | 14 | //! Project version string for OEPlatform. 15 | FOUNDATION_EXPORT const unsigned char OEPlatformVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/Routing/OMERouterManager.swift: -------------------------------------------------------------------------------- 1 | 2 | import Combine 3 | import UIKit 4 | 5 | public struct RoutingInterceptorResult { 6 | public var canProceed: Bool 7 | public var parameters: RoutingParameters? 8 | public var proceedWithNewRouter: RoutingAPI? 9 | 10 | public init(canProceed: Bool, 11 | parameters: RoutingParameters? = nil, 12 | proceedWithNewRouter: RoutingAPI? = nil) { 13 | self.canProceed = canProceed 14 | self.parameters = parameters 15 | self.proceedWithNewRouter = proceedWithNewRouter 16 | } 17 | } 18 | 19 | public protocol RoutingInterceptor: AnyObject { 20 | func allowTransition(_ parameters: RoutingParameters, router: RoutingAPI) -> Bool 21 | func handleInterrupt(parameters: RoutingParameters, router: RoutingAPI) -> Future 22 | } 23 | 24 | 25 | public protocol OMENavigationFactory { 26 | func makeNavigationController() -> UINavigationController 27 | } 28 | 29 | public protocol RoutingManager: AnyObject { 30 | 31 | var navigationFactory: OMENavigationFactory { get set } 32 | 33 | func createRouter() -> RoutingAPI 34 | 35 | func registerInterceptor(_ interceptor: RoutingInterceptor) 36 | } 37 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/Routing/OMERoutingManagerImpl.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | public final class RoutingManagerImpl: RoutingManager { 5 | public var navigationFactory: OMENavigationFactory = DefaultNavigationFactory() 6 | 7 | private(set) var interceptors: [RoutingInterceptor] = [] 8 | 9 | public init() {} 10 | 11 | public func createRouter() -> RoutingAPI { 12 | setupNewRouter().router 13 | } 14 | 15 | private func addSalt() {} 16 | 17 | public func registerInterceptor(_ interceptor: RoutingInterceptor) { 18 | interceptors.append(interceptor) 19 | } 20 | } 21 | 22 | extension RoutingManagerImpl: OMEInterceptProvider {} 23 | 24 | extension RoutingManagerImpl: NewRouterProvider { 25 | func setupNewRouter() -> OMENewRouterSetup { 26 | let navigationController = navigationFactory.makeNavigationController() 27 | let navigationRouter = NavigationRouter(navigationController, routerProvider: self) 28 | 29 | let interceptor = OMEInterceptRouter(router: navigationRouter, interceptorProvider: self) 30 | return OMENewRouterSetup(navigationController: navigationController, router: interceptor) 31 | } 32 | } 33 | 34 | final class DefaultNavigationFactory: OMENavigationFactory { 35 | func makeNavigationController() -> UINavigationController { 36 | let result = UINavigationController() 37 | result.navigationBar.prefersLargeTitles = true 38 | return result 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/Routing/Views/NAVControllerWrapper.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct NAVControllerWrapper: UIViewControllerRepresentable { 4 | let navigationController: UINavigationController 5 | 6 | func makeCoordinator() -> UINavigationController { 7 | return navigationController 8 | } 9 | 10 | func makeUIViewController(context: Context) -> UINavigationController { 11 | return context.coordinator 12 | } 13 | 14 | func updateUIViewController(_ uiViewController: UINavigationController, context: Context) { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/Routing/Views/OMENavigationView.swift: -------------------------------------------------------------------------------- 1 | 2 | import SwiftUI 3 | import Tattoo 4 | 5 | public struct OMENavigationView: View { 6 | 7 | let routingManager: NewRouterProvider 8 | 9 | let viewProvider: (RoutingAPI) -> Content 10 | 11 | public init(scope: APICenter, @ViewBuilder content: @escaping (RoutingAPI) -> Content) { 12 | self.routingManager = scope.newRouterProvider 13 | self.viewProvider = content 14 | } 15 | 16 | private func beginSalt() { 17 | } 18 | 19 | public var body: some View { 20 | let navigationController = createNewNavigationController() 21 | NAVControllerWrapper(navigationController: navigationController) 22 | .onPreferenceChange(NAVBarTintColorKey.self, perform: { value in 23 | navigationController.navigationBar.tintColor = value.map { UIColor($0) } 24 | }) 25 | } 26 | 27 | private func createNewNavigationController() -> UINavigationController { 28 | let setup = routingManager.setupNewRouter() 29 | let child = AnyView(viewProvider(setup.router)) 30 | _ = setup.router.push(view: child) 31 | return setup.navigationController 32 | } 33 | } 34 | 35 | struct SHNavigationView_Previews: PreviewProvider { 36 | static let scope: APICenter = { 37 | let result = APICenter() 38 | result.registerService(RoutingManager.self, RoutingManagerImpl.init) 39 | return result 40 | }() 41 | static var previews: some View { 42 | OMENavigationView(scope: scope) { _ in 43 | Text("world!") 44 | .navigationTitle("Hello") 45 | } 46 | } 47 | } 48 | 49 | extension APICenter { 50 | var newRouterProvider: NewRouterProvider { 51 | let routingManager = getService(RoutingManager.self) as? NewRouterProvider 52 | return routingManager ?? getService(NewRouterProvider.self) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/Routing/Views/SHNavigationPreferences.swift: -------------------------------------------------------------------------------- 1 | 2 | import SwiftUI 3 | 4 | public struct NAVBarTintColorKey: PreferenceKey { 5 | public static var defaultValue: Color? 6 | 7 | public static func reduce(value: inout Color?, nextValue: () -> Color?) { 8 | value = nextValue() ?? value 9 | } 10 | } 11 | 12 | public extension View { 13 | func navigationBarTintColor(_ color: Color?) -> some View { 14 | self.preference(key: NAVBarTintColorKey.self, value: color) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/SessionManager/SessionManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SessionManager.swift 3 | // OEPlatform 4 | // 5 | // Created by samuelsong on 2021/10/31. 6 | // 7 | 8 | import Foundation 9 | import KeychainAccess 10 | import Tattoo 11 | 12 | struct Session { 13 | public static let dataKey = "data" 14 | public static let usrKey = "user" 15 | public static let emailKey = "email" 16 | public static let nameKey = "name" 17 | public static let tokenKey = "token" 18 | public static let expireKey = "exp" 19 | public static let uuidKey = "uuid" 20 | public static let pictureURLKey = "imageURL" 21 | } 22 | 23 | public class SessionManager: SessionAPI { 24 | public var token: String? 25 | static private let guid = "S4K8QNVVRR.com.omniedge.client" 26 | private var expire: Date? 27 | 28 | public init(scope: APICenter) { 29 | loadFromKeychain() 30 | } 31 | 32 | public func login(token: String) -> Bool { 33 | let keychain = Keychain(service: Self.guid) 34 | 35 | let dict = JWTUtil.decode(jwtToken: token) 36 | guard !dict.isEmpty else { 37 | return false 38 | } 39 | keychain[Session.tokenKey] = token 40 | self.token = token 41 | return true 42 | } 43 | 44 | public func logout() { 45 | let keychain = Keychain(service: Self.guid) 46 | do { 47 | try keychain.removeAll() 48 | self.expire = nil 49 | } catch { 50 | // 51 | } 52 | } 53 | 54 | @discardableResult 55 | private func loadFromKeychain() -> Bool { 56 | let keychain = Keychain(service: Self.guid) 57 | if let token = keychain[Session.tokenKey] { 58 | self.token = token 59 | return true 60 | } 61 | return false 62 | } 63 | } 64 | 65 | public extension String { 66 | struct JWTUser { 67 | public var name: String? 68 | public var email: String? 69 | } 70 | var jwt: JWTUser? { 71 | let dict = JWTUtil.decode(jwtToken: self) 72 | guard !dict.isEmpty else { 73 | return nil 74 | } 75 | 76 | if let data = dict[Session.dataKey] as? [String: Any], 77 | let user = data[Session.usrKey] as? [String: Any] { 78 | return JWTUser(name: user[Session.nameKey] as? String, email: user[Session.emailKey] as? String) 79 | } 80 | return nil 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatform/SessionManager/UserManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserManager.swift 3 | // OEPlatform 4 | // 5 | // Created by samuelsong on 2021/11/21. 6 | // 7 | 8 | import Foundation 9 | import Tattoo 10 | 11 | public class UserManager: UserAPI { 12 | let scope: APICenter 13 | 14 | public init(scope: APICenter) { 15 | self.scope = scope 16 | } 17 | 18 | public func user(email: String) -> User? { 19 | if let user: User? = scope.userDefaults().getDecodable(for: email) { 20 | return user 21 | } else { 22 | return nil 23 | } 24 | } 25 | 26 | public func setUser(_ user: User, for email: String) { 27 | do { 28 | try scope.userDefaults().setEncodable(user, for: email) 29 | } catch { 30 | // 31 | } 32 | } 33 | 34 | public func createUser(token: String) -> User? { 35 | guard let jwt = token.jwt, let email = jwt.email, let name = jwt.name else { 36 | return nil 37 | } 38 | let user = User(email: email, name: name) 39 | do { 40 | try scope.userDefaults().setEncodable(user, for: email) 41 | } catch { 42 | return nil 43 | } 44 | return user 45 | } 46 | 47 | public func clear() { 48 | if let identifier = Bundle.main.bundleIdentifier { 49 | scope.userDefaults().removePersistentDomain(forName: identifier) 50 | } 51 | } 52 | } 53 | 54 | extension UserDefaults { 55 | func setEncodable(_ encodable: T, for key: String) throws { 56 | let data = try PropertyListEncoder().encode(encodable) 57 | self.set(data, forKey: key) 58 | } 59 | 60 | func getDecodable(for key: String) -> T? { 61 | guard 62 | self.object(forKey: key) != nil, 63 | let data = self.value(forKey: key) as? Data 64 | else { 65 | return nil 66 | } 67 | 68 | let obj = try? PropertyListDecoder().decode(T.self, from: data) 69 | return obj 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatformTests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Libraries/OEPlatform/OEPlatformTests/OEPlatformTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OEPlatformTests.swift 3 | // OEPlatformTests 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/14. 6 | // 7 | // 8 | 9 | @testable import OEPlatform 10 | import XCTest 11 | 12 | class OEPlatformTests: XCTestCase { 13 | 14 | override func setUpWithError() throws { 15 | try super.setUpWithError() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDownWithError() throws { 20 | try super.tearDownWithError() 21 | // Put teardown code here. This method is called after the invocation of each test method in the class. 22 | } 23 | 24 | func testExample() throws { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() throws { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | .PHONY : hook tools templates all 3 | #.SILENT : init tools 4 | 5 | NO_COLOR='\033[0m' 6 | GREEN='\033[0;32m' 7 | 8 | hook: 9 | git config core.hooksPath .githooks 10 | 11 | tools: 12 | ./scripts/setup_devtools.sh 13 | 14 | templates: 15 | ./scripts/setup_templates.sh 16 | 17 | all: | hook tools templates 18 | -------------------------------------------------------------------------------- /Omniedge.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Omniedge.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Omniedge.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Omniedge.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "Amplify", 6 | "repositoryURL": "https://github.com/aws-amplify/amplify-ios", 7 | "state": { 8 | "branch": null, 9 | "revision": "58b8f469e988f101957e4a80508a39b90a518a56", 10 | "version": "1.8.1" 11 | } 12 | }, 13 | { 14 | "package": "AppSyncRealTimeClient", 15 | "repositoryURL": "https://github.com/aws-amplify/aws-appsync-realtime-client-ios.git", 16 | "state": { 17 | "branch": null, 18 | "revision": "16c2c3aaf0b0a812dbc2023cecb0dbd433f99810", 19 | "version": "1.4.4" 20 | } 21 | }, 22 | { 23 | "package": "AWSiOSSDKV2", 24 | "repositoryURL": "https://github.com/aws-amplify/aws-sdk-ios-spm.git", 25 | "state": { 26 | "branch": null, 27 | "revision": "9057509ddfc1f3ef1c36264e9b8e8173eda634c9", 28 | "version": "2.23.3" 29 | } 30 | }, 31 | { 32 | "package": "SQLite.swift", 33 | "repositoryURL": "https://github.com/stephencelis/SQLite.swift.git", 34 | "state": { 35 | "branch": null, 36 | "revision": "0a9893ec030501a3956bee572d6b4fdd3ae158a1", 37 | "version": "0.12.2" 38 | } 39 | }, 40 | { 41 | "package": "Starscream", 42 | "repositoryURL": "https://github.com/daltoniam/Starscream", 43 | "state": { 44 | "branch": null, 45 | "revision": "e6b65c6d9077ea48b4a7bdda8994a1d3c6969c8d", 46 | "version": "3.1.1" 47 | } 48 | }, 49 | { 50 | "package": "swift-nio-zlib-support", 51 | "repositoryURL": "https://github.com/apple/swift-nio-zlib-support.git", 52 | "state": { 53 | "branch": null, 54 | "revision": "37760e9a52030bb9011972c5213c3350fa9d41fd", 55 | "version": "1.0.0" 56 | } 57 | } 58 | ] 59 | }, 60 | "version": 1 61 | } 62 | -------------------------------------------------------------------------------- /Omniedge.xcodeproj/xcshareddata/xcschemes/OmniedgeTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 37 | 38 | 44 | 45 | 47 | 48 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Omniedge/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Omniedge 4 | // 5 | // Created by samuel.song.bc@gmail.com on 2021/4/22. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 13 | // Override point for customization after application launch. 14 | return true 15 | } 16 | 17 | // MARK: UISceneSession Lifecycle 18 | 19 | @available(iOS 13.0, *) 20 | func application(_ application: UIApplication, 21 | configurationForConnecting connectingSceneSession: UISceneSession, 22 | options: UIScene.ConnectionOptions) -> UISceneConfiguration { 23 | // Called when a new scene session is being created. 24 | // Use this method to select a configuration to create the new scene with. 25 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 26 | } 27 | 28 | @available(iOS 13.0, *) 29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 30 | // Called when the user discards a scene session. 31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Omniedge/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon.png -------------------------------------------------------------------------------- /Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon120-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon120-1.png -------------------------------------------------------------------------------- /Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon120.png -------------------------------------------------------------------------------- /Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon180.png -------------------------------------------------------------------------------- /Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon40x40.png -------------------------------------------------------------------------------- /Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon58.png -------------------------------------------------------------------------------- /Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon60.png -------------------------------------------------------------------------------- /Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon80.png -------------------------------------------------------------------------------- /Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Omniedge/Assets.xcassets/AppIcon.appiconset/AppIcon87.png -------------------------------------------------------------------------------- /Omniedge/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "AppIcon40x40.png", 5 | "idiom" : "iphone", 6 | "scale" : "2x", 7 | "size" : "20x20" 8 | }, 9 | { 10 | "filename" : "AppIcon60.png", 11 | "idiom" : "iphone", 12 | "scale" : "3x", 13 | "size" : "20x20" 14 | }, 15 | { 16 | "filename" : "AppIcon58.png", 17 | "idiom" : "iphone", 18 | "scale" : "2x", 19 | "size" : "29x29" 20 | }, 21 | { 22 | "filename" : "AppIcon87.png", 23 | "idiom" : "iphone", 24 | "scale" : "3x", 25 | "size" : "29x29" 26 | }, 27 | { 28 | "filename" : "AppIcon80.png", 29 | "idiom" : "iphone", 30 | "scale" : "2x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "filename" : "AppIcon120.png", 35 | "idiom" : "iphone", 36 | "scale" : "3x", 37 | "size" : "40x40" 38 | }, 39 | { 40 | "filename" : "AppIcon120-1.png", 41 | "idiom" : "iphone", 42 | "scale" : "2x", 43 | "size" : "60x60" 44 | }, 45 | { 46 | "filename" : "AppIcon180.png", 47 | "idiom" : "iphone", 48 | "scale" : "3x", 49 | "size" : "60x60" 50 | }, 51 | { 52 | "idiom" : "ipad", 53 | "scale" : "1x", 54 | "size" : "20x20" 55 | }, 56 | { 57 | "idiom" : "ipad", 58 | "scale" : "2x", 59 | "size" : "20x20" 60 | }, 61 | { 62 | "idiom" : "ipad", 63 | "scale" : "1x", 64 | "size" : "29x29" 65 | }, 66 | { 67 | "idiom" : "ipad", 68 | "scale" : "2x", 69 | "size" : "29x29" 70 | }, 71 | { 72 | "idiom" : "ipad", 73 | "scale" : "1x", 74 | "size" : "40x40" 75 | }, 76 | { 77 | "idiom" : "ipad", 78 | "scale" : "2x", 79 | "size" : "40x40" 80 | }, 81 | { 82 | "idiom" : "ipad", 83 | "scale" : "1x", 84 | "size" : "76x76" 85 | }, 86 | { 87 | "idiom" : "ipad", 88 | "scale" : "2x", 89 | "size" : "76x76" 90 | }, 91 | { 92 | "idiom" : "ipad", 93 | "scale" : "2x", 94 | "size" : "83.5x83.5" 95 | }, 96 | { 97 | "filename" : "AppIcon.png", 98 | "idiom" : "ios-marketing", 99 | "scale" : "1x", 100 | "size" : "1024x1024" 101 | } 102 | ], 103 | "info" : { 104 | "author" : "xcode", 105 | "version" : 1 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Omniedge/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Omniedge/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Omniedge/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Omniedge/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | UISceneStoryboardFile 37 | Main 38 | 39 | 40 | 41 | 42 | UIApplicationSupportsIndirectInputEvents 43 | 44 | UILaunchStoryboardName 45 | LaunchScreen 46 | UIMainStoryboardFile 47 | Main 48 | UIRequiredDeviceCapabilities 49 | 50 | armv7 51 | 52 | UISupportedInterfaceOrientations 53 | 54 | UIInterfaceOrientationPortrait 55 | 56 | UISupportedInterfaceOrientations~ipad 57 | 58 | UIInterfaceOrientationPortrait 59 | UIInterfaceOrientationPortraitUpsideDown 60 | UIInterfaceOrientationLandscapeLeft 61 | UIInterfaceOrientationLandscapeRight 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /Omniedge/Omniedge.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.networking.networkextension 6 | 7 | packet-tunnel-provider 8 | 9 | com.apple.developer.networking.vpn.api 10 | 11 | allow-vpn 12 | 13 | com.apple.security.application-groups 14 | 15 | group.com.meandlife.Omniedge 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Omniedge/SwiftUI/AlertButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlertButton.swift 3 | // Omniedge 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/6/20. 6 | // 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct AlertButton: View { 12 | @State private var showAlert = false 13 | 14 | var text: String 15 | var title: String 16 | var message: String? 17 | var confirm: (() -> Void)? 18 | var cancel: (() -> Void)? 19 | 20 | var body: some View { 21 | Button(action: { 22 | self.showAlert = true 23 | }, label: { 24 | Text(text).foregroundColor(.red) 25 | }) 26 | .alert(isPresented: $showAlert) { 27 | Alert( 28 | title: Text(title), 29 | message: Text(message ?? ""), 30 | primaryButton: .destructive(Text("确认"), action: { self.confirm?() }), 31 | secondaryButton: .cancel(Text("取消"), action: { self.cancel?() }) 32 | ) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Omniedge/SwiftUI/ListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListView.swift 3 | // Omniedge 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/6/20. 6 | // 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct ListView: View { 12 | var body: some View { 13 | Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) 14 | } 15 | } 16 | 17 | struct ListView_Previews: PreviewProvider { 18 | static var previews: some View { 19 | ListView() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Omniedge/SwiftUI/MainViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewModel.swift 3 | // Omniedge 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/6/20. 6 | // 7 | // 8 | 9 | import Foundation 10 | import OmniedgeDylib 11 | 12 | final class MainViewModel: ObservableObject { 13 | @Published var config: OmniEdgeConfig 14 | @Published var status = OmniEdgeManager.Status.offline 15 | @Published var showAlert = false 16 | 17 | init(config: OmniEdgeConfig) { 18 | self.config = config 19 | OmniEdgeManager.shared.statusDidChangeHandler = { [weak self] status in 20 | self?.status = status 21 | } 22 | } 23 | 24 | func handleStart() { 25 | OmniEdgeManager.shared.start(with: config) { _ in 26 | } 27 | } 28 | 29 | func handleStop() { 30 | OmniEdgeManager.shared.stop() 31 | } 32 | 33 | func handleRemove() { 34 | OmniEdgeManager.shared.removeFromPreferences { error in 35 | if error != nil { 36 | self.showAlert = true 37 | } else { 38 | self.showAlert = false 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Omniedge/SwiftUI/UIView+Keyboard.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Keyboard.swift 3 | // Omniedge 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/6/20. 6 | // 7 | // 8 | 9 | import SwiftUI 10 | 11 | extension View { 12 | func hideKeyboard() { 13 | UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /OmniedgeDylib/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /OmniedgeDylib/OmniEdgeLog.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OmniEdgeLog.swift 3 | // Tunnel 4 | // 5 | // Created by samuel.song.bc@gmail.com on 2021/5/24. 6 | // 7 | 8 | import Foundation 9 | import OSLog 10 | 11 | typealias OmniEdgeLog = OSLog 12 | -------------------------------------------------------------------------------- /OmniedgeDylib/OmniedgeDylib.h: -------------------------------------------------------------------------------- 1 | // 2 | // OmniedgeDylib.h 3 | // OmniedgeDylib 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/6/20. 6 | // 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for OmniedgeDylib. 12 | FOUNDATION_EXPORT double OmniedgeDylibVersionNumber; 13 | 14 | //! Project version string for OmniedgeDylib. 15 | FOUNDATION_EXPORT const unsigned char OmniedgeDylibVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /OmniedgeDylib/OmniedgeDylib.xcodeproj/xcuserdata/yong.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | OmniedgeDylib.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 7 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /OmniedgeDylibTests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /OmniedgeDylibTests/OmniedgeDylibTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OmniedgeDylibTests.swift 3 | // OmniedgeDylibTests 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/6/20. 6 | // 7 | // 8 | 9 | @testable import OmniedgeDylib 10 | import XCTest 11 | 12 | class OmniedgeDylibTests: XCTestCase { 13 | 14 | override func setUpWithError() throws { 15 | try super.setUpWithError() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDownWithError() throws { 20 | try super.tearDownWithError() 21 | // Put teardown code here. This method is called after the invocation of each test method in the class. 22 | } 23 | 24 | func testExample() throws { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() throws { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /OmniedgeNew/AllTests.xctestplan: -------------------------------------------------------------------------------- 1 | { 2 | "configurations" : [ 3 | { 4 | "id" : "136BB69F-1F9B-4265-98DB-52E735616999", 5 | "name" : "Configuration 1", 6 | "options" : { 7 | } 8 | } 9 | ], 10 | "defaultOptions" : { 11 | }, 12 | "testTargets" : [ 13 | { 14 | "target" : { 15 | "containerPath" : "container:..\/Libraries\/OEPlatform\/OEPlatform.xcodeproj", 16 | "identifier" : "7EF5A35D26C767E300EDFC03", 17 | "name" : "OEPlatformTests" 18 | } 19 | }, 20 | { 21 | "target" : { 22 | "containerPath" : "container:..\/Libraries\/Login\/Login.xcodeproj", 23 | "identifier" : "8EC12D40A59F4E845C71699F", 24 | "name" : "LoginTests" 25 | } 26 | }, 27 | { 28 | "target" : { 29 | "containerPath" : "container:..\/Libraries\/DeviceList\/DeviceList.xcodeproj", 30 | "identifier" : "9FECE060343F3651D9BC119C", 31 | "name" : "DeviceListTests" 32 | } 33 | } 34 | ], 35 | "version" : 1 36 | } -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew.xcodeproj/xcuserdata/yong.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | OmniedgeNew.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 4 11 | 12 | Tunnel.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 5 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "KeychainAccess", 6 | "repositoryURL": "https://github.com/kishikawakatsumi/KeychainAccess.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "84e546727d66f1adc5439debad16270d0fdd04e7", 10 | "version": "4.2.2" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew.xcworkspace/xcuserdata/yong.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew.xcworkspace/xcuserdata/yong.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon1024.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon20@1x.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon20@2x.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon29@1x.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon29@2x-1.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon29@2x.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon29@3x.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon40.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon40@1x.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon40@2x-1.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon40@2x.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon40@3x.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon60.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon60@2x.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon60@3x.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon76@1x.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon76@2x.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/OmniedgeNew/OmniedgeNew/Assets.xcassets/AppIcon.appiconset/icon83.5@2x.png -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // OmniedgeNew 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/14. 6 | // 7 | // 8 | 9 | #if DEBUG 10 | 11 | @testable import Login 12 | 13 | import SwiftUI 14 | 15 | struct ContentView: View { 16 | var body: some View { 17 | NavigationView { 18 | LoginView(viewModel: LoginViewModel(LoginDataStoreMock())) 19 | } 20 | } 21 | } 22 | 23 | struct ContentView_Previews: PreviewProvider { 24 | static var previews: some View { 25 | ContentView() 26 | } 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | 28 | UIApplicationSupportsIndirectInputEvents 29 | 30 | UILaunchScreen 31 | 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | 40 | UISupportedInterfaceOrientations~ipad 41 | 42 | UIInterfaceOrientationPortrait 43 | UIInterfaceOrientationPortraitUpsideDown 44 | UIInterfaceOrientationLandscapeLeft 45 | UIInterfaceOrientationLandscapeRight 46 | 47 | UIUserInterfaceStyle 48 | Light 49 | 50 | 51 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/OmniedgeNew.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.networking.networkextension 6 | 7 | packet-tunnel-provider 8 | 9 | com.apple.security.application-groups 10 | 11 | group.com.jieqi.omniedge 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/OmniedgeNewApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OmniedgeNewApp.swift 3 | // OmniedgeNew 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/14. 6 | // 7 | // 8 | 9 | import SwiftUI 10 | import Tattoo 11 | 12 | @main 13 | struct OmniedgeNewApp: App { 14 | @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate 15 | var body: some Scene { 16 | WindowGroup { 17 | appDelegate.appCoordinator.contentView.ignoresSafeArea().navigationBarHidden(true) 18 | } 19 | } 20 | } 21 | 22 | class AppDelegate: NSObject, UIApplicationDelegate { 23 | private let appScope = APICenter() 24 | let appCoordinator: AppCoordinator 25 | 26 | override init() { 27 | appCoordinator = AppCoordinator(scope: appScope) 28 | super.init() 29 | } 30 | 31 | func application(_ application: UIApplication, 32 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { 33 | appCoordinator.bootstrap(scope: appScope) 34 | return true 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/OmniedgeNewRelease.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.networking.networkextension 6 | 7 | packet-tunnel-provider 8 | 9 | com.apple.security.application-groups 10 | 11 | group.com.jieqi.omniedge 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNew/TunnelProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TunnelProvider.swift 3 | // OmniedgeNew 4 | // 5 | // Created by samuelsong on 2021/11/22. 6 | // 7 | 8 | import Foundation 9 | import OEPlatform 10 | import OmniedgeDylib 11 | import Tattoo 12 | 13 | public class TunnelProvider: TunnelAPI { 14 | public init(scope: APICenter) {} 15 | 16 | public func start(_ complete: @escaping (Error?) -> Void) { 17 | let config = OmniEdgeConfig() 18 | OmniEdgeManager.shared.start(with: config, completion: { result in 19 | complete(result) 20 | }) 21 | } 22 | 23 | public func stop() { 24 | OmniEdgeManager.shared.stop() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNewTests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNewTests/OmniedgeNewTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OmniedgeNewTests.swift 3 | // OmniedgeNewTests 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/14. 6 | // 7 | // 8 | 9 | @testable import OmniedgeNew 10 | import XCTest 11 | 12 | class OmniedgeNewTests: XCTestCase { 13 | 14 | override func setUpWithError() throws { 15 | try super.setUpWithError() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDownWithError() throws { 20 | try super.tearDownWithError() 21 | // Put teardown code here. This method is called after the invocation of each test method in the class. 22 | } 23 | 24 | func testExample() throws { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() throws { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNewUITests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /OmniedgeNew/OmniedgeNewUITests/OmniedgeNewUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OmniedgeNewUITests.swift 3 | // OmniedgeNewUITests 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/14. 6 | // 7 | // 8 | 9 | import XCTest 10 | 11 | class OmniedgeNewUITests: XCTestCase { 12 | 13 | override func setUpWithError() throws { 14 | try super.setUpWithError() 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | 17 | // In UI tests it is usually best to stop immediately when a failure occurs. 18 | continueAfterFailure = false 19 | 20 | // In UI tests it’s important to set the initial state - such as interface orientation 21 | //- required for your tests before they run. The setUp method is a good place to do this. 22 | } 23 | 24 | override func tearDownWithError() throws { 25 | try super.tearDownWithError() 26 | // Put teardown code here. This method is called after the invocation of each test method in the class. 27 | } 28 | 29 | func testExample() throws { 30 | // UI tests must launch the application that they test. 31 | let app = XCUIApplication() 32 | app.launch() 33 | 34 | // Use recording to get started writing UI tests. 35 | // Use XCTAssert and related functions to verify your tests produce the correct results. 36 | } 37 | 38 | func testLaunchPerformance() throws { 39 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { 40 | // This measures how long it takes to launch your application. 41 | measure(metrics: [XCTApplicationLaunchMetric()]) { 42 | XCUIApplication().launch() 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /OmniedgeNew/Tunnel/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.networkextension.packet-tunnel 9 | NSExtensionPrincipalClass 10 | $(PRODUCT_MODULE_NAME).PacketTunnelProvider 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /OmniedgeNew/Tunnel/Tunnel-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import "edge_ios_oc.h" 6 | -------------------------------------------------------------------------------- /OmniedgeNew/Tunnel/Tunnel.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.networking.networkextension 6 | 7 | packet-tunnel-provider 8 | 9 | com.apple.developer.networking.vpn.api 10 | 11 | allow-vpn 12 | 13 | com.apple.security.application-groups 14 | 15 | group.com.jieqi.omniedge 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /OmniedgeTests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /OmniedgeTests/OmniedgeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OmniedgeTests.swift 3 | // OmniedgeTests 4 | // 5 | // Created by samuel.song.bc@gmail.com on 2021/4/22. 6 | // 7 | 8 | import NetworkExtension 9 | @testable import Omniedge 10 | import XCTest 11 | 12 | class OmniedgeTests: XCTestCase { 13 | private var engine: PacketTunnelEngine? 14 | private var tunnel = PacketTunnelProvider() 15 | 16 | override func setUpWithError() throws { 17 | try super.setUpWithError() 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | engine = PacketTunnelEngine(provider: tunnel) 20 | } 21 | 22 | override func tearDownWithError() throws { 23 | try super.tearDownWithError() 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | print("Omniedge: test done\n") 26 | } 27 | 28 | func testExample() throws { 29 | // This is an example of a functional test case. 30 | // Use XCTAssert and related functions to verify your tests produce the correct results. 31 | if let engine = engine { 32 | let config = OmniEdgeConfig() 33 | engine.start(config: config) 34 | 35 | //tun 36 | sleep(5) 37 | print("send tun\n") 38 | var hello = "hello from tun" 39 | var data = Data(hello.utf8) 40 | engine.onTunData(data) 41 | 42 | #if false 43 | //udp 44 | sleep(10) 45 | print("send udp\n") 46 | hello = "hello from udp" 47 | data = Data(hello.utf8) 48 | engine.sendEvent(event: .UDPEvent, data: data) 49 | 50 | //mgr 51 | sleep(10) 52 | print("send mgr\n") 53 | hello = "stop" 54 | data = Data(hello.utf8) 55 | engine.sendEvent(event: .MgrEvent, data: data) 56 | #endif 57 | 58 | sleep(1000) 59 | print("test over\n") 60 | } 61 | } 62 | 63 | func testPerformanceExample() throws { 64 | // This is an example of a performance test case. 65 | self.measure { 66 | // Put the code you want to measure the time of here. 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /OmniedgeUITests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /OmniedgeUITests/OmniedgeUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OmniedgeUITests.swift 3 | // OmniedgeUITests 4 | // 5 | // Created by samuel.song.bc@gmail.com on 2021/4/22. 6 | // 7 | 8 | import XCTest 9 | 10 | class OmniedgeUITests: XCTestCase { 11 | 12 | override func setUpWithError() throws { 13 | try super.setUpWithError() 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | 16 | // In UI tests it is usually best to stop immediately when a failure occurs. 17 | continueAfterFailure = false 18 | 19 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they 20 | //run. The setUp method is a good place to do this. 21 | } 22 | 23 | override func tearDownWithError() throws { 24 | try super.tearDownWithError() 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | } 27 | 28 | func testExample() throws { 29 | // UI tests must launch the application that they test. 30 | let app = XCUIApplication() 31 | app.launch() 32 | 33 | // Use recording to get started writing UI tests. 34 | // Use XCTAssert and related functions to verify your tests produce the correct results. 35 | } 36 | 37 | func testLaunchPerformance() throws { 38 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { 39 | // This measures how long it takes to launch your application. 40 | measure(metrics: [XCTApplicationLaunchMetric()]) { 41 | XCUIApplication().launch() 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Packages/OEDI/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | -------------------------------------------------------------------------------- /Packages/OEDI/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "OEDI", 8 | platforms: [ 9 | .iOS(.v14) 10 | ], 11 | products: [ 12 | // Products define the executables and libraries a package produces, and make them visible to other packages. 13 | .library( 14 | name: "OEDI", 15 | targets: ["OEDI"]) 16 | ], 17 | dependencies: [ 18 | // Dependencies declare other packages that this package depends on. 19 | // .package(url: /* package url */, from: "1.0.0"), 20 | ], 21 | targets: [ 22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 23 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 24 | .target( 25 | name: "OEDI", 26 | dependencies: []), 27 | .testTarget( 28 | name: "OEDITests", 29 | dependencies: ["OEDI"]) 30 | ] 31 | ) 32 | -------------------------------------------------------------------------------- /Packages/OEDI/README.md: -------------------------------------------------------------------------------- 1 | # OEDI 2 | 3 | Dependency injection. 4 | -------------------------------------------------------------------------------- /Packages/OEDI/Sources/OEDI/OEDI.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol InjectionKey { 4 | associatedtype Value 5 | static var currentValue: Self.Value { get set } 6 | } 7 | 8 | struct InjectedValues { 9 | private static var current = InjectedValues() 10 | 11 | static subscript(key: K.Type) -> K.Value where K: InjectionKey { 12 | get { key.currentValue } 13 | set { key.currentValue = newValue } 14 | } 15 | 16 | static subscript(_ keyPath: WritableKeyPath) -> T { 17 | get { current[keyPath: keyPath] } 18 | set { current[keyPath: keyPath] = newValue } 19 | } 20 | } 21 | 22 | @propertyWrapper 23 | struct Injected { 24 | private let keyPath: WritableKeyPath 25 | var wrappedValue: T { 26 | get { InjectedValues[keyPath] } 27 | set { InjectedValues[keyPath] = newValue } 28 | } 29 | init(_ keyPath: WritableKeyPath) { 30 | self.keyPath = keyPath 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Packages/OEDI/Tests/OEDITests/OEDITests.swift: -------------------------------------------------------------------------------- 1 | @testable import OEDI 2 | import XCTest 3 | 4 | final class OEDITests: XCTestCase { 5 | func testExample() { 6 | // This is an example of a functional test case. 7 | // Use XCTAssert and related functions to verify your tests produce the correct 8 | // results. 9 | //XCTAssertEqual(OEDI().text, "Hello, World!") 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Packages/OENetwork/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | -------------------------------------------------------------------------------- /Packages/OENetwork/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "OENetwork", 8 | platforms: [ 9 | .iOS(.v14) 10 | ], 11 | products: [ 12 | // Products define the executables and libraries a package produces, and make them visible to other packages. 13 | .library( 14 | name: "OENetwork", 15 | targets: ["OENetwork"]) 16 | ], 17 | dependencies: [ 18 | // Dependencies declare other packages that this package depends on. 19 | // .package(url: /* package url */, from: "1.0.0"), 20 | ], 21 | targets: [ 22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 23 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 24 | .target( 25 | name: "OENetwork", 26 | dependencies: []), 27 | .testTarget( 28 | name: "OENetworkTests", 29 | dependencies: ["OENetwork"]) 30 | ] 31 | ) 32 | -------------------------------------------------------------------------------- /Packages/OENetwork/README.md: -------------------------------------------------------------------------------- 1 | # OENetwork 2 | 3 | A description of this package. 4 | -------------------------------------------------------------------------------- /Packages/OENetwork/Sources/OENetwork/OENetwork.swift: -------------------------------------------------------------------------------- 1 | import Combine 2 | import Foundation 3 | 4 | public struct OENetwork { 5 | var baseURL: String! 6 | var networkDispatcher: NetworkDispatcher! 7 | 8 | public init(baseURL: String, dispatcher: NetworkDispatcher = NetworkDispatcher()) { 9 | self.baseURL = baseURL 10 | self.networkDispatcher = dispatcher 11 | } 12 | 13 | public func dispatch(_ request: R) -> AnyPublisher { 14 | //typealias RequestPublisher = AnyPublisher 15 | guard let urlRequest = request.asURLRequest(baseURL: baseURL) else { 16 | return Fail(outputType: R.ReturnType.self, 17 | failure: NetworkRequestError.badRequest).eraseToAnyPublisher() 18 | } 19 | let requestPublisher: AnyPublisher = networkDispatcher.dispatch(request: urlRequest) 20 | return requestPublisher.eraseToAnyPublisher() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Packages/OENetwork/Sources/OENetwork/OENetworkDispatch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/25. 6 | // 7 | // 8 | 9 | import Combine 10 | import Foundation 11 | 12 | public enum NetworkRequestError: LocalizedError, Equatable { 13 | case invalidRequest 14 | case badRequest 15 | case unauthorized 16 | case forbidden 17 | case notFound 18 | case error4xx(_ code: Int) 19 | case serverError 20 | case error5xx(_ code: Int) 21 | case decodingError 22 | case urlSessionFailed(_ error: URLError) 23 | case unknownError 24 | } 25 | 26 | public struct NetworkDispatcher { 27 | let urlSession: URLSession! 28 | 29 | public init(urlSession: URLSession = .shared) { 30 | self.urlSession = urlSession 31 | } 32 | 33 | public func dispatch(request: URLRequest) -> AnyPublisher { 34 | return urlSession.dataTaskPublisher(for: request) 35 | .tryMap({data, response in 36 | if let response = response as? HTTPURLResponse, !(200...299).contains(response.statusCode) { 37 | throw httpError(response.statusCode) 38 | } 39 | #if DEBUG 40 | print("data: \(String(decoding: data, as: UTF8.self))") 41 | #endif 42 | 43 | return data 44 | }) 45 | .receive(on: DispatchQueue.main) 46 | .decode(type: ReturnType.self, decoder: JSONDecoder()) 47 | .mapError { error in 48 | handleError(error) 49 | } 50 | .eraseToAnyPublisher() 51 | } 52 | } 53 | 54 | extension NetworkDispatcher { 55 | private func httpError(_ statusCode: Int) -> NetworkRequestError { 56 | switch statusCode { 57 | case 400: return .badRequest 58 | case 401: return .unauthorized 59 | case 403: return .forbidden 60 | case 404: return .notFound 61 | case 402, 405...499: return .error4xx(statusCode) 62 | case 500: return .serverError 63 | case 501...599: return .error5xx(statusCode) 64 | default: return .unknownError 65 | } 66 | } 67 | 68 | private func handleError(_ error: Error) -> NetworkRequestError { 69 | switch error { 70 | case is Swift.DecodingError: 71 | return .decodingError 72 | case let urlError as URLError: 73 | return .urlSessionFailed(urlError) 74 | case let error as NetworkRequestError: 75 | return error 76 | default: 77 | return .unknownError 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Packages/OENetwork/Sources/OENetwork/OERequest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/24. 6 | // 7 | // 8 | 9 | import Combine 10 | import Foundation 11 | 12 | public enum HTTPMethod: String { 13 | case get = "GET" 14 | case post = "POST" 15 | } 16 | 17 | public protocol Request { 18 | var method: HTTPMethod { get } 19 | var path: String { get } 20 | var headers: [String: String]? { get } 21 | var contentType: String { get } 22 | var body: [String: Any]? { get } 23 | var token: String? { get } 24 | associatedtype ReturnType: Codable 25 | } 26 | 27 | // MARK: - Default For Protocl 28 | public extension Request { 29 | var method: HTTPMethod { return .post } //default POST 30 | var headers: [String: String]? { 31 | let version: String = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "0.0.0" 32 | if let token = token { 33 | return ["User-Agent": "OmniEdge iOS \(version)", "Accept": "*/*", "Content-Type": "application/json", "Authorization": "Bearer \(token)"] 34 | } else { 35 | return ["User-Agent": "OmniEdge iOS \(version)", "Accept": "*/*", "Content-Type": "application/json"] 36 | } 37 | } 38 | var contentType: String { return "application/json" } 39 | var body: [String: Any]? { return nil } 40 | var token: String? { return nil } 41 | } 42 | 43 | // MARK: - Private 44 | extension Request { 45 | private func requestBodyFrom(_ body: [String: Any]?) -> Data? { 46 | guard let body = body else { return nil } 47 | guard let httpBody = try? JSONSerialization.data(withJSONObject: body, options: []) else { 48 | return nil 49 | } 50 | return httpBody 51 | } 52 | func asURLRequest(baseURL: String) -> URLRequest? { 53 | guard var urlComponents = URLComponents(string: baseURL) else { return nil } 54 | urlComponents.path = "\(urlComponents.path)\(path)" 55 | guard let finalURL = urlComponents.url else { return nil } 56 | var request = URLRequest(url: finalURL) 57 | request.httpMethod = method.rawValue 58 | request.httpBody = requestBodyFrom(body) 59 | request.allHTTPHeaderFields = headers 60 | request.timeoutInterval = 10 /// set 10 sew 61 | #if DEBUG 62 | print("request: \(request)") 63 | print("body: \(String(describing: body))") 64 | #endif 65 | return request 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Packages/OEUIKit/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "OEUIKit", 8 | platforms: [ 9 | .iOS(.v14) 10 | ], 11 | products: [ 12 | // Products define the executables and libraries a package produces, and make them visible to other packages. 13 | .library( 14 | name: "OEUIKit", 15 | targets: ["OEUIKit"]) 16 | ], 17 | dependencies: [ 18 | // Dependencies declare other packages that this package depends on. 19 | // .package(url: /* package url */, from: "1.0.0"), 20 | ], 21 | targets: [ 22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 23 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 24 | .target( 25 | name: "OEUIKit", 26 | dependencies: []), 27 | .testTarget( 28 | name: "OEUIKitTests", 29 | dependencies: ["OEUIKit"]) 30 | ] 31 | ) 32 | -------------------------------------------------------------------------------- /Packages/OEUIKit/README.md: -------------------------------------------------------------------------------- 1 | # OEUIKit 2 | 3 | A description of this package. 4 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Colors.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Color.swift 3 | // 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/17. 6 | // 7 | // 8 | 9 | import SwiftUI 10 | 11 | public extension Color { 12 | struct OME { 13 | //foreground 14 | public static let primary = Color("Primary", bundle: .module) 15 | public static let gray = Color("Gray", bundle: .module) 16 | public static let background: Color = Color("Background", bundle: .module) 17 | 18 | public static let label: Color = Color(.label) 19 | public static let controlBackground: Color = Color("Blue", bundle: .module) 20 | public static let gray20 = Color("Gray20", bundle: .module) 21 | public static let gray50 = Color("Gray50", bundle: .module) 22 | public static let gray60 = Color("Gray60", bundle: .module) 23 | 24 | public static let onPrimary = Color("OnPrimary", bundle: .module) 25 | public static let slate = Color("Slate", bundle: .module) 26 | 27 | public static let error: Color = Color("ErrorRed", bundle: .module) 28 | public static let successGreen = Color("SuccessGreen", bundle: .module) 29 | } 30 | } 31 | 32 | struct Color_Previews: PreviewProvider { 33 | static var previews: some View { 34 | VStack(alignment: .leading) { 35 | Button(action: {}, label: { 36 | Text("primary") 37 | .frame(maxWidth: .infinity) 38 | .foregroundColor(.white) 39 | .padding(14) 40 | }) 41 | .background(Color.OME.primary) 42 | .padding() 43 | //.border(Color.black, width: 1) 44 | 45 | Button(action: {}, label: { 46 | Text("background") 47 | .frame(maxWidth: .infinity) 48 | .foregroundColor(.black) 49 | .padding(14) 50 | }) 51 | .background(Color.OME.background) 52 | .padding() 53 | //.border(Color.black, width: 1) 54 | 55 | Button(action: {}, label: { 56 | Text("gray") 57 | .frame(maxWidth: .infinity) 58 | .foregroundColor(.black) 59 | .padding(14) 60 | }) 61 | .background(Color.OME.gray) 62 | .padding() 63 | //.border(Color.black, width: 1) 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Images.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftUIView.swift 3 | // 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/19. 6 | // 7 | // 8 | 9 | import SwiftUI 10 | 11 | public extension Image { 12 | struct OME { 13 | public static let primary = Image("PrimaryIcon", bundle: .module) 14 | public static let google = Image("Google", bundle: .module) 15 | public static let textLogoIcon = Image("TextLogoIcon", bundle: .module) 16 | public static let textLogoText = Image("TextLogoText", bundle: .module) 17 | } 18 | } 19 | 20 | public extension Image { 21 | func imageColorAppearance(color: Color) -> some View { 22 | self 23 | .renderingMode(.template) 24 | .foregroundColor(color) 25 | } 26 | } 27 | 28 | struct Images_Previews: PreviewProvider { 29 | static var previews: some View { 30 | VStack { 31 | Text("Primary Icon") 32 | .padding() 33 | Image.OME.primary 34 | Text("Google") 35 | Image.OME.google 36 | Text("Text Logo") 37 | HStack { 38 | Image.OME.textLogoIcon 39 | Image.OME.textLogoText 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Colors/Background.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xE5", 9 | "green" : "0xE5", 10 | "red" : "0xE5" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.000", 27 | "green" : "0.000", 28 | "red" : "0.000" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Colors/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Colors/ErrorRed.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x1F", 9 | "green" : "0x37", 10 | "red" : "0xCC" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x1F", 27 | "green" : "0x37", 28 | "red" : "0xCC" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Colors/Gray.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xD8", 9 | "green" : "0xD4", 10 | "red" : "0xD4" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xD8", 27 | "green" : "0xD4", 28 | "red" : "0xD4" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Colors/Gray20.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xD9", 9 | "green" : "0xD3", 10 | "red" : "0xCF" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.851", 27 | "green" : "0.831", 28 | "red" : "0.812" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Colors/Gray50.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x9A", 9 | "green" : "0x90", 10 | "red" : "0x86" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x9A", 27 | "green" : "0x90", 28 | "red" : "0x86" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Colors/Gray60.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0x63", 9 | "green" : "0x5C", 10 | "red" : "0x5D" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0x63", 27 | "green" : "0x5C", 28 | "red" : "0x5D" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Colors/OnPrimary.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xFF", 9 | "green" : "0xFF", 10 | "red" : "0xFF" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "1.000", 27 | "green" : "1.000", 28 | "red" : "1.000" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Colors/Primary.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xED", 9 | "green" : "0x59", 10 | "red" : "0x48" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "1.000", 27 | "green" : "1.000", 28 | "red" : "1.000" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Colors/Slate.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.231", 9 | "green" : "0.204", 10 | "red" : "0.184" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.231", 27 | "green" : "0.204", 28 | "red" : "0.184" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Colors/SuccessGreen.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.298", 9 | "green" : "0.706", 10 | "red" : "0.000" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.298", 27 | "green" : "0.706", 28 | "red" : "0.000" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/Google.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "logo googleg 48dp.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "logo googleg 48dp@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "logo googleg 48dp@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/Google.imageset/logo googleg 48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/Google.imageset/logo googleg 48dp.png -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/Google.imageset/logo googleg 48dp@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/Google.imageset/logo googleg 48dp@2x.png -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/Google.imageset/logo googleg 48dp@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/Google.imageset/logo googleg 48dp@3x.png -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/PrimaryIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Icon.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "Icon@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "Icon@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/PrimaryIcon.imageset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/PrimaryIcon.imageset/Icon.png -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/PrimaryIcon.imageset/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/PrimaryIcon.imageset/Icon@2x.png -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/PrimaryIcon.imageset/Icon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/PrimaryIcon.imageset/Icon@3x.png -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/TextLogoIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "TextLogoIcon.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "TextLogoIcon@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "TextLogoIcon@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/TextLogoIcon.imageset/TextLogoIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/TextLogoIcon.imageset/TextLogoIcon.png -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/TextLogoIcon.imageset/TextLogoIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/TextLogoIcon.imageset/TextLogoIcon@2x.png -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/TextLogoIcon.imageset/TextLogoIcon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/TextLogoIcon.imageset/TextLogoIcon@3x.png -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/TextLogoText.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "TextLogoText.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "TextLogoText@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "filename" : "TextLogoText@3x.png", 15 | "idiom" : "universal", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "author" : "xcode", 21 | "version" : 1 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/TextLogoText.imageset/TextLogoText.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/TextLogoText.imageset/TextLogoText.png -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/TextLogoText.imageset/TextLogoText@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/TextLogoText.imageset/TextLogoText@2x.png -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/TextLogoText.imageset/TextLogoText@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/Packages/OEUIKit/Sources/OEUIKit/Resources/Media.xcassets/Images/TextLogoText.imageset/TextLogoText@3x.png -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Spinner.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftUIView.swift 3 | // 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/9/5. 6 | // 7 | // 8 | 9 | import SwiftUI 10 | 11 | public struct Spinner: View { 12 | @Binding public var spinning: Bool 13 | @State private var enable = false 14 | 15 | private var animation: Animation { 16 | Animation.linear(duration: 1.0).repeatForever(autoreverses: false) 17 | } 18 | 19 | public var body: some View { 20 | Image(systemName: "arrow.triangle.2.circlepath") 21 | .resizable() 22 | .aspectRatio( 30.0 / 24.0, contentMode: .fit) 23 | .rotationEffect(Angle.degrees(spinning && enable ? 360 : 0)) 24 | .animation(spinning ? animation : .default) 25 | .onAppear(perform: { 26 | enable = true 27 | }) 28 | .onDisappear(perform: { 29 | enable = false 30 | }) 31 | .frame(minWidth: 12) 32 | } 33 | 34 | public static var forever: Self { 35 | .init(spinning: .constant(true)) 36 | } 37 | 38 | public init(spinning: Binding) { 39 | _spinning = spinning 40 | } 41 | } 42 | 43 | public struct LoadingView: View { 44 | public init() {} 45 | public var body: some View { 46 | VStack { 47 | Rectangle() 48 | .fill(Color.clear.opacity(0)) 49 | .allowsHitTesting(false) 50 | Spinner.forever 51 | .frame(width: 30) 52 | } 53 | } 54 | } 55 | 56 | struct Spinner_Previews: PreviewProvider { 57 | static var previews: some View { 58 | Spinner.forever 59 | .frame(width: 60) 60 | .previewLayout(.fixed(width: 200, height: 100)) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/TextFields.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Inputs.swift 3 | // 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/19. 6 | // 7 | // 8 | 9 | import SwiftUI 10 | 11 | // MARK: - Public 12 | public extension View { 13 | func inputButtonAppearance() -> some View { 14 | self.modifier(ButtonAppearance()) 15 | } 16 | 17 | func signUpButtonAppearance() -> some View { 18 | self.modifier(ContinueButtonAppearance()) 19 | } 20 | } 21 | 22 | #if canImport(UIKit) 23 | public extension View { 24 | func hideKeyboard() { 25 | UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), 26 | to: nil, 27 | from: nil, 28 | for: nil) 29 | } 30 | } 31 | #endif 32 | 33 | // MARK: - Private 34 | //customised modifier for input buttons 35 | private struct ButtonAppearance: ViewModifier { 36 | func body(content: Content) -> some View { 37 | content 38 | .padding() 39 | .autocapitalization(.none) 40 | .frame(height: 48.0) 41 | .background(Color(red: 239 / 255, green: 243 / 255, blue: 244 / 255)) 42 | .font(Font.system(size: 15, weight: .medium)) 43 | .overlay( 44 | RoundedRectangle(cornerRadius: 5) 45 | .stroke(Color.gray.opacity(0.3), lineWidth: 1) 46 | ) 47 | } 48 | } 49 | 50 | //customised modifier for continue buttons 51 | private struct ContinueButtonAppearance: ViewModifier { 52 | func body(content: Content) -> some View { 53 | content 54 | .foregroundColor(.white) 55 | .font(Font.system(size: 18)) 56 | .frame(maxWidth: .infinity, minHeight: 48.0) 57 | } 58 | } 59 | 60 | struct SwiftUIView_Previews: PreviewProvider { 61 | @State static var email: String = "" 62 | static var previews: some View { 63 | VStack { 64 | TextField("Email", text: $email) 65 | .inputButtonAppearance() 66 | .textContentType(.emailAddress) 67 | .keyboardType(.emailAddress) 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Texts.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/21. 6 | // 7 | // 8 | 9 | import SwiftUI 10 | 11 | public extension Text { 12 | struct OME { 13 | public static let slogon = { Text("Bring intranet on the internet") 14 | .font(Font.OME.subTitle) 15 | .foregroundColor(Color.OME.gray) 16 | }() 17 | } 18 | } 19 | 20 | struct Texts_Previews: PreviewProvider { 21 | static var previews: some View { 22 | Text.OME.slogon.padding() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Sources/OEUIKit/Views.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftUIView.swift 3 | // 4 | // 5 | // Created by samuelsong(samuel.song.bc@gmail.com) on 2021/8/30. 6 | // 7 | // 8 | 9 | import SwiftUI 10 | 11 | public extension View { 12 | func asAnyView() -> AnyView { 13 | return AnyView(self) 14 | } 15 | } 16 | 17 | public struct AlertView: View { 18 | private let message: String 19 | public init(_ message: String) { 20 | self.message = message 21 | } 22 | public var body: some View { 23 | HStack { 24 | Spacer() 25 | HStack(alignment: .top, spacing: 10) { 26 | Image(systemName: "x.circle") 27 | .imageColorAppearance(color: Color.OME.error) 28 | Text(message) 29 | .font(.system(size: 15)) 30 | .fixedSize(horizontal: false, vertical: true) 31 | } 32 | .padding(.vertical, 10) 33 | Spacer() 34 | } 35 | .background(Color.OME.error.opacity(0.1)) 36 | .border(Color.OME.error, width: 1) 37 | } 38 | } 39 | 40 | public extension View { 41 | func configureBackground() { 42 | let barApperance = UINavigationBarAppearance() 43 | barApperance.backgroundColor = UIColor(Color.OME.background) 44 | UINavigationBar.appearance().standardAppearance = barApperance 45 | UINavigationBar.appearance().scrollEdgeAppearance = barApperance 46 | } 47 | } 48 | 49 | public extension Spacer { 50 | /// https://stackoverflow.com/a/57416760/3393964 51 | func forceTapGesture(count: Int = 1, perform action: @escaping () -> Void) -> some View { 52 | ZStack { 53 | Color.black.opacity(0.001).onTapGesture(count: count, perform: action) 54 | self 55 | } 56 | } 57 | } 58 | 59 | struct Views_Previews: PreviewProvider { 60 | static var previews: some View { 61 | VStack { 62 | AlertView("The email address and password combination you entered is invalid. Please try again.") 63 | AlertView("error") 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Packages/OEUIKit/Tests/OEUIKitTests/OEUIKitTests.swift: -------------------------------------------------------------------------------- 1 | @testable import OEUIKit 2 | import XCTest 3 | 4 | final class OEUIKitTests: XCTestCase { 5 | func testExample() { 6 | // This is an example of a functional test case. 7 | // Use XCTAssert and related functions to verify your tests produce the correct 8 | // results. 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Packages/Tattoo/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | -------------------------------------------------------------------------------- /Packages/Tattoo/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Packages/Tattoo/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Tattoo", 8 | platforms: [ 9 | .iOS(.v13) 10 | ], 11 | products: [ 12 | // Products define the executables and libraries a package produces, and make them visible to other packages. 13 | .library( 14 | name: "Tattoo", 15 | targets: ["Tattoo"]) 16 | ], 17 | dependencies: [ 18 | // Dependencies declare other packages that this package depends on. 19 | // .package(url: /* package url */, from: "1.0.0"), 20 | ], 21 | targets: [ 22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 23 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 24 | .target( 25 | name: "Tattoo", 26 | dependencies: []), 27 | .testTarget( 28 | name: "TattooTests", 29 | dependencies: ["Tattoo"]) 30 | ] 31 | ) 32 | -------------------------------------------------------------------------------- /Packages/Tattoo/Sources/Tattoo/APIModule.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public typealias APIModule = (APICenter) -> Void 5 | 6 | public class ModuleSalt{ 7 | } 8 | 9 | public func startTattoo(_ scope: APICenter = mainCenter, modules: APIModule...) { 10 | modules.forEach { (module) in 11 | module(scope) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Packages/Tattoo/Sources/Tattoo/APIQualifier.swift: -------------------------------------------------------------------------------- 1 | 2 | public typealias QualifierValue = String 3 | 4 | public protocol APIQualifier { 5 | var value: QualifierValue { get } 6 | } 7 | 8 | public class StringQualifier: APIQualifier { 9 | 10 | public let value: QualifierValue 11 | 12 | public init(qualifier: String) { 13 | self.value = qualifier 14 | } 15 | } 16 | 17 | public class QulifierSalt{ 18 | } 19 | 20 | public class TypeQualifier: APIQualifier { 21 | 22 | public let value: QualifierValue 23 | 24 | public init(type: T.Type) { 25 | self.value = "\(type)" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Packages/Tattoo/Tests/TattooTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !canImport(ObjectiveC) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | // testCase(TattooTests.allTests), 7 | ] 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OmniEdge-iOS 2 | 3 | >Bring the intranet on the internet 4 | 5 | [Install from App Store](https://apps.apple.com/us/app/omniedgenew/id1603005893) 6 | 7 | image 8 | 9 | 10 | [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0) 11 | 12 | [🤝 Website](https://omniedge.io) 13 | [💬 Twitter](https://twitter.com/omniedgeio) 14 | [😇 Discord](https://discord.gg/d4faRPYj) 15 | 16 | Main repo: [https://github.com/omniedgeio/omniedge](https://github.com/omniedgeio/omniedge) 17 | 18 | A cross-platform private network tool for developers. 19 | 20 | ![iPhone 11 Pro](https://user-images.githubusercontent.com/93888/171176670-44ee5db1-f61f-4caa-9227-9b2dd26417e2.png) 21 | 22 | 23 | ## How to get started? 24 | 25 | 1. If you only need a convenient connectivity service 26 | Just visit https://omniedge.io/download and download the apps for your platform. 27 | 28 | 2. If you are an experienced programmer 29 | You can prepare your own supernode and build the client to reach your own target accroding to the following `Compiler and debugger` Section. 30 | 31 | ## Compiler and debugger 32 | 33 | Open `OmniEdgeNew/OmniEdgeNew.xcworkspace` and compile by yourself. 34 | Latest version of Xcode 35 | 36 | - [Architecture](/docs/Architecture.md) 37 | - [Network](/docs/Network.md) 38 | 39 | We recommend compiling the package on your devices separately, specially the **Tunnel** package. 40 | 41 | image 42 | 43 | ## Contributing Guildlines 44 | 45 | Check the tempalte into .github folder to report an issue or submit a PR: 46 | 1. ISSUE_TEMPLATE.md 47 | 2. PULL_REQUEST_TEMPLATE.md 48 | 49 | ## Contributors 50 | 51 | @zteshadow 52 | 53 | ## About US 54 | [OmniEdge](https://omniedge.io) is primiary developed by the people at [https://github.com/orgs/omniedgeio/people](https://github.com/orgs/omniedgeio/people). 55 | -------------------------------------------------------------------------------- /Tunnel-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import "edge_ios_oc.h" 6 | -------------------------------------------------------------------------------- /Tunnel/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Tunnel 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSExtension 24 | 25 | NSExtensionPointIdentifier 26 | com.apple.networkextension.packet-tunnel 27 | NSExtensionPrincipalClass 28 | $(PRODUCT_MODULE_NAME).PacketTunnelProvider 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Tunnel/Tunnel.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.networking.networkextension 6 | 7 | packet-tunnel-provider 8 | 9 | com.apple.developer.networking.vpn.api 10 | 11 | allow-vpn 12 | 13 | com.apple.security.application-groups 14 | 15 | group.com.jieqi.omniedge 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/Architecture.md: -------------------------------------------------------------------------------- 1 | # OmniEdge iOS Application 2 | 3 | ## Environment Setup 4 | 5 | - You can setup the shared githooks like so: 6 | `git config core.hooksPath .githooks` 7 | 8 | - You can use some of our custom Xcode template like so: 9 | `./scripts/setup_templates.sh` 10 | 11 | - You can setup our common dev tools like so: 12 | `./scripts/setup_swiftlint.sh` 13 | 14 | ### Swiftlint 15 | 16 | This project uses [Swiftlint](https://github.com/realm/SwiftLint) to enforce coding style. 17 | 18 | #### Installation 19 | 20 | You will need to have Swiftlint installed on your development machine which can be done by running the script or following the [Swiftlint installation](https://github.com/realm/SwiftLint#installation) instructions. 21 | `./scripts/setup_swiftlint.sh` 22 | 23 | ### Dependency Management 24 | 25 | Our project uses mainly Swift Package Manager. 26 | If a dependency doesn't have SPM - we can consider adding it via Carthage. 27 | 28 | #### Setup 29 | 30 | 1. Make sure an SSH key is setup for github.com/stubhub. Support can be found here: 31 | 32 | https://help.github.com/en/enterprise/2.15/user/articles/adding-a-new-ssh-key-to-your-github-account 33 | 2. `cd` to the root of your local ios repo, if you're not there already: 34 | 35 | `cd ` 36 | 37 | 38 | ### Prepare local machine 39 | 40 | TBD 41 | 42 | ## Developer menu 43 | 44 | TBD 45 | 46 | -------------------------------------------------------------------------------- /resource/androidmodule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/resource/androidmodule.png -------------------------------------------------------------------------------- /resource/androidrunloop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/resource/androidrunloop.png -------------------------------------------------------------------------------- /resource/end2site.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/resource/end2site.png -------------------------------------------------------------------------------- /resource/iosrunloop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/resource/iosrunloop.png -------------------------------------------------------------------------------- /resource/iosstartup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/resource/iosstartup.png -------------------------------------------------------------------------------- /resource/p2pvpn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/resource/p2pvpn.png -------------------------------------------------------------------------------- /resource/site2site.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/resource/site2site.png -------------------------------------------------------------------------------- /resource/tap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/resource/tap.png -------------------------------------------------------------------------------- /resource/tun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/resource/tun.png -------------------------------------------------------------------------------- /resource/tuntap1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omniedgeio/omniedge-iOS/cd6414f6dacdfc0a20fb233e6823fe653ea326bd/resource/tuntap1.png -------------------------------------------------------------------------------- /scripts/clean_projects.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | set -euo pipefail 4 | 5 | projects=(`find . -name project.pbxproj`) 6 | 7 | for project in $projects 8 | do 9 | python ./scripts/xUnique.py -sp $project > /dev/null 10 | done 11 | -------------------------------------------------------------------------------- /scripts/configure_workspace.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | require 'xcodeproj' 3 | require 'json' 4 | 5 | project_name = ARGV[0] 6 | api_file = "#{project_name}API.swift" 7 | module_path = "Libraries/#{project_name}/#{project_name}.xcodeproj" 8 | platform_path = 'Libraries/OEPlatform/OEPlatform.xcodeproj' 9 | app_path = 'OmniedgeNew/OmniedgeNew.xcodeproj' 10 | 11 | platform = Xcodeproj::Project.open(platform_path) 12 | 13 | mainPlatform = platform.native_targets.find { |target| target.name == 'OEPlatform' } 14 | # Add the API file to the platform project: 15 | fileRef = platform['OEPlatform/ModulesAPI'].new_file(api_file) 16 | mainPlatform.add_file_references([fileRef]) 17 | 18 | platform.save() 19 | 20 | # Add the module project file to the OmniedgeNew app 21 | app = Xcodeproj::Project.open(app_path) 22 | app['Libraries'].new_file(module_path).set_path("../#{module_path}") 23 | 24 | # TODO - could add the project as a dependency as well 25 | 26 | app.save() 27 | 28 | # Add the test target to the test plan: 29 | 30 | new_module = Xcodeproj::Project.open(module_path) 31 | 32 | module_tests = new_module.native_targets.find { |target| target.name == "#{project_name}Tests" } 33 | 34 | new_test = { 35 | target: { 36 | containerPath: "container:../#{module_path}", 37 | identifier: module_tests.uuid, 38 | name: "#{project_name}Tests" 39 | } 40 | } 41 | 42 | tests_path = 'OmniedgeNew/AllTests.xctestplan' 43 | 44 | test_plan = JSON.parse(File.read(tests_path)) 45 | test_plan["testTargets"] << new_test 46 | 47 | options = { 48 | :space_before => ' ', 49 | :escape_slash => true 50 | } 51 | File.write(tests_path, JSON.pretty_generate(test_plan, options)) 52 | -------------------------------------------------------------------------------- /scripts/git-add-matches.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export FILE_NAME=$1 4 | export PATTERN=$2 5 | 6 | # Credit: https://stackoverflow.com/a/37339566 7 | 8 | diff=`mktemp` 9 | git diff $FILE_NAME > $diff 10 | [ -s $diff ] || exit 11 | 12 | patch=`mktemp` 13 | 14 | gawk -v pat="$PATTERN" ' 15 | function hh(){ 16 | if(keep && n > 0){ 17 | for(i=0;i hr){ 50 | if(/^\-/ && $0 !~ pat){ 51 | har[4]++; 52 | sub(/^\-/, " ", $0); 53 | out[n++] = $0 54 | } 55 | else if(/^\+/ && $0 !~ pat){ 56 | har[4]--; 57 | } 58 | else{ 59 | if(/^[+-]/){ 60 | keep=1 61 | } 62 | out[n++] = $0 63 | } 64 | } 65 | } 66 | END{ 67 | hh() 68 | }' $diff > $patch 69 | 70 | git restore -- $FILE_NAME 71 | git apply --recount $patch 72 | git add $FILE_NAME 73 | 74 | rm $diff 75 | rm $patch 76 | -------------------------------------------------------------------------------- /scripts/setup_devtools.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd scripts 4 | ./setup_swiftlint.sh 5 | ./setup_xcodegen.sh 6 | 7 | echo "Installing gems. Your password might be required" 8 | 9 | sudo gem install xcodeproj json 10 | -------------------------------------------------------------------------------- /scripts/setup_module.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ] ; then 4 | echo "Please provide the new module name" 5 | exit 1 6 | fi 7 | 8 | echo "Setting up module $1" 9 | 10 | killall -3 Xcode 11 | 12 | export PROJECT_NAME=$1 13 | export PROJECT_DIR=Libraries/$1 14 | export LC_CTYPE=C 15 | export LANG=C 16 | 17 | # Clean anything in the new module folder 18 | # Then setup the new folder structure 19 | rm -Rf $PROJECT_DIR 20 | cp -r templates/module-starter Libraries 21 | mv Libraries/module-starter $PROJECT_DIR 22 | 23 | cd $PROJECT_DIR 24 | 25 | # Rename templates to new name: 26 | 27 | mv ___FILEBASENAME___ ${PROJECT_NAME} 28 | mv ___FILEBASENAME___Tests ${PROJECT_NAME}Tests 29 | mv ___FILEBASENAME___Demo ${PROJECT_NAME}Demo 30 | 31 | find . -name "*___FILEBASENAME___*" | sed -e "p;s/___FILEBASENAME___/$PROJECT_NAME/" | xargs -n2 mv 32 | 33 | # Rename {{ project_name }} in templates to $PROJECT_NAME 34 | 35 | find ./ -type f -exec sed -i "" -e "s/{{ project_name }}/$PROJECT_NAME/g" {} \; 36 | 37 | # Generate the project 38 | xcodegen --spec module.yml 39 | 40 | # Cleanup project scaffold 41 | rm -f module.yml 42 | 43 | cd ../../ 44 | 45 | export API_FILE=Libraries/OEPlatform/OEPlatform/ModulesAPI/${PROJECT_NAME}API.swift 46 | export SH_PLATFORM=Libraries/OEPlatform/OEPlatform.xcodeproj 47 | export APP_PROJECT=OmniedgeNew/OmniedgeNew.xcodeproj 48 | #export TEST_PLAN=OmniedgeNew/AllTests.xctestplan 49 | 50 | # Copy the new module API to the new place: 51 | 52 | cp templates/platform-injection/___FILEBASENAME___API.swift $API_FILE 53 | 54 | # Replace the template with the new project name 55 | 56 | sed -i "" -e "s/{{ project_name }}/$PROJECT_NAME/g" $API_FILE 57 | 58 | # Configure the workspace (add the API file and the new project to the main app) 59 | ./scripts/configure_workspace.rb $1 60 | 61 | # Cleanup the projects 62 | ./scripts/clean_projects.sh 63 | 64 | # Commit to git 65 | 66 | git add $PROJECT_DIR $API_FILE $APP_PROJECT $TEST_PLAN 67 | ./scripts/git-add-matches.sh $SH_PLATFORM $1 68 | git commit -m "Auto generated module $1" $API_FILE $SH_PLATFORM $PROJECT_DIR $APP_PROJECT $TEST_PLAN 69 | 70 | echo "Setup complete - have fun!" 71 | -------------------------------------------------------------------------------- /scripts/setup_swiftlint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | REQUIRED_LINT_VERSION=0.41.0 4 | 5 | SWIFT_LINT=$(which swiftlint) 6 | 7 | SWIFT_LINT_VERSION=$("$SWIFT_LINT" version) 8 | 9 | if [ "$SWIFT_LINT_VERSION" = "$REQUIRED_LINT_VERSION" ]; then 10 | echo "Already have required version. Congrats! Now run swiftlint to lint your files." 11 | exit 0 12 | fi 13 | 14 | mint install realm/SwiftLint@0.41.0 15 | -------------------------------------------------------------------------------- /scripts/setup_templates.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mkdir -p ~/Library/Developer/Xcode/Templates/Custom\ Templates 4 | 5 | cp -R templates ~/Library/Developer/Xcode/Templates/Custom\ Templates 6 | -------------------------------------------------------------------------------- /scripts/setup_xcodegen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | REQUIRED_XCODE_GEN_VERSION="Version: 2.23.1" 4 | 5 | XCODE_GEN=$(which xcodegen) 6 | 7 | XCODE_GEN_VERSION=$("$XCODE_GEN" version) 8 | 9 | if [ "$XCODE_GEN_VERSION" = "$REQUIRED_XCODE_GEN_VERSION" ]; then 10 | echo "Already have required version. Congrats!" 11 | exit 0 12 | fi 13 | 14 | mint install yonaskolb/xcodegen@2.23.1 15 | -------------------------------------------------------------------------------- /scripts/swiftlint: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | echo "Linting..." 3 | swiftlint --strict --quiet 4 | -------------------------------------------------------------------------------- /scripts/verify_projects.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | set -euo pipefail 4 | 5 | projects=(`find . -name project.pbxproj`) 6 | 7 | for project in $projects 8 | do 9 | python ./scripts/xUnique.py -spc $project > /dev/null 10 | done 11 | -------------------------------------------------------------------------------- /templates/MvvMC.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Kind 6 | Xcode.IDEKit.TextSubstitutionFileTemplateKind 7 | Platforms 8 | 9 | com.apple.platform.iphoneos 10 | 11 | Options 12 | 13 | 14 | AllowedTypes 15 | 16 | public.swift-source 17 | 18 | Identifier 19 | productName 20 | Required 21 | 22 | Name 23 | Feature Name 24 | Description 25 | The name of the Mvvm + C to create 26 | Type 27 | text 28 | Default 29 | Feature1 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /templates/MvvMC.xctemplate/___FILEBASENAME___/Coordinators/___FILEBASENAME___Coordinator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILEBASENAMEASIDENTIFIER___.swift 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___ 6 | // ___COPYRIGHT___ 7 | // 8 | 9 | import Foundation 10 | import SHPlatform 11 | import Tattoo 12 | 13 | class ___FILEBASENAMEASIDENTIFIER___: Coordinator { 14 | 15 | private let viewModel: ___VARIABLE_productName:identifier___ViewModel 16 | private let router: RoutingAPI 17 | private let scope: Scope 18 | 19 | init(router: RoutingAPI, scope: Scope) { 20 | self.router = router 21 | self.scope = scope 22 | self.viewModel = ___VARIABLE_productName:identifier___ViewModel() 23 | } 24 | 25 | // TODO - put your coordinator logic here 26 | } 27 | -------------------------------------------------------------------------------- /templates/MvvMC.xctemplate/___FILEBASENAME___/DataStores/___FILEBASENAME___DataStore.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILEBASENAMEASIDENTIFIER___.swift 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___ 6 | // ___COPYRIGHT___ 7 | // 8 | 9 | import Combine 10 | 11 | // Delete this if you don't need a data-store in your use case. 12 | protocol ___FILEBASENAMEASIDENTIFIER___ { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /templates/MvvMC.xctemplate/___FILEBASENAME___/Models/___FILEBASENAME___Model.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILEBASENAMEASIDENTIFIER___.swift 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___ 6 | // ___COPYRIGHT___ 7 | // 8 | 9 | import Foundation 10 | 11 | // Delete if you don't need it 12 | struct ___FILEBASENAMEASIDENTIFIER___: Codable, Hashable { 13 | // TODO - put your data model here 14 | } 15 | -------------------------------------------------------------------------------- /templates/MvvMC.xctemplate/___FILEBASENAME___/ViewModels/___FILEBASENAME___ViewModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILEBASENAMEASIDENTIFIER___.swift 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___ 6 | // ___COPYRIGHT___ 7 | // 8 | 9 | import Combine 10 | import Foundation 11 | import SHPlatform 12 | 13 | class ___FILEBASENAMEASIDENTIFIER___: ObservableObject { 14 | // TODO - put your view model logic here 15 | } 16 | -------------------------------------------------------------------------------- /templates/MvvMC.xctemplate/___FILEBASENAME___/Views/___FILEBASENAME___View.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILEBASENAMEASIDENTIFIER___.swift 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___ 6 | // ___COPYRIGHT___ 7 | // 8 | 9 | import SHUIKit 10 | import SwiftUI 11 | 12 | struct ___FILEBASENAMEASIDENTIFIER___: View { 13 | @EnvironmentObject var viewModel: ___FILEBASENAMEASIDENTIFIER___Model 14 | 15 | var body: some View { 16 | // TODO - put your view here 17 | EmptyView() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /templates/module-starter/___FILEBASENAME___/___FILEBASENAME___.h: -------------------------------------------------------------------------------- 1 | // 2 | // {{ project_name }}.h 3 | // {{ project_name }} 4 | // 5 | // 6 | 7 | #import 8 | 9 | //! Project version number for {{ project_name }}. 10 | FOUNDATION_EXPORT double {{ project_name }}VersionNumber; 11 | 12 | //! Project version string for {{ project_name }}. 13 | FOUNDATION_EXPORT const unsigned char {{ project_name }}VersionString[]; 14 | -------------------------------------------------------------------------------- /templates/module-starter/___FILEBASENAME___/___FILEBASENAME___.swift: -------------------------------------------------------------------------------- 1 | // 2 | // {{ project_name }}.swift 3 | // {{ project_name }} 4 | // 5 | // 6 | 7 | import Foundation 8 | import OEPlatform 9 | 10 | /// Document your module purpose 11 | public class {{ project_name }}: {{ project_name }}API { 12 | 13 | public init() { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /templates/module-starter/___FILEBASENAME___Demo/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /templates/module-starter/___FILEBASENAME___Demo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /templates/module-starter/___FILEBASENAME___Demo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /templates/module-starter/___FILEBASENAME___Demo/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // {{ project_name }}Demo 4 | // 5 | // 6 | 7 | import SwiftUI 8 | 9 | struct ContentView: View { 10 | var body: some View { 11 | Text("Hello, world!") 12 | .padding() 13 | } 14 | } 15 | 16 | struct ContentView_Previews: PreviewProvider { 17 | static var previews: some View { 18 | ContentView() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /templates/module-starter/___FILEBASENAME___Demo/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /templates/module-starter/___FILEBASENAME___Demo/___FILEBASENAME___DemoApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // {{ project_name }}DemoApp.swift 3 | // {{ project_name }}Demo 4 | // 5 | // 6 | 7 | import SwiftUI 8 | 9 | @main 10 | struct {{ project_name }}DemoApp: App { 11 | var body: some Scene { 12 | WindowGroup { 13 | ContentView() 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /templates/module-starter/___FILEBASENAME___Tests/___FILEBASENAME___Tests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // {{ project_name }}Tests.swift 3 | // {{ project_name }}Tests 4 | // 5 | // 6 | 7 | @testable import {{ project_name }} 8 | import XCTest 9 | 10 | class {{ project_name }}Tests: XCTestCase { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /templates/platform-injection/___FILEBASENAME___API.swift: -------------------------------------------------------------------------------- 1 | // 2 | // {{ project_name }}API.swift 3 | // OEPlatform 4 | // 5 | // 6 | 7 | import Foundation 8 | 9 | /// The {{ project_name }} public APIs to be used by other modules 10 | public protocol {{ project_name }}API { 11 | // TODO - add the public APIs here 12 | } 13 | --------------------------------------------------------------------------------