From a32f25f090a43db7f5844fb35ddc668aec0be946 Mon Sep 17 00:00:00 2001 From: Elad Dekel <74513560+eladdekel@users.noreply.github.com> Date: Wed, 15 May 2024 21:37:43 -0400 Subject: [PATCH 1/3] implementation of native iOS app --- software/source/clients/ios/README.md | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 software/source/clients/ios/README.md diff --git a/software/source/clients/ios/README.md b/software/source/clients/ios/README.md new file mode 100644 index 0000000..2eaeac1 --- /dev/null +++ b/software/source/clients/ios/README.md @@ -0,0 +1,29 @@ +# iOS/iPadOS Native Client + +This repository contains the source code for the 01 iOS/iPadOS Native app. It is a work in progress and currently has a dedicated development button. + +Feel free to improve this and make a pull request! + +To run it on your own, you can either install the app directly through the current TestFlight [here](https://testflight.apple.com/join/v8SyuzMT), or build from the source code files in Xcode on your Mac. + +## Instructions + +Follow the **[software setup steps](https://github.com/OpenInterpreter/01?tab=readme-ov-file#software)** in the main repo's README first before you read this + +In Xcode, open the 'zerooone-app' project file in the project folder, change the Signing Team and Bundle Identifier, and build. + +## Using the App + +To use the app there are four features: + +### 1. The speak "Button" +Made to emulate the button on the hardware models of 01, the big, yellow circle in the middle of the screen is what you hold when you want to speak to the model, and let go when you're finished speaking. + +### 2. The settings button +Tapping the settings button will allow you to input your websocket address so that the app can properly connect to your computer. If you're not sure how to obtain this, read the **'How to Install'** section below! + +### 3. The reconnect button +The arrow will be RED when the websocket connection is not live, and GREEN when it is. If you're making some changes you can easily reconnect by simply tapping the arrow button (or you can just start holding the speak button, too!). + +### 4. The terminal button +The terminal button allows you to see all response text coming in from the server side of the 01. You can toggle it by tapping on the button, and each toggle clears the on-device cache of text. From 92788d9f16c113ba8067699715b83844dabe7ddc Mon Sep 17 00:00:00 2001 From: Elad Dekel <74513560+eladdekel@users.noreply.github.com> Date: Wed, 15 May 2024 21:40:49 -0400 Subject: [PATCH 2/3] implementation of native iOS app --- .../zeroone-app.xcodeproj/project.pbxproj | 415 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 5 + .../UserInterfaceState.xcuserstate | Bin 0 -> 69795 bytes .../WorkspaceSettings.xcsettings | 14 + .../xcdebugger/Breakpoints_v2.xcbkptlist | 6 + .../xcschemes/xcschememanagement.plist | 14 + .../zeroone-app/zeroone-app/AppDelegate.swift | 36 ++ .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 14 + .../Assets.xcassets/AppIcon.appiconset/O.png | Bin 0 -> 39280 bytes .../zeroone-app/Assets.xcassets/Contents.json | 6 + .../vector.imageset/Contents.json | 12 + .../vector.imageset/vector.svg | 5 + .../zeroone-app/AudioRecording.swift | 67 +++ .../Base.lproj/LaunchScreen.storyboard | 25 ++ .../zeroone-app/Base.lproj/Main.storyboard | 127 ++++++ .../ios/zeroone-app/zeroone-app/Info.plist | 27 ++ .../zeroone-app/SceneDelegate.swift | 52 +++ .../zeroone-app/ViewController.swift | 366 +++++++++++++++ 21 files changed, 1217 insertions(+) create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.pbxproj create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/xcuserdata/eladdekel.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/xcuserdata/eladdekel.xcuserdatad/WorkspaceSettings.xcsettings create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app/AppDelegate.swift create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/AppIcon.appiconset/O.png create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/Contents.json create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/vector.imageset/Contents.json create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/vector.imageset/vector.svg create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app/AudioRecording.swift create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app/Base.lproj/LaunchScreen.storyboard create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app/Base.lproj/Main.storyboard create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app/Info.plist create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app/SceneDelegate.swift create mode 100644 software/source/clients/ios/zeroone-app/zeroone-app/ViewController.swift diff --git a/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.pbxproj b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.pbxproj new file mode 100644 index 0000000..37a8592 --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.pbxproj @@ -0,0 +1,415 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 750E4C0B2BEDD11C00AEE3B1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 750E4C0A2BEDD11C00AEE3B1 /* AppDelegate.swift */; }; + 750E4C0D2BEDD11C00AEE3B1 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 750E4C0C2BEDD11C00AEE3B1 /* SceneDelegate.swift */; }; + 750E4C0F2BEDD11C00AEE3B1 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 750E4C0E2BEDD11C00AEE3B1 /* ViewController.swift */; }; + 750E4C122BEDD11C00AEE3B1 /* Base in Resources */ = {isa = PBXBuildFile; fileRef = 750E4C112BEDD11C00AEE3B1 /* Base */; }; + 750E4C142BEDD11D00AEE3B1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 750E4C132BEDD11D00AEE3B1 /* Assets.xcassets */; }; + 750E4C172BEDD11D00AEE3B1 /* Base in Resources */ = {isa = PBXBuildFile; fileRef = 750E4C162BEDD11D00AEE3B1 /* Base */; }; + 750E4C202BEDD16E00AEE3B1 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = 750E4C1F2BEDD16E00AEE3B1 /* Starscream */; }; + 755DC3B22BEE60A7002B66DF /* AudioRecording.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755DC3B12BEE60A7002B66DF /* AudioRecording.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 750E4C072BEDD11C00AEE3B1 /* zeroone-app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "zeroone-app.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 750E4C0A2BEDD11C00AEE3B1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 750E4C0C2BEDD11C00AEE3B1 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 750E4C0E2BEDD11C00AEE3B1 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 750E4C112BEDD11C00AEE3B1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 750E4C132BEDD11D00AEE3B1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 750E4C162BEDD11D00AEE3B1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 750E4C182BEDD11D00AEE3B1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 755DC3B12BEE60A7002B66DF /* AudioRecording.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRecording.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 750E4C042BEDD11C00AEE3B1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 750E4C202BEDD16E00AEE3B1 /* Starscream in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 750E4BFE2BEDD11C00AEE3B1 = { + isa = PBXGroup; + children = ( + 750E4C092BEDD11C00AEE3B1 /* zeroone-app */, + 750E4C082BEDD11C00AEE3B1 /* Products */, + ); + sourceTree = ""; + }; + 750E4C082BEDD11C00AEE3B1 /* Products */ = { + isa = PBXGroup; + children = ( + 750E4C072BEDD11C00AEE3B1 /* zeroone-app.app */, + ); + name = Products; + sourceTree = ""; + }; + 750E4C092BEDD11C00AEE3B1 /* zeroone-app */ = { + isa = PBXGroup; + children = ( + 750E4C0A2BEDD11C00AEE3B1 /* AppDelegate.swift */, + 750E4C0C2BEDD11C00AEE3B1 /* SceneDelegate.swift */, + 750E4C0E2BEDD11C00AEE3B1 /* ViewController.swift */, + 750E4C102BEDD11C00AEE3B1 /* Main.storyboard */, + 750E4C132BEDD11D00AEE3B1 /* Assets.xcassets */, + 750E4C152BEDD11D00AEE3B1 /* LaunchScreen.storyboard */, + 750E4C182BEDD11D00AEE3B1 /* Info.plist */, + 755DC3B12BEE60A7002B66DF /* AudioRecording.swift */, + ); + path = "zeroone-app"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 750E4C062BEDD11C00AEE3B1 /* zeroone-app */ = { + isa = PBXNativeTarget; + buildConfigurationList = 750E4C1B2BEDD11D00AEE3B1 /* Build configuration list for PBXNativeTarget "zeroone-app" */; + buildPhases = ( + 750E4C032BEDD11C00AEE3B1 /* Sources */, + 750E4C042BEDD11C00AEE3B1 /* Frameworks */, + 750E4C052BEDD11C00AEE3B1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "zeroone-app"; + packageProductDependencies = ( + 750E4C1F2BEDD16E00AEE3B1 /* Starscream */, + ); + productName = "zeroone-app"; + productReference = 750E4C072BEDD11C00AEE3B1 /* zeroone-app.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 750E4BFF2BEDD11C00AEE3B1 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1530; + LastUpgradeCheck = 1530; + TargetAttributes = { + 750E4C062BEDD11C00AEE3B1 = { + CreatedOnToolsVersion = 15.3; + }; + }; + }; + buildConfigurationList = 750E4C022BEDD11C00AEE3B1 /* Build configuration list for PBXProject "zeroone-app" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 750E4BFE2BEDD11C00AEE3B1; + packageReferences = ( + 750E4C1E2BEDD16D00AEE3B1 /* XCRemoteSwiftPackageReference "Starscream" */, + ); + productRefGroup = 750E4C082BEDD11C00AEE3B1 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 750E4C062BEDD11C00AEE3B1 /* zeroone-app */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 750E4C052BEDD11C00AEE3B1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 750E4C142BEDD11D00AEE3B1 /* Assets.xcassets in Resources */, + 750E4C172BEDD11D00AEE3B1 /* Base in Resources */, + 750E4C122BEDD11C00AEE3B1 /* Base in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 750E4C032BEDD11C00AEE3B1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 750E4C0F2BEDD11C00AEE3B1 /* ViewController.swift in Sources */, + 750E4C0B2BEDD11C00AEE3B1 /* AppDelegate.swift in Sources */, + 755DC3B22BEE60A7002B66DF /* AudioRecording.swift in Sources */, + 750E4C0D2BEDD11C00AEE3B1 /* SceneDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 750E4C102BEDD11C00AEE3B1 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 750E4C112BEDD11C00AEE3B1 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 750E4C152BEDD11D00AEE3B1 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 750E4C162BEDD11D00AEE3B1 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 750E4C192BEDD11D00AEE3B1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 750E4C1A2BEDD11D00AEE3B1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 750E4C1C2BEDD11D00AEE3B1 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 4; + DEVELOPMENT_TEAM = W5NGQJV8X2; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "zeroone-app/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = 01ForiOS; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; + INFOPLIST_KEY_NSMicrophoneUsageDescription = "Audio data from microphone is needed to send commands."; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + IPHONEOS_DEPLOYMENT_TARGET = 15; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.ontheroofstudios.zeroone-app"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 750E4C1D2BEDD11D00AEE3B1 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 4; + DEVELOPMENT_TEAM = W5NGQJV8X2; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "zeroone-app/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = 01ForiOS; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; + INFOPLIST_KEY_NSMicrophoneUsageDescription = "Audio data from microphone is needed to send commands."; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + IPHONEOS_DEPLOYMENT_TARGET = 15; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.ontheroofstudios.zeroone-app"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 750E4C022BEDD11C00AEE3B1 /* Build configuration list for PBXProject "zeroone-app" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 750E4C192BEDD11D00AEE3B1 /* Debug */, + 750E4C1A2BEDD11D00AEE3B1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 750E4C1B2BEDD11D00AEE3B1 /* Build configuration list for PBXNativeTarget "zeroone-app" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 750E4C1C2BEDD11D00AEE3B1 /* Debug */, + 750E4C1D2BEDD11D00AEE3B1 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 750E4C1E2BEDD16D00AEE3B1 /* XCRemoteSwiftPackageReference "Starscream" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/daltoniam/Starscream"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 4.0.8; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 750E4C1F2BEDD16E00AEE3B1 /* Starscream */ = { + isa = XCSwiftPackageProductDependency; + package = 750E4C1E2BEDD16D00AEE3B1 /* XCRemoteSwiftPackageReference "Starscream" */; + productName = Starscream; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 750E4BFF2BEDD11C00AEE3B1 /* Project object */; +} diff --git a/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/xcuserdata/eladdekel.xcuserdatad/UserInterfaceState.xcuserstate b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/project.xcworkspace/xcuserdata/eladdekel.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..9ad695539a16147d233dc8faf5be5324cff543a9 GIT binary patch literal 69795 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 yI<-2xI=^~ + + + + BuildLocationStyle + UseAppPreferences + CustomBuildLocationType + RelativeToDerivedData + DerivedDataLocationStyle + Default + ShowSharedSchemesAutomaticallyEnabled + + + diff --git a/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..a1ddc74 --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcschemes/xcschememanagement.plist b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..31bfb5f --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + zeroone-app.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/software/source/clients/ios/zeroone-app/zeroone-app/AppDelegate.swift b/software/source/clients/ios/zeroone-app/zeroone-app/AppDelegate.swift new file mode 100644 index 0000000..de09029 --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app/AppDelegate.swift @@ -0,0 +1,36 @@ +// +// AppDelegate.swift +// zeroone-app +// +// Created by Elad Dekel on 2024-05-09. +// + +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/AccentColor.colorset/Contents.json b/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/AppIcon.appiconset/Contents.json b/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..4e17533 --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "O.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/AppIcon.appiconset/O.png b/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/AppIcon.appiconset/O.png new file mode 100644 index 0000000000000000000000000000000000000000..0e7193ded6a1a14d51fb646fd8f9e584a5ffbf69 GIT binary patch literal 39280 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%0D5cKqEse^Q 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 literal 0 HcmV?d00001 diff --git a/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/Contents.json b/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/vector.imageset/Contents.json b/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/vector.imageset/Contents.json new file mode 100644 index 0000000..4311484 --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/vector.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "vector.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/vector.imageset/vector.svg b/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/vector.imageset/vector.svg new file mode 100644 index 0000000..49c449b --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app/Assets.xcassets/vector.imageset/vector.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/software/source/clients/ios/zeroone-app/zeroone-app/AudioRecording.swift b/software/source/clients/ios/zeroone-app/zeroone-app/AudioRecording.swift new file mode 100644 index 0000000..46cde0e --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app/AudioRecording.swift @@ -0,0 +1,67 @@ +// +// AudioRecording.swift +// zeroone-app +// +// Created by Elad Dekel on 2024-05-10. +// + +import Foundation +import AVFoundation + +class AudioRecording: NSObject, AVAudioRecorderDelegate { + + var recorder: AVAudioRecorder! + var session: AVAudioSession! + + var isRecording = false + + func startRecording() { + session = AVAudioSession() + let audio = getDocumentsDirectory().appendingPathComponent("tempvoice.wav") // indicates where the audio data will be recording to + let s: [String: Any] = [ + AVFormatIDKey: kAudioFormatLinearPCM, + AVSampleRateKey: 16000.0, + AVNumberOfChannelsKey: 1, + AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue + ] + do { + recorder = try AVAudioRecorder(url: audio, settings: s) + try session.setActive(true) + try session.setCategory(.playAndRecord, mode: .default) + recorder!.delegate = self + recorder!.record() + isRecording = true + + } catch { + print("Error recording") + print(error.localizedDescription) + } + + } + + func getDocumentsDirectory() -> URL { // big thanks to twostraws for this helper function (hackingwithswift.com) + let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) + return paths[0] + } + + + func stopRecording() -> Data? { + if isRecording && recorder != nil { + recorder!.stop() + let audio = getDocumentsDirectory().appendingPathComponent("tempvoice.wav") + recorder = nil + do { + let data = try Data(contentsOf: audio) // sends raw audio data + try FileManager.default.removeItem(at: audio) // deletes the file + return data + } catch { + print(error.localizedDescription) + return nil + } + } else { + print("not recording") + return nil + } + } + +} diff --git a/software/source/clients/ios/zeroone-app/zeroone-app/Base.lproj/LaunchScreen.storyboard b/software/source/clients/ios/zeroone-app/zeroone-app/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/software/source/clients/ios/zeroone-app/zeroone-app/Base.lproj/Main.storyboard b/software/source/clients/ios/zeroone-app/zeroone-app/Base.lproj/Main.storyboard new file mode 100644 index 0000000..d9cd8b2 --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app/Base.lproj/Main.storyboard @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/software/source/clients/ios/zeroone-app/zeroone-app/Info.plist b/software/source/clients/ios/zeroone-app/zeroone-app/Info.plist new file mode 100644 index 0000000..aef04f9 --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app/Info.plist @@ -0,0 +1,27 @@ + + + + + NSSpeechRecognitionUsageDescription + Your audio is used the convert your voice requests into text requests. + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + + diff --git a/software/source/clients/ios/zeroone-app/zeroone-app/SceneDelegate.swift b/software/source/clients/ios/zeroone-app/zeroone-app/SceneDelegate.swift new file mode 100644 index 0000000..a67a1a3 --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app/SceneDelegate.swift @@ -0,0 +1,52 @@ +// +// SceneDelegate.swift +// zeroone-app +// +// Created by Elad Dekel on 2024-05-09. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } + + +} + diff --git a/software/source/clients/ios/zeroone-app/zeroone-app/ViewController.swift b/software/source/clients/ios/zeroone-app/zeroone-app/ViewController.swift new file mode 100644 index 0000000..0b39175 --- /dev/null +++ b/software/source/clients/ios/zeroone-app/zeroone-app/ViewController.swift @@ -0,0 +1,366 @@ +// +// ViewController.swift +// zeroone-app +// +// Created by Elad Dekel on 2024-05-09. +// + +import UIKit +import Starscream +import AVFoundation + + +class ViewController: UIViewController, WebSocketDelegate { + + @IBOutlet weak var terminalFeed: UITextView! + @IBOutlet weak var terminalButton: UIImageView! + @IBOutlet weak var reconnectIcon: UIImageView! + @IBOutlet weak var circle: UIImageView! + @IBOutlet weak var settingsGear: UIImageView! + @IBOutlet weak var infoText: UILabel! + + var audioRecordingInstance: AudioRecording? + private var audioData = Data() + private var audioPlayer: AVAudioPlayer? + var address: String? + var isConnected = false + var recordingPermission = false + var terminal = false + var socket: WebSocket? + + + override func viewDidLoad() { + super.viewDidLoad() + terminalFeed.layer.cornerRadius = 15 + infoText.text = "Hold to start once connected." + // Create a gesture recognizer that tracks when the "button" is held + let pressGesture = UILongPressGestureRecognizer(target: self, action: #selector(buttonPress(_:))) + pressGesture.minimumPressDuration = 0.01 + circle.addGestureRecognizer(pressGesture) + circle.isUserInteractionEnabled = true + circle.translatesAutoresizingMaskIntoConstraints = false + + // Create a geature recognizer for the settings button + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(settingsGear(_:))) + settingsGear.addGestureRecognizer(tapGesture) + settingsGear.isUserInteractionEnabled = true + + + let reconnectGesture = UITapGestureRecognizer(target: self, action: #selector(recconectIcon(_:))) + reconnectIcon.addGestureRecognizer(reconnectGesture) + reconnectIcon.isUserInteractionEnabled = true + + + let terminal = UITapGestureRecognizer(target: self, action: #selector(terminalIcon(_:))) + terminalButton.addGestureRecognizer(terminal) + terminalButton.isUserInteractionEnabled = true + + + } + + + + + + + func checkRecordingPerms() { + let sess = AVAudioSession.sharedInstance() + switch (sess.recordPermission) { + case.denied, .undetermined: + sess.requestRecordPermission { (granted) in + if granted { + self.recordingPermission = true + } else { + let alert = UIAlertController(title: "Recording Not Permitted", message: "You must allow audio recording in order to send commands. Close the app and re-open it to try again.", preferredStyle: .alert) + let action = UIAlertAction(title: "Understood", style: .default) + alert.addAction(action) + self.present(alert, animated: true) + } + } + case .granted: + recordingPermission = true + default: + break + } + } + + override func viewDidAppear(_ animated: Bool) { + if ((UserDefaults.standard.value(forKey: "IPINFO")) != nil) { + print("here") + address = UserDefaults.standard.string(forKey: "IPINFO") + establishConnection() + } else { + print("there") + setAddress() + } + checkRecordingPerms() + } + + func receieved(data: String) { + infoText.text = data + } + + + + + + func setAddress() { + let alert = UIAlertController(title: "Set the Address", message: "Input the address of the WebSocket (found in the terminal running 01 software)", preferredStyle: .alert) + alert.addTextField { (field) in + field.placeholder = "Enter Address Here" + } + let cancelButton = UIAlertAction(title: "Cancel", style: .cancel) + alert.addAction(cancelButton) + let submitButton = UIAlertAction(title: "Done", style: .default) { (_) in + if let field = alert.textFields?.first, let text = field.text { + UserDefaults.standard.setValue(text, forKey: "IPINFO") + self.address = text + self.establishConnection() + // HAVE THE TEXT FIELD + } + } + alert.addAction(submitButton) + + present(alert, animated: true) + } + + @objc func recconectIcon(_ sender: UIGestureRecognizer) { + infoText.text = "" + self.establishConnection() + } + + @objc func terminalIcon(_ sender: UIGestureRecognizer) { + if (terminal) { + UIView.animate(withDuration: 0.3) { + self.terminalFeed.text = "" + self.terminalFeed.alpha = 0 + let moveT = CGAffineTransform(translationX: 0, y: -190) + self.appendTranslation(transform: moveT) + self.terminalButton.image = UIImage(systemName: "apple.terminal") + } completion: { done in + self.terminal = false + } + } else { + UIView.animate(withDuration: 0.3) { + self.terminalFeed.alpha = 1 + let moveT = CGAffineTransform(translationX: 0, y: 190) + self.appendTranslation(transform: moveT) + self.terminalButton.image = UIImage(systemName: "apple.terminal.fill") + } completion: { done in + self.terminal = true + } + + } + } + + @objc func settingsGear(_ sender: UIGestureRecognizer) { + infoText.text = "" + setAddress() + } + + func appendTranslation(transform: CGAffineTransform) { + var currentTransform = self.circle.transform + currentTransform = currentTransform.concatenating(transform) + self.circle.transform = currentTransform + } + + @objc func buttonPress(_ sender: UILongPressGestureRecognizer) { + infoText.text = "" + let feedback = UIImpactFeedbackGenerator(style: .medium) + if sender.state == .began { + socket?.connect() + // check for recording permission, if exists + // it began, start recording! + if (isConnected && recordingPermission) { + audioRecordingInstance = AudioRecording() + audioRecordingInstance!.startRecording() + infoText.text = "" + UIView.animate(withDuration: 0.1) { + self.circle.tintColor = .green + let newT = CGAffineTransform(scaleX: 0.7, y: 0.7) + self.appendTranslation(transform: newT) + feedback.prepare() + feedback.impactOccurred() + } + } else { + let errorFeedback = UIImpactFeedbackGenerator(style: .heavy) + errorFeedback.prepare() + errorFeedback.impactOccurred() + if (isConnected && !recordingPermission) { + infoText.text = "Not recording permission. Please close and re-open the app." + } else { + infoText.text = "Not connected." + establishConnection() + } + UIView.animate(withDuration: 0.5) { + self.circle.tintColor = .red + } completion: { _ in + self.circle.tintColor = .systemYellow + } + + + } + } else if sender.state == .ended { + if (isConnected && recordingPermission) { + if (audioRecordingInstance != nil) { + let response = audioRecordingInstance!.stopRecording() + if (response != nil) { + sendAudio(audio: response!) + } + UIView.animate(withDuration: 0.1) { + self.circle.tintColor = .systemYellow + let newT = CGAffineTransform(scaleX: 1.4, y: 1.4) + self.appendTranslation(transform: newT) + feedback.prepare() + feedback.impactOccurred() + } + } + } + // stop recording and send the audio + } + } + + + + + + func establishConnection() { //connect to the web socket + if (address != nil) { + var request = URLRequest(url: URL(string: "http://\(address!)")!) + request.timeoutInterval = 5 + socket = WebSocket(request: request) + socket!.delegate = self + socket!.connect() + } else { + setAddress() + } + } + + func didReceive(event: Starscream.WebSocketEvent, client: any Starscream.WebSocketClient) { // deal with receiving data from websocket + switch event { + case .connected( _): + isConnected = true + reconnectIcon.tintColor = .green + case .disconnected(let reason, let code): + isConnected = false + reconnectIcon.tintColor = .red + case .text(let string): + if (terminal) { + terminalFeed.text = terminalFeed.text + "\n>> \(string)" + let range = NSMakeRange(terminalFeed.text.count - 1, 0) + terminalFeed.scrollRangeToVisible(range) + } + if (string.contains("audio") && string.contains("bytes.raw") && string.contains("start")) { + infoText.text = "Receiving response..." + // it started collecting data! + print("Audio is being receieved.") + } else if (string.contains("audio") && string.contains("bytes.raw") && string.contains("end")) { + infoText.text = "" + print("Audio is no longer being receieved.") + let wavHeader = createWAVHeader(audioDataSize: Int32(audioData.count - 44)) + // Combine header and data + var completeWAVData = Data() + completeWAVData.append(wavHeader) + completeWAVData.append(audioData.subdata(in: 44.. Data { + let headerSize: Int32 = 44 // Standard WAV header size + let chunkSize: Int32 = 36 + audioDataSize + let sampleRate: Int32 = 16000 // From i2s_config + let numChannels: Int16 = 1 // From i2s_config (mono) + let bitsPerSample: Int16 = 16 // From i2s_config + let byteRate: Int32 = sampleRate * Int32(numChannels) * Int32(bitsPerSample) / 8 + let blockAlign: Int16 = numChannels * bitsPerSample / 8 + + var headerData = Data() + + // RIFF Chunk + headerData.append(stringToData("RIFF")) // ChunkID + headerData.append(int32ToData(chunkSize)) // ChunkSize + headerData.append(stringToData("WAVE")) // Format + + // fmt Subchunk + headerData.append(stringToData("fmt ")) // Subchunk1ID + headerData.append(int32ToData(16)) // Subchunk1Size (16 for PCM) + headerData.append(int16ToData(1)) // AudioFormat (1 for PCM) + headerData.append(int16ToData(numChannels)) // NumChannels + headerData.append(int32ToData(sampleRate)) // SampleRate + headerData.append(int32ToData(byteRate)) // ByteRate + headerData.append(int16ToData(blockAlign)) // BlockAlign + headerData.append(int16ToData(bitsPerSample)) // BitsPerSample + + // data Subchunk + headerData.append(stringToData("data")) // Subchunk2ID + headerData.append(int32ToData(audioDataSize)) // Subchunk2Size + + return headerData + } + + func stringToData(_ string: String) -> Data { + return string.data(using: .utf8)! + } + + func int16ToData(_ value: Int16) -> Data { + var value = value.littleEndian + return Data(bytes: &value, count: MemoryLayout.size) + } + + func int32ToData(_ value: Int32) -> Data { + var value = value.littleEndian + return Data(bytes: &value, count: MemoryLayout.size) + } + + + func sendAudio(audio: Data) { + if (isConnected) { + socket!.write(string: "{\"role\": \"user\", \"type\": \"audio\", \"format\": \"bytes.raw\", \"start\": true}") + socket!.write(data: audio) + socket!.write(string: "{\"role\": \"user\", \"type\": \"audio\", \"format\": \"bytes.raw\", \"end\": true}") + } else { + print("Not connected!") + } + } + + + + + +} + + From 81cdce00fbcb9db80a1ddaf01251588c04829a72 Mon Sep 17 00:00:00 2001 From: Elad Dekel <74513560+eladdekel@users.noreply.github.com> Date: Wed, 15 May 2024 21:41:57 -0400 Subject: [PATCH 3/3] implementation of native iOS app --- .../xcdebugger/Breakpoints_v2.xcbkptlist | 6 ------ .../xcschemes/xcschememanagement.plist | 14 -------------- 2 files changed, 20 deletions(-) delete mode 100644 software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist delete mode 100644 software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index a1ddc74..0000000 --- a/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,6 +0,0 @@ - - - diff --git a/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcschemes/xcschememanagement.plist b/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 31bfb5f..0000000 --- a/software/source/clients/ios/zeroone-app/zeroone-app.xcodeproj/xcuserdata/eladdekel.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - SchemeUserState - - zeroone-app.xcscheme_^#shared#^_ - - orderHint - 0 - - - -