├── Podfile ├── Podfile.lock ├── README.md ├── VirtualClassroom.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── cardoso.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── VirtualClassroom.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── VirtualClassroom ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Class │ ├── ClassViewController+Call.swift │ ├── ClassViewController+Chat.swift │ ├── ClassViewController+Handlers.swift │ ├── ClassViewController+Views.swift │ └── ClassViewController.swift ├── Extensions │ └── String+Random.swift ├── Info.plist ├── Join │ ├── JoinViewController+Constraints.swift │ ├── JoinViewController+Handlers.swift │ ├── JoinViewController+Views.swift │ └── JoinViewController.swift └── SceneDelegate.swift └── meta └── teacher.png /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'VirtualClassroom' do 5 | # Comment the next line if you don't want to use dynamic frameworks 6 | use_frameworks! 7 | 8 | # Pods for VirtualClassroom 9 | pod 'StreamChat', '~> 2.2' 10 | pod 'VoxeetUXKit', '~> 1.3' 11 | end 12 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Nuke (8.4.1) 3 | - RxCocoa (5.1.1): 4 | - RxRelay (~> 5) 5 | - RxSwift (~> 5) 6 | - RxGesture (3.0.2): 7 | - RxCocoa (~> 5.1) 8 | - RxSwift (~> 5.1) 9 | - RxRelay (5.1.1): 10 | - RxSwift (~> 5) 11 | - RxSwift (5.1.1) 12 | - SDWebImage (5.8.2): 13 | - SDWebImage/Core (= 5.8.2) 14 | - SDWebImage/Core (5.8.2) 15 | - SnapKit (5.0.1) 16 | - Starscream (3.1.1) 17 | - StreamChat (2.2.5): 18 | - Nuke (~> 8.4) 19 | - RxGesture (~> 3.0) 20 | - SnapKit (~> 5.0) 21 | - StreamChatCore (= 2.2.5) 22 | - SwiftyGif (~> 5.2.0) 23 | - StreamChatClient (2.2.5): 24 | - Starscream (~> 3.1) 25 | - StreamChatCore (2.2.5): 26 | - RxCocoa (~> 5.1) 27 | - RxSwift (~> 5.1) 28 | - StreamChatClient (= 2.2.5) 29 | - SwiftyGif (5.2.0) 30 | - VoxeetSDK (2.4.0) 31 | - VoxeetUXKit (1.3.4): 32 | - SDWebImage (~> 5.0) 33 | - VoxeetSDK (~> 2.0) 34 | 35 | DEPENDENCIES: 36 | - StreamChat (~> 2.2) 37 | - VoxeetUXKit (~> 1.3) 38 | 39 | SPEC REPOS: 40 | trunk: 41 | - Nuke 42 | - RxCocoa 43 | - RxGesture 44 | - RxRelay 45 | - RxSwift 46 | - SDWebImage 47 | - SnapKit 48 | - Starscream 49 | - StreamChat 50 | - StreamChatClient 51 | - StreamChatCore 52 | - SwiftyGif 53 | - VoxeetSDK 54 | - VoxeetUXKit 55 | 56 | SPEC CHECKSUMS: 57 | Nuke: d780e3507a86b86c589ab3cc5cd302d5456f06fb 58 | RxCocoa: 32065309a38d29b5b0db858819b5bf9ef038b601 59 | RxGesture: d6bd7447ca3a596c7a9702a6a2b6a2bb5d8bae54 60 | RxRelay: d77f7d771495f43c556cbc43eebd1bb54d01e8e9 61 | RxSwift: 81470a2074fa8780320ea5fe4102807cb7118178 62 | SDWebImage: f923a89d7344af399ba77b87a523ae747408207a 63 | SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb 64 | Starscream: 4bb2f9942274833f7b4d296a55504dcfc7edb7b0 65 | StreamChat: 6aefba044efe17fb620564a4983e6523184f5e09 66 | StreamChatClient: 0d81226a9f3242feae3852943132aceacfd2bb56 67 | StreamChatCore: 279479f53874712c2bc18f90c9862c9ebd19321c 68 | SwiftyGif: b85c6b33a9411859d9e1db998b6a8214aea942df 69 | VoxeetSDK: 44b67623efdb5d681223482abc245c6a8ab9a9e9 70 | VoxeetUXKit: 5d09d9518604fd30fbf376916060a709d8ad2ee8 71 | 72 | PODFILE CHECKSUM: 47de70c3032dccd51e6c77430bd9ae1c748e644f 73 | 74 | COCOAPODS: 1.9.3 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 💬 Virtual Classroom App for iOS with Stream Chat and Dolby.io [![](https://img.shields.io/twitter/url?url=https%3A%2F%2Fgithub.com%2FGetStream%2Fedtech-classroom-app-ios)](https://twitter.com/intent/tweet?text=Want%20to%20build%20an%20edtech%20virtual%20classroom%20app%20for%20iOS%20with%20video%20and%20chat%3F%20Learn%20how%3A&url=https%3A%2F%2Fgithub.com%2FGetStream%2Fedtech-classroom-app-ios) 2 | 3 | 4 | 5 | ## 📚 Tutorial 6 | 7 | This repository contains the completed Xcode project following the [How to Build a Virtual Classroom iOS App with Video and Chat](https://getstream.io/blog/edtech-virtual-classroom-ios/) tutorial. You should read it before trying to run this project as it contains it may contain useful information not present in this README. 8 | 9 | ## ⚙️ Setup 10 | 11 | ## Requirements 12 | - Xcode 11+ 13 | - iOS 13+ 14 | - A [Stream](https://getstream.io/accounts/signup/) account 15 | - A [Dolby.io](https://dolby.io/organizations/register) account 16 | 17 | ### Configuration 18 | 19 | You should place your [Stream Chat](https://getstream.io/chat) and [Dolby.io](https://dolby.io) credentials in [`AppDelegate.swift`](VirtualClassroom/AppDelegate.swift#L18-L20). 20 | 21 | ### Dependencies 22 | 23 | To install the dependencies, use CocoaPods in this project's folder: 24 | 25 | ```bash 26 | $ pod install --repo-update 27 | ``` 28 | 29 | ### Running 30 | 31 | Run this sample app as any normal app, but only on real devices. If you run in a simulator, the chat will work, but you won't be able to watch or stream video due to limitations of the simulator, though voice should work. 32 | 33 | ## 🔗 Helpful Links 34 | 35 | - [Build an iMessage Clone with The Stream Chat iOS SDK](https://getstream.io/blog/build-imessage-clone/) 36 | - [Stream Chat iOS Tutorial](https://getstream.io/tutorials/ios-chat/) 37 | - [Stream Chat iOS Repo](https://github.com/GetStream/stream-chat-swift) 38 | - [Stream Chat iOS Docs](http://getstream.io/chat/docs?language=swift) 39 | -------------------------------------------------------------------------------- /VirtualClassroom.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 51; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8040754124AD784C00F2C9D8 /* JoinViewController+Views.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8040754024AD784C00F2C9D8 /* JoinViewController+Views.swift */; }; 11 | 8040754324AD791900F2C9D8 /* JoinViewController+Handlers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8040754224AD791900F2C9D8 /* JoinViewController+Handlers.swift */; }; 12 | 8040754524AD79AF00F2C9D8 /* JoinViewController+Constraints.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8040754424AD79AF00F2C9D8 /* JoinViewController+Constraints.swift */; }; 13 | 8040754824AD7D7B00F2C9D8 /* ClassViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8040754724AD7D7B00F2C9D8 /* ClassViewController.swift */; }; 14 | 8040754A24AD7E9100F2C9D8 /* ClassViewController+Chat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8040754924AD7E9100F2C9D8 /* ClassViewController+Chat.swift */; }; 15 | 8040754C24AD809B00F2C9D8 /* ClassViewController+Views.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8040754B24AD809B00F2C9D8 /* ClassViewController+Views.swift */; }; 16 | 8040754E24AD832800F2C9D8 /* ClassViewController+Handlers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8040754D24AD832800F2C9D8 /* ClassViewController+Handlers.swift */; }; 17 | 8040755024AD83A600F2C9D8 /* ClassViewController+Call.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8040754F24AD83A600F2C9D8 /* ClassViewController+Call.swift */; }; 18 | 8040755324AEB88E00F2C9D8 /* String+Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8040755224AEB88E00F2C9D8 /* String+Random.swift */; }; 19 | 808A85F524AC0805008488E7 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 808A85F424AC0805008488E7 /* AppDelegate.swift */; }; 20 | 808A85F724AC0805008488E7 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 808A85F624AC0805008488E7 /* SceneDelegate.swift */; }; 21 | 808A85F924AC0805008488E7 /* JoinViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 808A85F824AC0805008488E7 /* JoinViewController.swift */; }; 22 | 808A85FC24AC0805008488E7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 808A85FA24AC0805008488E7 /* Main.storyboard */; }; 23 | 808A85FE24AC0806008488E7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 808A85FD24AC0806008488E7 /* Assets.xcassets */; }; 24 | 808A860124AC0806008488E7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 808A85FF24AC0806008488E7 /* LaunchScreen.storyboard */; }; 25 | 8DB4F2178E25851EBBDF28A7 /* Pods_VirtualClassroom.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B450CDBE649E6079043F02C6 /* Pods_VirtualClassroom.framework */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 2A70025B666B761E85FA4123 /* Pods-VirtualClassroom.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VirtualClassroom.debug.xcconfig"; path = "Target Support Files/Pods-VirtualClassroom/Pods-VirtualClassroom.debug.xcconfig"; sourceTree = ""; }; 30 | 8040754024AD784C00F2C9D8 /* JoinViewController+Views.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JoinViewController+Views.swift"; sourceTree = ""; }; 31 | 8040754224AD791900F2C9D8 /* JoinViewController+Handlers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JoinViewController+Handlers.swift"; sourceTree = ""; }; 32 | 8040754424AD79AF00F2C9D8 /* JoinViewController+Constraints.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JoinViewController+Constraints.swift"; sourceTree = ""; }; 33 | 8040754724AD7D7B00F2C9D8 /* ClassViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClassViewController.swift; sourceTree = ""; }; 34 | 8040754924AD7E9100F2C9D8 /* ClassViewController+Chat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ClassViewController+Chat.swift"; sourceTree = ""; }; 35 | 8040754B24AD809B00F2C9D8 /* ClassViewController+Views.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ClassViewController+Views.swift"; sourceTree = ""; }; 36 | 8040754D24AD832800F2C9D8 /* ClassViewController+Handlers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ClassViewController+Handlers.swift"; sourceTree = ""; }; 37 | 8040754F24AD83A600F2C9D8 /* ClassViewController+Call.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ClassViewController+Call.swift"; sourceTree = ""; }; 38 | 8040755224AEB88E00F2C9D8 /* String+Random.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Random.swift"; sourceTree = ""; }; 39 | 808A85F124AC0805008488E7 /* VirtualClassroom.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VirtualClassroom.app; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | 808A85F424AC0805008488E7 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 41 | 808A85F624AC0805008488E7 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 42 | 808A85F824AC0805008488E7 /* JoinViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinViewController.swift; sourceTree = ""; }; 43 | 808A85FB24AC0805008488E7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 44 | 808A85FD24AC0806008488E7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 45 | 808A860024AC0806008488E7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 46 | 808A860224AC0806008488E7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47 | B450CDBE649E6079043F02C6 /* Pods_VirtualClassroom.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_VirtualClassroom.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | DF102529EC3F070959A0AC7B /* Pods-VirtualClassroom.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VirtualClassroom.release.xcconfig"; path = "Target Support Files/Pods-VirtualClassroom/Pods-VirtualClassroom.release.xcconfig"; sourceTree = ""; }; 49 | /* End PBXFileReference section */ 50 | 51 | /* Begin PBXFrameworksBuildPhase section */ 52 | 808A85EE24AC0805008488E7 /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 2147483647; 55 | files = ( 56 | 8DB4F2178E25851EBBDF28A7 /* Pods_VirtualClassroom.framework in Frameworks */, 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | /* End PBXFrameworksBuildPhase section */ 61 | 62 | /* Begin PBXGroup section */ 63 | 8040753F24AD780D00F2C9D8 /* Join */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | 808A85F824AC0805008488E7 /* JoinViewController.swift */, 67 | 8040754024AD784C00F2C9D8 /* JoinViewController+Views.swift */, 68 | 8040754424AD79AF00F2C9D8 /* JoinViewController+Constraints.swift */, 69 | 8040754224AD791900F2C9D8 /* JoinViewController+Handlers.swift */, 70 | ); 71 | path = Join; 72 | sourceTree = ""; 73 | }; 74 | 8040754624AD7D6A00F2C9D8 /* Class */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 8040754724AD7D7B00F2C9D8 /* ClassViewController.swift */, 78 | 8040754924AD7E9100F2C9D8 /* ClassViewController+Chat.swift */, 79 | 8040754B24AD809B00F2C9D8 /* ClassViewController+Views.swift */, 80 | 8040754D24AD832800F2C9D8 /* ClassViewController+Handlers.swift */, 81 | 8040754F24AD83A600F2C9D8 /* ClassViewController+Call.swift */, 82 | ); 83 | path = Class; 84 | sourceTree = ""; 85 | }; 86 | 8040755124AEB87E00F2C9D8 /* Extensions */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 8040755224AEB88E00F2C9D8 /* String+Random.swift */, 90 | ); 91 | path = Extensions; 92 | sourceTree = ""; 93 | }; 94 | 808A85E824AC0805008488E7 = { 95 | isa = PBXGroup; 96 | children = ( 97 | 808A85F324AC0805008488E7 /* VirtualClassroom */, 98 | 808A85F224AC0805008488E7 /* Products */, 99 | EAAB5A50072B41D64B42DC0D /* Pods */, 100 | E1491F77975E8F9F99D726E3 /* Frameworks */, 101 | ); 102 | sourceTree = ""; 103 | }; 104 | 808A85F224AC0805008488E7 /* Products */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | 808A85F124AC0805008488E7 /* VirtualClassroom.app */, 108 | ); 109 | name = Products; 110 | sourceTree = ""; 111 | }; 112 | 808A85F324AC0805008488E7 /* VirtualClassroom */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 808A85F424AC0805008488E7 /* AppDelegate.swift */, 116 | 808A85F624AC0805008488E7 /* SceneDelegate.swift */, 117 | 8040755124AEB87E00F2C9D8 /* Extensions */, 118 | 8040753F24AD780D00F2C9D8 /* Join */, 119 | 8040754624AD7D6A00F2C9D8 /* Class */, 120 | 808A85FA24AC0805008488E7 /* Main.storyboard */, 121 | 808A85FD24AC0806008488E7 /* Assets.xcassets */, 122 | 808A85FF24AC0806008488E7 /* LaunchScreen.storyboard */, 123 | 808A860224AC0806008488E7 /* Info.plist */, 124 | ); 125 | path = VirtualClassroom; 126 | sourceTree = ""; 127 | }; 128 | E1491F77975E8F9F99D726E3 /* Frameworks */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | B450CDBE649E6079043F02C6 /* Pods_VirtualClassroom.framework */, 132 | ); 133 | name = Frameworks; 134 | sourceTree = ""; 135 | }; 136 | EAAB5A50072B41D64B42DC0D /* Pods */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | 2A70025B666B761E85FA4123 /* Pods-VirtualClassroom.debug.xcconfig */, 140 | DF102529EC3F070959A0AC7B /* Pods-VirtualClassroom.release.xcconfig */, 141 | ); 142 | path = Pods; 143 | sourceTree = ""; 144 | }; 145 | /* End PBXGroup section */ 146 | 147 | /* Begin PBXNativeTarget section */ 148 | 808A85F024AC0805008488E7 /* VirtualClassroom */ = { 149 | isa = PBXNativeTarget; 150 | buildConfigurationList = 808A860524AC0806008488E7 /* Build configuration list for PBXNativeTarget "VirtualClassroom" */; 151 | buildPhases = ( 152 | 50D99F7AB03BA6F70CEC6BF9 /* [CP] Check Pods Manifest.lock */, 153 | 808A85ED24AC0805008488E7 /* Sources */, 154 | 808A85EE24AC0805008488E7 /* Frameworks */, 155 | 808A85EF24AC0805008488E7 /* Resources */, 156 | FEE0521E4D37FD555240BE4E /* [CP] Embed Pods Frameworks */, 157 | ); 158 | buildRules = ( 159 | ); 160 | dependencies = ( 161 | ); 162 | name = VirtualClassroom; 163 | productName = VirtualClassroom; 164 | productReference = 808A85F124AC0805008488E7 /* VirtualClassroom.app */; 165 | productType = "com.apple.product-type.application"; 166 | }; 167 | /* End PBXNativeTarget section */ 168 | 169 | /* Begin PBXProject section */ 170 | 808A85E924AC0805008488E7 /* Project object */ = { 171 | isa = PBXProject; 172 | attributes = { 173 | LastSwiftUpdateCheck = 1150; 174 | LastUpgradeCheck = 1150; 175 | ORGANIZATIONNAME = "Matheus Cardoso"; 176 | TargetAttributes = { 177 | 808A85F024AC0805008488E7 = { 178 | CreatedOnToolsVersion = 11.5; 179 | }; 180 | }; 181 | }; 182 | buildConfigurationList = 808A85EC24AC0805008488E7 /* Build configuration list for PBXProject "VirtualClassroom" */; 183 | compatibilityVersion = "Xcode 9.3"; 184 | developmentRegion = en; 185 | hasScannedForEncodings = 0; 186 | knownRegions = ( 187 | en, 188 | Base, 189 | ); 190 | mainGroup = 808A85E824AC0805008488E7; 191 | productRefGroup = 808A85F224AC0805008488E7 /* Products */; 192 | projectDirPath = ""; 193 | projectRoot = ""; 194 | targets = ( 195 | 808A85F024AC0805008488E7 /* VirtualClassroom */, 196 | ); 197 | }; 198 | /* End PBXProject section */ 199 | 200 | /* Begin PBXResourcesBuildPhase section */ 201 | 808A85EF24AC0805008488E7 /* Resources */ = { 202 | isa = PBXResourcesBuildPhase; 203 | buildActionMask = 2147483647; 204 | files = ( 205 | 808A860124AC0806008488E7 /* LaunchScreen.storyboard in Resources */, 206 | 808A85FE24AC0806008488E7 /* Assets.xcassets in Resources */, 207 | 808A85FC24AC0805008488E7 /* Main.storyboard in Resources */, 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | }; 211 | /* End PBXResourcesBuildPhase section */ 212 | 213 | /* Begin PBXShellScriptBuildPhase section */ 214 | 50D99F7AB03BA6F70CEC6BF9 /* [CP] Check Pods Manifest.lock */ = { 215 | isa = PBXShellScriptBuildPhase; 216 | buildActionMask = 2147483647; 217 | files = ( 218 | ); 219 | inputFileListPaths = ( 220 | ); 221 | inputPaths = ( 222 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 223 | "${PODS_ROOT}/Manifest.lock", 224 | ); 225 | name = "[CP] Check Pods Manifest.lock"; 226 | outputFileListPaths = ( 227 | ); 228 | outputPaths = ( 229 | "$(DERIVED_FILE_DIR)/Pods-VirtualClassroom-checkManifestLockResult.txt", 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | shellPath = /bin/sh; 233 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 234 | showEnvVarsInLog = 0; 235 | }; 236 | FEE0521E4D37FD555240BE4E /* [CP] Embed Pods Frameworks */ = { 237 | isa = PBXShellScriptBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | ); 241 | inputFileListPaths = ( 242 | "${PODS_ROOT}/Target Support Files/Pods-VirtualClassroom/Pods-VirtualClassroom-frameworks-${CONFIGURATION}-input-files.xcfilelist", 243 | ); 244 | name = "[CP] Embed Pods Frameworks"; 245 | outputFileListPaths = ( 246 | "${PODS_ROOT}/Target Support Files/Pods-VirtualClassroom/Pods-VirtualClassroom-frameworks-${CONFIGURATION}-output-files.xcfilelist", 247 | ); 248 | runOnlyForDeploymentPostprocessing = 0; 249 | shellPath = /bin/sh; 250 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-VirtualClassroom/Pods-VirtualClassroom-frameworks.sh\"\n"; 251 | showEnvVarsInLog = 0; 252 | }; 253 | /* End PBXShellScriptBuildPhase section */ 254 | 255 | /* Begin PBXSourcesBuildPhase section */ 256 | 808A85ED24AC0805008488E7 /* Sources */ = { 257 | isa = PBXSourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | 8040754824AD7D7B00F2C9D8 /* ClassViewController.swift in Sources */, 261 | 8040754A24AD7E9100F2C9D8 /* ClassViewController+Chat.swift in Sources */, 262 | 808A85F924AC0805008488E7 /* JoinViewController.swift in Sources */, 263 | 8040755024AD83A600F2C9D8 /* ClassViewController+Call.swift in Sources */, 264 | 8040754124AD784C00F2C9D8 /* JoinViewController+Views.swift in Sources */, 265 | 808A85F524AC0805008488E7 /* AppDelegate.swift in Sources */, 266 | 8040754524AD79AF00F2C9D8 /* JoinViewController+Constraints.swift in Sources */, 267 | 8040754324AD791900F2C9D8 /* JoinViewController+Handlers.swift in Sources */, 268 | 8040754C24AD809B00F2C9D8 /* ClassViewController+Views.swift in Sources */, 269 | 8040755324AEB88E00F2C9D8 /* String+Random.swift in Sources */, 270 | 808A85F724AC0805008488E7 /* SceneDelegate.swift in Sources */, 271 | 8040754E24AD832800F2C9D8 /* ClassViewController+Handlers.swift in Sources */, 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | /* End PBXSourcesBuildPhase section */ 276 | 277 | /* Begin PBXVariantGroup section */ 278 | 808A85FA24AC0805008488E7 /* Main.storyboard */ = { 279 | isa = PBXVariantGroup; 280 | children = ( 281 | 808A85FB24AC0805008488E7 /* Base */, 282 | ); 283 | name = Main.storyboard; 284 | sourceTree = ""; 285 | }; 286 | 808A85FF24AC0806008488E7 /* LaunchScreen.storyboard */ = { 287 | isa = PBXVariantGroup; 288 | children = ( 289 | 808A860024AC0806008488E7 /* Base */, 290 | ); 291 | name = LaunchScreen.storyboard; 292 | sourceTree = ""; 293 | }; 294 | /* End PBXVariantGroup section */ 295 | 296 | /* Begin XCBuildConfiguration section */ 297 | 808A860324AC0806008488E7 /* Debug */ = { 298 | isa = XCBuildConfiguration; 299 | buildSettings = { 300 | ALWAYS_SEARCH_USER_PATHS = NO; 301 | CLANG_ANALYZER_NONNULL = YES; 302 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 303 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 304 | CLANG_CXX_LIBRARY = "libc++"; 305 | CLANG_ENABLE_MODULES = YES; 306 | CLANG_ENABLE_OBJC_ARC = YES; 307 | CLANG_ENABLE_OBJC_WEAK = YES; 308 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 309 | CLANG_WARN_BOOL_CONVERSION = YES; 310 | CLANG_WARN_COMMA = YES; 311 | CLANG_WARN_CONSTANT_CONVERSION = YES; 312 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 313 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 314 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 315 | CLANG_WARN_EMPTY_BODY = YES; 316 | CLANG_WARN_ENUM_CONVERSION = YES; 317 | CLANG_WARN_INFINITE_RECURSION = YES; 318 | CLANG_WARN_INT_CONVERSION = YES; 319 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 320 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 321 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 322 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 323 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 324 | CLANG_WARN_STRICT_PROTOTYPES = YES; 325 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 326 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 327 | CLANG_WARN_UNREACHABLE_CODE = YES; 328 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 329 | COPY_PHASE_STRIP = NO; 330 | DEBUG_INFORMATION_FORMAT = dwarf; 331 | ENABLE_STRICT_OBJC_MSGSEND = YES; 332 | ENABLE_TESTABILITY = YES; 333 | GCC_C_LANGUAGE_STANDARD = gnu11; 334 | GCC_DYNAMIC_NO_PIC = NO; 335 | GCC_NO_COMMON_BLOCKS = YES; 336 | GCC_OPTIMIZATION_LEVEL = 0; 337 | GCC_PREPROCESSOR_DEFINITIONS = ( 338 | "DEBUG=1", 339 | "$(inherited)", 340 | ); 341 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 342 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 343 | GCC_WARN_UNDECLARED_SELECTOR = YES; 344 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 345 | GCC_WARN_UNUSED_FUNCTION = YES; 346 | GCC_WARN_UNUSED_VARIABLE = YES; 347 | IPHONEOS_DEPLOYMENT_TARGET = 13.5; 348 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 349 | MTL_FAST_MATH = YES; 350 | ONLY_ACTIVE_ARCH = YES; 351 | SDKROOT = iphoneos; 352 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 353 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 354 | }; 355 | name = Debug; 356 | }; 357 | 808A860424AC0806008488E7 /* Release */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | ALWAYS_SEARCH_USER_PATHS = NO; 361 | CLANG_ANALYZER_NONNULL = YES; 362 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 363 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 364 | CLANG_CXX_LIBRARY = "libc++"; 365 | CLANG_ENABLE_MODULES = YES; 366 | CLANG_ENABLE_OBJC_ARC = YES; 367 | CLANG_ENABLE_OBJC_WEAK = YES; 368 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 369 | CLANG_WARN_BOOL_CONVERSION = YES; 370 | CLANG_WARN_COMMA = YES; 371 | CLANG_WARN_CONSTANT_CONVERSION = YES; 372 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 373 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 374 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 375 | CLANG_WARN_EMPTY_BODY = YES; 376 | CLANG_WARN_ENUM_CONVERSION = YES; 377 | CLANG_WARN_INFINITE_RECURSION = YES; 378 | CLANG_WARN_INT_CONVERSION = YES; 379 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 380 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 381 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 382 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 383 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 384 | CLANG_WARN_STRICT_PROTOTYPES = YES; 385 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 386 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 387 | CLANG_WARN_UNREACHABLE_CODE = YES; 388 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 389 | COPY_PHASE_STRIP = NO; 390 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 391 | ENABLE_NS_ASSERTIONS = NO; 392 | ENABLE_STRICT_OBJC_MSGSEND = YES; 393 | GCC_C_LANGUAGE_STANDARD = gnu11; 394 | GCC_NO_COMMON_BLOCKS = YES; 395 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 396 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 397 | GCC_WARN_UNDECLARED_SELECTOR = YES; 398 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 399 | GCC_WARN_UNUSED_FUNCTION = YES; 400 | GCC_WARN_UNUSED_VARIABLE = YES; 401 | IPHONEOS_DEPLOYMENT_TARGET = 13.5; 402 | MTL_ENABLE_DEBUG_INFO = NO; 403 | MTL_FAST_MATH = YES; 404 | SDKROOT = iphoneos; 405 | SWIFT_COMPILATION_MODE = wholemodule; 406 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 407 | VALIDATE_PRODUCT = YES; 408 | }; 409 | name = Release; 410 | }; 411 | 808A860624AC0806008488E7 /* Debug */ = { 412 | isa = XCBuildConfiguration; 413 | baseConfigurationReference = 2A70025B666B761E85FA4123 /* Pods-VirtualClassroom.debug.xcconfig */; 414 | buildSettings = { 415 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 416 | CODE_SIGN_STYLE = Automatic; 417 | DEVELOPMENT_TEAM = FWD9V5VYJ2; 418 | INFOPLIST_FILE = VirtualClassroom/Info.plist; 419 | LD_RUNPATH_SEARCH_PATHS = ( 420 | "$(inherited)", 421 | "@executable_path/Frameworks", 422 | ); 423 | PRODUCT_BUNDLE_IDENTIFIER = so.cardo.VirtualClassroom; 424 | PRODUCT_NAME = "$(TARGET_NAME)"; 425 | SWIFT_VERSION = 5.0; 426 | TARGETED_DEVICE_FAMILY = "1,2"; 427 | }; 428 | name = Debug; 429 | }; 430 | 808A860724AC0806008488E7 /* Release */ = { 431 | isa = XCBuildConfiguration; 432 | baseConfigurationReference = DF102529EC3F070959A0AC7B /* Pods-VirtualClassroom.release.xcconfig */; 433 | buildSettings = { 434 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 435 | CODE_SIGN_STYLE = Automatic; 436 | DEVELOPMENT_TEAM = FWD9V5VYJ2; 437 | INFOPLIST_FILE = VirtualClassroom/Info.plist; 438 | LD_RUNPATH_SEARCH_PATHS = ( 439 | "$(inherited)", 440 | "@executable_path/Frameworks", 441 | ); 442 | PRODUCT_BUNDLE_IDENTIFIER = so.cardo.VirtualClassroom; 443 | PRODUCT_NAME = "$(TARGET_NAME)"; 444 | SWIFT_VERSION = 5.0; 445 | TARGETED_DEVICE_FAMILY = "1,2"; 446 | }; 447 | name = Release; 448 | }; 449 | /* End XCBuildConfiguration section */ 450 | 451 | /* Begin XCConfigurationList section */ 452 | 808A85EC24AC0805008488E7 /* Build configuration list for PBXProject "VirtualClassroom" */ = { 453 | isa = XCConfigurationList; 454 | buildConfigurations = ( 455 | 808A860324AC0806008488E7 /* Debug */, 456 | 808A860424AC0806008488E7 /* Release */, 457 | ); 458 | defaultConfigurationIsVisible = 0; 459 | defaultConfigurationName = Release; 460 | }; 461 | 808A860524AC0806008488E7 /* Build configuration list for PBXNativeTarget "VirtualClassroom" */ = { 462 | isa = XCConfigurationList; 463 | buildConfigurations = ( 464 | 808A860624AC0806008488E7 /* Debug */, 465 | 808A860724AC0806008488E7 /* Release */, 466 | ); 467 | defaultConfigurationIsVisible = 0; 468 | defaultConfigurationName = Release; 469 | }; 470 | /* End XCConfigurationList section */ 471 | }; 472 | rootObject = 808A85E924AC0805008488E7 /* Project object */; 473 | } 474 | -------------------------------------------------------------------------------- /VirtualClassroom.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /VirtualClassroom.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /VirtualClassroom.xcodeproj/xcuserdata/cardoso.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | VirtualClassroom.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 15 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /VirtualClassroom.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /VirtualClassroom.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /VirtualClassroom/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // VirtualClassroom 4 | // 5 | // Created by Matheus Cardoso on 30/06/20. 6 | // Copyright © 2020 Matheus Cardoso. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import StreamChatClient 11 | import VoxeetSDK 12 | import VoxeetUXKit 13 | 14 | @UIApplicationMain 15 | class AppDelegate: UIResponder, UIApplicationDelegate { 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | Client.configureShared(.init(apiKey: "74e5enp33qj2", logOptions: .info)) 19 | 20 | VoxeetSDK.shared.initialize(consumerKey: "ZTBib3I3NzkzMmt0aA==", consumerSecret: "NDUyM2kzMTc0ZHNvZWxjaHRucG41dmpidnE=") 21 | VoxeetUXKit.shared.initialize() 22 | 23 | return true 24 | } 25 | 26 | // MARK: UISceneSession Lifecycle 27 | 28 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 29 | // Called when a new scene session is being created. 30 | // Use this method to select a configuration to create the new scene with. 31 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 32 | } 33 | 34 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 35 | // Called when the user discards a scene session. 36 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 37 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 38 | } 39 | 40 | 41 | } 42 | 43 | -------------------------------------------------------------------------------- /VirtualClassroom/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 | -------------------------------------------------------------------------------- /VirtualClassroom/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /VirtualClassroom/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 | -------------------------------------------------------------------------------- /VirtualClassroom/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /VirtualClassroom/Class/ClassViewController+Call.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClassViewController+Call.swift 3 | // VirtualClassroom 4 | // 5 | // Created by Matheus Cardoso on 01/07/20. 6 | // Copyright © 2020 Matheus Cardoso. All rights reserved. 7 | // 8 | 9 | import VoxeetSDK 10 | import VoxeetUXKit 11 | 12 | extension ClassViewController { 13 | func startCall() { 14 | let options = VTConferenceOptions() 15 | options.alias = "history_class_id" 16 | VoxeetSDK.shared.conference.create(options: options, success: { conf in 17 | VoxeetSDK.shared.conference.join(conference: conf) 18 | }, fail: { error in 19 | print(error) 20 | }) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /VirtualClassroom/Class/ClassViewController+Chat.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClassViewController+Chat.swift 3 | // VirtualClassroom 4 | // 5 | // Created by Matheus Cardoso on 01/07/20. 6 | // Copyright © 2020 Matheus Cardoso. All rights reserved. 7 | // 8 | 9 | import StreamChatClient 10 | 11 | extension ClassViewController { 12 | func setupStudent() { 13 | Client.shared.set(user: student, token: .development) 14 | self.presenter = .init(channel: channel) 15 | } 16 | 17 | func setupTeacher() { 18 | Client.shared.set(user: teacher, token: .development) 19 | self.presenter = .init(channel: channel) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /VirtualClassroom/Class/ClassViewController+Handlers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChatViewController+Handlers.swift 3 | // VirtualClassroom 4 | // 5 | // Created by Matheus Cardoso on 01/07/20. 6 | // Copyright © 2020 Matheus Cardoso. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension ClassViewController { 12 | func setupHandlers() { 13 | setupCallButtonHandler() 14 | } 15 | 16 | func setupCallButtonHandler() { 17 | navigationItem.rightBarButtonItem?.target = self 18 | navigationItem.rightBarButtonItem?.action = #selector(callButtonPressed) 19 | } 20 | 21 | @objc func callButtonPressed() { 22 | startCall() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /VirtualClassroom/Class/ClassViewController+Views.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClassViewController+Views.swift 3 | // VirtualClassroom 4 | // 5 | // Created by Matheus Cardoso on 01/07/20. 6 | // Copyright © 2020 Matheus Cardoso. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension ClassViewController { 12 | func setupViews() { 13 | setupCallButton() 14 | } 15 | 16 | func setupCallButton() { 17 | let button = UIBarButtonItem() 18 | button.image = UIImage(systemName: "phone") 19 | 20 | navigationItem.rightBarButtonItem = button 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /VirtualClassroom/Class/ClassViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClassViewController.swift 3 | // VirtualClassroom 4 | // 5 | // Created by Matheus Cardoso on 01/07/20. 6 | // Copyright © 2020 Matheus Cardoso. All rights reserved. 7 | // 8 | 9 | import StreamChat 10 | import StreamChatClient 11 | 12 | class ClassViewController: ChatViewController { 13 | lazy var channel = Client.shared.channel( 14 | type: .messaging, 15 | id: "history_class_id", 16 | extraData: ChannelExtraData(name: "History Class", imageURL: nil) 17 | ) 18 | 19 | let student = User(id: .random()) 20 | let teacher = User( 21 | id: "teacher", 22 | extraData: UserExtraData( 23 | name: "Teacher", 24 | avatarURL: URL(string: "https://raw.githubusercontent.com/GetStream/edtech-classroom-app-ios/main/meta/teacher.png") 25 | ) 26 | ) 27 | 28 | override func viewDidLoad() { 29 | super.viewDidLoad() 30 | 31 | setupViews() 32 | setupHandlers() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /VirtualClassroom/Extensions/String+Random.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+Random.swift 3 | // VirtualClassroom 4 | // 5 | // Created by Matheus Cardoso on 02/07/20. 6 | // Copyright © 2020 Matheus Cardoso. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension String { 12 | static func random(length: Int = 10) -> String { 13 | let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 14 | return String((0.. 2 | 3 | 4 | 5 | NSMicrophoneUsageDescription 6 | This app needs to use the microphone 7 | NSCameraUsageDescription 8 | This app needs to use the camera 9 | CFBundleDevelopmentRegion 10 | $(DEVELOPMENT_LANGUAGE) 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | $(PRODUCT_NAME) 19 | CFBundlePackageType 20 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | UIApplicationSceneManifest 28 | 29 | UIApplicationSupportsMultipleScenes 30 | 31 | UISceneConfigurations 32 | 33 | UIWindowSceneSessionRoleApplication 34 | 35 | 36 | UISceneConfigurationName 37 | Default Configuration 38 | UISceneDelegateClassName 39 | $(PRODUCT_MODULE_NAME).SceneDelegate 40 | UISceneStoryboardFile 41 | Main 42 | 43 | 44 | 45 | 46 | UILaunchStoryboardName 47 | LaunchScreen 48 | UIMainStoryboardFile 49 | Main 50 | UIRequiredDeviceCapabilities 51 | 52 | armv7 53 | 54 | UISupportedInterfaceOrientations 55 | 56 | UIInterfaceOrientationPortrait 57 | UIInterfaceOrientationLandscapeLeft 58 | UIInterfaceOrientationLandscapeRight 59 | 60 | UISupportedInterfaceOrientations~ipad 61 | 62 | UIInterfaceOrientationPortrait 63 | UIInterfaceOrientationPortraitUpsideDown 64 | UIInterfaceOrientationLandscapeLeft 65 | UIInterfaceOrientationLandscapeRight 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /VirtualClassroom/Join/JoinViewController+Constraints.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JoinViewController+Constraints.swift 3 | // VirtualClassroom 4 | // 5 | // Created by Matheus Cardoso on 01/07/20. 6 | // Copyright © 2020 Matheus Cardoso. All rights reserved. 7 | // 8 | 9 | extension JoinViewController { 10 | func setupConstraints() { 11 | view.addConstraints([ 12 | studentButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), 13 | studentButton.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor, constant: -100), 14 | teacherButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), 15 | teacherButton.centerYAnchor.constraint(equalTo: studentButton.centerYAnchor, constant: 100) 16 | ]) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /VirtualClassroom/Join/JoinViewController+Handlers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JoinViewController+Handlers.swift 3 | // VirtualClassroom 4 | // 5 | // Created by Matheus Cardoso on 01/07/20. 6 | // Copyright © 2020 Matheus Cardoso. All rights reserved. 7 | // 8 | 9 | import StreamChat 10 | 11 | extension JoinViewController { 12 | func setupHandlers() { 13 | studentButton.addTarget(self, action: #selector(handleStudentButtonPress), for: .touchUpInside) 14 | teacherButton.addTarget(self, action: #selector(handleTeacherButtonPress), for: .touchUpInside) 15 | } 16 | 17 | @objc func handleStudentButtonPress() { 18 | let classVC = ClassViewController() 19 | classVC.setupStudent() 20 | 21 | navigationController?.pushViewController(classVC, animated: true) 22 | } 23 | 24 | @objc func handleTeacherButtonPress() { 25 | let classVC = ClassViewController() 26 | classVC.setupTeacher() 27 | 28 | navigationController?.pushViewController(classVC, animated: true) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /VirtualClassroom/Join/JoinViewController+Views.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JoinViewController+Views.swift 3 | // VirtualClassroom 4 | // 5 | // Created by Matheus Cardoso on 01/07/20. 6 | // Copyright © 2020 Matheus Cardoso. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension JoinViewController { 12 | func setupViews() { 13 | setupStudentButton() 14 | setupTeacherButton() 15 | } 16 | 17 | func setupStudentButton() { 18 | studentButton.translatesAutoresizingMaskIntoConstraints = false 19 | studentButton.setTitleColor(.systemBlue, for: .normal) 20 | studentButton.setTitle("Student 👨‍🎓", for: .normal) 21 | studentButton.titleLabel?.font = .systemFont(ofSize: 32) 22 | 23 | view.addSubview(studentButton) 24 | } 25 | 26 | func setupTeacherButton() { 27 | teacherButton.translatesAutoresizingMaskIntoConstraints = false 28 | teacherButton.setTitleColor(.systemBlue, for: .normal) 29 | teacherButton.setTitle("Teacher 👩‍🏫", for: .normal) 30 | teacherButton.titleLabel?.font = .systemFont(ofSize: 32) 31 | 32 | view.addSubview(teacherButton) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /VirtualClassroom/Join/JoinViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JoinViewController.swift 3 | // VirtualClassroom 4 | // 5 | // Created by Matheus Cardoso on 30/06/20. 6 | // Copyright © 2020 Matheus Cardoso. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class JoinViewController: UIViewController { 12 | let studentButton = UIButton() 13 | let teacherButton = UIButton() 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | title = "Join" 19 | 20 | setupViews() 21 | setupConstraints() 22 | setupHandlers() 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /VirtualClassroom/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // VirtualClassroom 4 | // 5 | // Created by Matheus Cardoso on 30/06/20. 6 | // Copyright © 2020 Matheus Cardoso. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 12 | 13 | var window: UIWindow? 14 | 15 | 16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 17 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 18 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 19 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 20 | guard let _ = (scene as? UIWindowScene) else { return } 21 | } 22 | 23 | func sceneDidDisconnect(_ scene: UIScene) { 24 | // Called as the scene is being released by the system. 25 | // This occurs shortly after the scene enters the background, or when its session is discarded. 26 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 27 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). 28 | } 29 | 30 | func sceneDidBecomeActive(_ scene: UIScene) { 31 | // Called when the scene has moved from an inactive state to an active state. 32 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 33 | } 34 | 35 | func sceneWillResignActive(_ scene: UIScene) { 36 | // Called when the scene will move from an active state to an inactive state. 37 | // This may occur due to temporary interruptions (ex. an incoming phone call). 38 | } 39 | 40 | func sceneWillEnterForeground(_ scene: UIScene) { 41 | // Called as the scene transitions from the background to the foreground. 42 | // Use this method to undo the changes made on entering the background. 43 | } 44 | 45 | func sceneDidEnterBackground(_ scene: UIScene) { 46 | // Called as the scene transitions from the foreground to the background. 47 | // Use this method to save data, release shared resources, and store enough scene-specific state information 48 | // to restore the scene back to its current state. 49 | } 50 | 51 | 52 | } 53 | 54 | -------------------------------------------------------------------------------- /meta/teacher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GetStream/edtech-classroom-app-ios/763793832ffb79403ba60c3e9d3c61c5a05f9014/meta/teacher.png --------------------------------------------------------------------------------