Compare commits
7 commits
master
...
iOS-17-Upd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e2ee8733b | ||
|
|
51e7ef0573 | ||
|
|
2ecc9a2ec9 | ||
|
|
0646453175 | ||
|
|
a34e2bf6d3 | ||
|
|
e5bb6df771 | ||
|
|
976bf512fa |
80 changed files with 976 additions and 1297 deletions
|
|
@ -98,7 +98,7 @@ public class FileTransferClient {
|
|||
// Set current peripheral
|
||||
self.blePeripheral = blePeripheral
|
||||
|
||||
// Setup services
|
||||
// Setup servic*es
|
||||
let servicesGroup = DispatchGroup()
|
||||
|
||||
var error: Error? = nil
|
||||
|
|
|
|||
|
|
@ -3,19 +3,19 @@
|
|||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 52;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
D505B99C2755323C00386E9F /* NetworkMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D505B99B2755323C00386E9F /* NetworkMonitor.swift */; };
|
||||
D505B99E2756894300386E9F /* ViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D505B99D2756894300386E9F /* ViewModifier.swift */; };
|
||||
D50887632A2E35510002B798 /* Wifi_ifaddrs.m in Sources */ = {isa = PBXBuildFile; fileRef = D50887622A2E35510002B798 /* Wifi_ifaddrs.m */; };
|
||||
D517F68126C5771D002996E8 /* FillerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D517F68026C5771D002996E8 /* FillerView.swift */; };
|
||||
D5199A2F28DD16F100ACC34C /* BleContentTransfer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5199A2E28DD16F100ACC34C /* BleContentTransfer.swift */; };
|
||||
D51D1413293A53BD0028AEDD /* WifiCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D51D1412293A53BD0028AEDD /* WifiCellViewModel.swift */; };
|
||||
D520D69029D4C9380022048D /* WifiServiceCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D520D68F29D4C9380022048D /* WifiServiceCellView.swift */; };
|
||||
D520D69229D4C9900022048D /* WifiServiceCellSubView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D520D69129D4C9900022048D /* WifiServiceCellSubView.swift */; };
|
||||
D5267411292E902700D4C79E /* Networking.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5267410292E902700D4C79E /* Networking.swift */; };
|
||||
D5269C00291960A300C0CE4B /* WifiSelection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5269BFF291960A300C0CE4B /* WifiSelection.swift */; };
|
||||
D5269C02291997DE00C0CE4B /* WifiServiceCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5269C01291997DE00C0CE4B /* WifiServiceCellView.swift */; };
|
||||
D5269C042919985400C0CE4B /* WifiServiceCellSubView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5269C032919985400C0CE4B /* WifiServiceCellSubView.swift */; };
|
||||
D5269C08291AB75800C0CE4B /* WifiPairingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5269C07291AB75800C0CE4B /* WifiPairingView.swift */; };
|
||||
D52A926D29071DF400973B6B /* SelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D52A926C29071DF400973B6B /* SelectionView.swift */; };
|
||||
D52A926F29078E0A00973B6B /* WifiServiceSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D52A926E29078E0A00973B6B /* WifiServiceSelectionView.swift */; };
|
||||
|
|
@ -68,7 +68,6 @@
|
|||
D58D887B26CC02B60085604A /* OnboardingViewPure.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58D887A26CC02B60085604A /* OnboardingViewPure.swift */; };
|
||||
D58E1C8828A2B10B00AB683E /* WifiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58E1C8728A2B10B00AB683E /* WifiView.swift */; };
|
||||
D58E1C8A28A2B15E00AB683E /* WifiViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58E1C8928A2B15E00AB683E /* WifiViewModel.swift */; };
|
||||
D58E1C8D28A2B32C00AB683E /* Wifi_ifaddrs.m in Sources */ = {isa = PBXBuildFile; fileRef = D58E1C8C28A2B32C00AB683E /* Wifi_ifaddrs.m */; };
|
||||
D58E1C8F28A30A5300AB683E /* WifiNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58E1C8E28A30A5300AB683E /* WifiNetworkService.swift */; };
|
||||
D595FC2E2812C23D00569D8C /* Image Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D595FC2D2812C23D00569D8C /* Image Extension.swift */; };
|
||||
D59DFD8F268A4A4D001737F6 /* BTConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59DFD8E268A4A4D001737F6 /* BTConnectionView.swift */; };
|
||||
|
|
@ -84,6 +83,8 @@
|
|||
D5BA1F7F28B66F280012FC62 /* WifiServiceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5BA1F7E28B66F280012FC62 /* WifiServiceManager.swift */; };
|
||||
D5BA1F8128B66F920012FC62 /* CircuitPythonService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5BA1F8028B66F920012FC62 /* CircuitPythonService.swift */; };
|
||||
D5BA1F8328B68ED40012FC62 /* NetworkPeripheral.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5BA1F8228B68ED40012FC62 /* NetworkPeripheral.swift */; };
|
||||
D5BBD12C2A1538C100961B68 /* BoardDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5BBD12B2A1538C100961B68 /* BoardDataProvider.swift */; };
|
||||
D5BBD12E2A1C6AB300961B68 /* BleBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5BBD12D2A1C6AB300961B68 /* BleBannerView.swift */; };
|
||||
D5C474AC27E174A5002DD160 /* WebView Content.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5C474AB27E174A5002DD160 /* WebView Content.swift */; };
|
||||
D5C474C827E39FD7002DD160 /* ReadexPro-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D5C474C627E39FC8002DD160 /* ReadexPro-Medium.ttf */; };
|
||||
D5C474C927E39FDA002DD160 /* ReadexPro-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = D5C474C727E39FC8002DD160 /* ReadexPro-Regular.ttf */; };
|
||||
|
|
@ -116,13 +117,14 @@
|
|||
D50237E3280994F900F1EE8A /* PyLeap.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = PyLeap.entitlements; path = "../../../../Desktop/Copy Of PyLeap Entitlement/PyLeap.entitlements"; sourceTree = "<group>"; };
|
||||
D505B99B2755323C00386E9F /* NetworkMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitor.swift; sourceTree = "<group>"; };
|
||||
D505B99D2756894300386E9F /* ViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModifier.swift; sourceTree = "<group>"; };
|
||||
D50887612A2E35490002B798 /* PyLeap-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PyLeap-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
D50887622A2E35510002B798 /* Wifi_ifaddrs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Wifi_ifaddrs.m; sourceTree = "<group>"; };
|
||||
D517F68026C5771D002996E8 /* FillerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FillerView.swift; sourceTree = "<group>"; };
|
||||
D5199A2E28DD16F100ACC34C /* BleContentTransfer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BleContentTransfer.swift; sourceTree = "<group>"; };
|
||||
D51D1412293A53BD0028AEDD /* WifiCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiCellViewModel.swift; sourceTree = "<group>"; };
|
||||
D520D68F29D4C9380022048D /* WifiServiceCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiServiceCellView.swift; sourceTree = "<group>"; };
|
||||
D520D69129D4C9900022048D /* WifiServiceCellSubView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiServiceCellSubView.swift; sourceTree = "<group>"; };
|
||||
D5267410292E902700D4C79E /* Networking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Networking.swift; sourceTree = "<group>"; };
|
||||
D5269BFF291960A300C0CE4B /* WifiSelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WifiSelection.swift; path = "PyLeap/Views/Unpaired View/WifiSelection.swift"; sourceTree = SOURCE_ROOT; };
|
||||
D5269C01291997DE00C0CE4B /* WifiServiceCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WifiServiceCellView.swift; path = ../../../../../../Desktop/WifiServiceCellView.swift; sourceTree = "<group>"; };
|
||||
D5269C032919985400C0CE4B /* WifiServiceCellSubView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WifiServiceCellSubView.swift; path = ../../../../../../Desktop/WifiServiceCellSubView.swift; sourceTree = "<group>"; };
|
||||
D5269C07291AB75800C0CE4B /* WifiPairingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiPairingView.swift; sourceTree = "<group>"; };
|
||||
D52A926C29071DF400973B6B /* SelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectionView.swift; sourceTree = "<group>"; };
|
||||
D52A926E29078E0A00973B6B /* WifiServiceSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiServiceSelectionView.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -177,7 +179,6 @@
|
|||
D58D887A26CC02B60085604A /* OnboardingViewPure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewPure.swift; sourceTree = "<group>"; };
|
||||
D58E1C8728A2B10B00AB683E /* WifiView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiView.swift; sourceTree = "<group>"; };
|
||||
D58E1C8928A2B15E00AB683E /* WifiViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiViewModel.swift; sourceTree = "<group>"; };
|
||||
D58E1C8C28A2B32C00AB683E /* Wifi_ifaddrs.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Wifi_ifaddrs.m; sourceTree = "<group>"; };
|
||||
D58E1C8E28A30A5300AB683E /* WifiNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiNetworkService.swift; sourceTree = "<group>"; };
|
||||
D595FC2D2812C23D00569D8C /* Image Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Image Extension.swift"; sourceTree = "<group>"; };
|
||||
D59DFD8E268A4A4D001737F6 /* BTConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTConnectionView.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -194,6 +195,8 @@
|
|||
D5BA1F7E28B66F280012FC62 /* WifiServiceManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiServiceManager.swift; sourceTree = "<group>"; };
|
||||
D5BA1F8028B66F920012FC62 /* CircuitPythonService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircuitPythonService.swift; sourceTree = "<group>"; };
|
||||
D5BA1F8228B68ED40012FC62 /* NetworkPeripheral.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkPeripheral.swift; sourceTree = "<group>"; };
|
||||
D5BBD12B2A1538C100961B68 /* BoardDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoardDataProvider.swift; sourceTree = "<group>"; };
|
||||
D5BBD12D2A1C6AB300961B68 /* BleBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BleBannerView.swift; sourceTree = "<group>"; };
|
||||
D5C474AB27E174A5002DD160 /* WebView Content.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WebView Content.swift"; sourceTree = "<group>"; };
|
||||
D5C474C227E39FAD002DD160 /* ReadexPro-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "ReadexPro-Bold.ttf"; sourceTree = "<group>"; };
|
||||
D5C474C527E39FC8002DD160 /* ReadexPro-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "ReadexPro-Light.ttf"; sourceTree = "<group>"; };
|
||||
|
|
@ -218,7 +221,6 @@
|
|||
D5DD39A628D11817000FAEB8 /* WifiFileTransfer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiFileTransfer.swift; sourceTree = "<group>"; };
|
||||
D5DD39A828D11962000FAEB8 /* WifiTransferService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiTransferService.swift; sourceTree = "<group>"; };
|
||||
D5DD39AA28D234C3000FAEB8 /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = "<group>"; };
|
||||
D5ECF4B828C8E3C600FBF93D /* PyLeap-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PyLeap-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
D5F53CEA2694B524007634C2 /* Blinka Animation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Blinka Animation.swift"; sourceTree = "<group>"; };
|
||||
D5F53CEC2694B7A9007634C2 /* OnboardingBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingBackgroundView.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
|
@ -278,9 +280,11 @@
|
|||
D59DFDB5268CD052001737F6 /* AppEnvironment.swift */,
|
||||
D534F3FB280B59090053699C /* ExampleView.swift */,
|
||||
D544A2502822D4730038D483 /* Spotlight Extension.swift */,
|
||||
D5BBD12A2A15389400961B68 /* Helpers */,
|
||||
D567E2B428B80DC10009F768 /* Outline.md */,
|
||||
D567E2DD28C8D3E20009F768 /* SettingsView */,
|
||||
D5C74DF027EB92E900730505 /* Model */,
|
||||
D59DFDB2268CCEAC001737F6 /* Views */,
|
||||
D59DFDB2268CCEAC001737F6 /* Features */,
|
||||
D5C74DEE27EB91D600730505 /* Networking */,
|
||||
D5C74DED27EB919200730505 /* Resource */,
|
||||
D5C41D6726C5F509004C38E3 /* Download View */,
|
||||
|
|
@ -376,23 +380,29 @@
|
|||
path = BLESetttings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D58E1C8628A2B0DE00AB683E /* Wifi View */ = {
|
||||
D56FFE1C2A2A4ED500EF1E3B /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D567E2DD28C8D3E20009F768 /* SettingsView */,
|
||||
D58E1C8728A2B10B00AB683E /* WifiView.swift */,
|
||||
D567E2B728C137880009F768 /* WifiCell.swift */,
|
||||
D51D1412293A53BD0028AEDD /* WifiCellViewModel.swift */,
|
||||
D567E2B928C1382E0009F768 /* WifiSubViewCell.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D58E1C8628A2B0DE00AB683E /* Wifi Module */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D56FFE1C2A2A4ED500EF1E3B /* Views */,
|
||||
D51D1412293A53BD0028AEDD /* WifiCellViewModel.swift */,
|
||||
D58E1C8928A2B15E00AB683E /* WifiViewModel.swift */,
|
||||
D5269C07291AB75800C0CE4B /* WifiPairingView.swift */,
|
||||
D52A926E29078E0A00973B6B /* WifiServiceSelectionView.swift */,
|
||||
D5269BFF291960A300C0CE4B /* WifiSelection.swift */,
|
||||
D5269C01291997DE00C0CE4B /* WifiServiceCellView.swift */,
|
||||
D5269C032919985400C0CE4B /* WifiServiceCellSubView.swift */,
|
||||
D520D68F29D4C9380022048D /* WifiServiceCellView.swift */,
|
||||
D5BA1F7E28B66F280012FC62 /* WifiServiceManager.swift */,
|
||||
D5DD39A628D11817000FAEB8 /* WifiFileTransfer.swift */,
|
||||
D5DD39A828D11962000FAEB8 /* WifiTransferService.swift */,
|
||||
D520D69129D4C9900022048D /* WifiServiceCellSubView.swift */,
|
||||
D5AA27F728CA785B001CCE25 /* CircuitPythonType.swift */,
|
||||
D5482F4A28E75053000B0C8E /* LocalNetworkAuth.swift */,
|
||||
D5AA27F928CA8D46001CCE25 /* WifiStatusHeaderBarView.swift */,
|
||||
|
|
@ -402,17 +412,17 @@
|
|||
D5BA1F8028B66F920012FC62 /* CircuitPythonService.swift */,
|
||||
D58E1C8E28A30A5300AB683E /* WifiNetworkService.swift */,
|
||||
D5BA1F8228B68ED40012FC62 /* NetworkPeripheral.swift */,
|
||||
D50887622A2E35510002B798 /* Wifi_ifaddrs.m */,
|
||||
D50887612A2E35490002B798 /* PyLeap-Bridging-Header.h */,
|
||||
D5D7DF2A28B3E321008552D1 /* BasicCredentials.swift */,
|
||||
D58E1C8C28A2B32C00AB683E /* Wifi_ifaddrs.m */,
|
||||
D5ECF4B828C8E3C600FBF93D /* PyLeap-Bridging-Header.h */,
|
||||
);
|
||||
path = "Wifi View";
|
||||
path = "Wifi Module";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D59DFDB2268CCEAC001737F6 /* Views */ = {
|
||||
D59DFDB2268CCEAC001737F6 /* Features */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D58E1C8628A2B0DE00AB683E /* Wifi View */,
|
||||
D58E1C8628A2B0DE00AB683E /* Wifi Module */,
|
||||
D5507ACE26C668BC00512BAA /* UI Components */,
|
||||
D59DFDB3268CCEB9001737F6 /* Onboarding Views */,
|
||||
D5C474AA27E1746F002DD160 /* WebView */,
|
||||
|
|
@ -424,7 +434,7 @@
|
|||
D517F68026C5771D002996E8 /* FillerView.swift */,
|
||||
D5D1F4AC27ECFD200040E2BF /* Startup View */,
|
||||
);
|
||||
path = Views;
|
||||
path = Features;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D59DFDB3268CCEB9001737F6 /* Onboarding Views */ = {
|
||||
|
|
@ -438,6 +448,14 @@
|
|||
path = "Onboarding Views";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D5BBD12A2A15389400961B68 /* Helpers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D5BBD12B2A1538C100961B68 /* BoardDataProvider.swift */,
|
||||
);
|
||||
path = Helpers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D5C41D6726C5F509004C38E3 /* Download View */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -535,6 +553,7 @@
|
|||
children = (
|
||||
D59E31A9281B8DD300D24211 /* DownloadState.swift */,
|
||||
D5507ACB26C668BC00512BAA /* BleModuleView.swift */,
|
||||
D5BBD12D2A1C6AB300961B68 /* BleBannerView.swift */,
|
||||
D5507ACC26C668BC00512BAA /* BleModuleViewModel.swift */,
|
||||
D5199A2E28DD16F100ACC34C /* BleContentTransfer.swift */,
|
||||
D5D5BB3828DD19F000E5D93F /* BleContentCommands.swift */,
|
||||
|
|
@ -605,8 +624,9 @@
|
|||
D52F7E682672F4C400911D43 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastSwiftUpdateCheck = 1250;
|
||||
LastUpgradeCheck = 1250;
|
||||
LastUpgradeCheck = 1500;
|
||||
TargetAttributes = {
|
||||
D52F7E6F2672F4C400911D43 = {
|
||||
CreatedOnToolsVersion = 12.5;
|
||||
|
|
@ -659,6 +679,7 @@
|
|||
D5D1F4B827ED2F4F0040E2BF /* FileManagerCheck.swift in Sources */,
|
||||
D52BE82A26A0660200630900 /* KeyboardUtils.swift in Sources */,
|
||||
D58182FB27F732E40091C43B /* SubCellViewModel.swift in Sources */,
|
||||
D520D69229D4C9900022048D /* WifiServiceCellSubView.swift in Sources */,
|
||||
D5D5BB3928DD19F000E5D93F /* BleContentCommands.swift in Sources */,
|
||||
D544A1D2281B9BB70038D483 /* Buttons.swift in Sources */,
|
||||
D5D1F4AE27ECFDA10040E2BF /* GifImage.swift in Sources */,
|
||||
|
|
@ -678,9 +699,9 @@
|
|||
D56F640C270242CA000E5975 /* UIColor+LightAndDark.swift in Sources */,
|
||||
D5F53CED2694B7A9007634C2 /* OnboardingBackgroundView.swift in Sources */,
|
||||
D5D1F4B227ECFF760040E2BF /* ProjectsModel.swift in Sources */,
|
||||
D5269C02291997DE00C0CE4B /* WifiServiceCellView.swift in Sources */,
|
||||
D5BA1F7A28B52A490012FC62 /* WifiListDetailView.swift in Sources */,
|
||||
D52F7E742672F4C400911D43 /* PyLeapApp.swift in Sources */,
|
||||
D5BBD12E2A1C6AB300961B68 /* BleBannerView.swift in Sources */,
|
||||
D567E2B628B81B730009F768 /* Queue.swift in Sources */,
|
||||
D534F3FC280B59090053699C /* ExampleView.swift in Sources */,
|
||||
D57858ED28327E18008E8BE4 /* PairingTutorialView.swift in Sources */,
|
||||
|
|
@ -702,7 +723,6 @@
|
|||
D5DD39A728D11817000FAEB8 /* WifiFileTransfer.swift in Sources */,
|
||||
D5AA27FA28CA8D46001CCE25 /* WifiStatusHeaderBarView.swift in Sources */,
|
||||
D5F53CEB2694B524007634C2 /* Blinka Animation.swift in Sources */,
|
||||
D5269C00291960A300C0CE4B /* WifiSelection.swift in Sources */,
|
||||
D5597BF826A9E14B00DF17C0 /* AppDelegate.swift in Sources */,
|
||||
D56F640E270242CA000E5975 /* String+DeletingPrefix.swift in Sources */,
|
||||
D57858F328333CBC008E8BE4 /* TroubleshootView.swift in Sources */,
|
||||
|
|
@ -739,18 +759,19 @@
|
|||
D567E2B828C137880009F768 /* WifiCell.swift in Sources */,
|
||||
D5D1F4B027ECFDE00040E2BF /* NavBarModifier.swift in Sources */,
|
||||
D5597C0C26AF018800DF17C0 /* View+If.swift in Sources */,
|
||||
D58E1C8D28A2B32C00AB683E /* Wifi_ifaddrs.m in Sources */,
|
||||
D56B75D4294BAAB400D008E7 /* BLESettingsView.swift in Sources */,
|
||||
D50887632A2E35510002B798 /* Wifi_ifaddrs.m in Sources */,
|
||||
D52BE7EE269DF36E00630900 /* DownloadViewModel.swift in Sources */,
|
||||
D59E31AA281B8DD300D24211 /* DownloadState.swift in Sources */,
|
||||
D520D69029D4C9380022048D /* WifiServiceCellView.swift in Sources */,
|
||||
D5BA1F7F28B66F280012FC62 /* WifiServiceManager.swift in Sources */,
|
||||
D5C74DF327EB92FA00730505 /* View+Extensions.swift in Sources */,
|
||||
D5AA27F828CA785B001CCE25 /* CircuitPythonType.swift in Sources */,
|
||||
D5199A2F28DD16F100ACC34C /* BleContentTransfer.swift in Sources */,
|
||||
D535E21628E1FA910096E548 /* ScrollRefreshableView.swift in Sources */,
|
||||
D5640216271B54BF00AE1519 /* MainSelectionView.swift in Sources */,
|
||||
D5269C042919985400C0CE4B /* WifiServiceCellSubView.swift in Sources */,
|
||||
D505B99C2755323C00386E9F /* NetworkMonitor.swift in Sources */,
|
||||
D5BBD12C2A1538C100961B68 /* BoardDataProvider.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -794,6 +815,7 @@
|
|||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
|
|
@ -808,7 +830,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
|
|
@ -855,6 +877,7 @@
|
|||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
|
|
@ -863,7 +886,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
|
|
@ -881,22 +904,22 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = PyLeap/PyLeap.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 0;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"PyLeap/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = 2X94RM7457;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = PyLeap/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.5;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.1.1;
|
||||
MARKETING_VERSION = 2.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.adafruit.PyLeap;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "PyLeap/Views/Wifi View/PyLeap-Bridging-Header.h";
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
|
|
@ -911,22 +934,22 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = PyLeap/PyLeap.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 0;
|
||||
CURRENT_PROJECT_VERSION = 2;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"PyLeap/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = 2X94RM7457;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = PyLeap/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.5;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.1.1;
|
||||
MARKETING_VERSION = 2.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.adafruit.PyLeap;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "PyLeap/Views/Wifi View/PyLeap-Bridging-Header.h";
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1320"
|
||||
LastUpgradeVersion = "1500"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
|||
21
PyLeap/Assets.xcassets/Placeholder Board Image.imageset/Contents.json
vendored
Normal file
21
PyLeap/Assets.xcassets/Placeholder Board Image.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Default device image.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
PyLeap/Assets.xcassets/Placeholder Board Image.imageset/Default device image.png
vendored
Normal file
BIN
PyLeap/Assets.xcassets/Placeholder Board Image.imageset/Default device image.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
47
PyLeap/Features/Paired View/BleBannerView.swift
Normal file
47
PyLeap/Features/Paired View/BleBannerView.swift
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// BleBannerView.swift
|
||||
// PyLeap
|
||||
//
|
||||
// Created by Trevor Beaton on 5/22/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct BleBannerView: View {
|
||||
var deviceName: String
|
||||
var disconnectAction: () -> Void
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack {
|
||||
Image("bluetoothLogo")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 16, height: 16)
|
||||
|
||||
Text(deviceName)
|
||||
.font(Font.custom("ReadexPro-Regular", size: 14))
|
||||
|
||||
Button(action: disconnectAction) {
|
||||
Text("Disconnect")
|
||||
.font(Font.custom("ReadexPro-Bold", size: 14))
|
||||
.underline()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// .background(GeometryReader {
|
||||
// Color.clear.preference(key: ViewHeightKey.self,
|
||||
// value: $0.frame(in: .local).size.height)
|
||||
// })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct BleBannerView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
BleBannerView(deviceName: "Test", disconnectAction: {
|
||||
print("Dismiss Action")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -13,8 +13,8 @@ class BleContentCommands: ObservableObject {
|
|||
|
||||
private weak var fileTransferClient: FileTransferClient?
|
||||
@Published var transmissionProgress: TransmissionProgress?
|
||||
|
||||
@Published var isTransmiting = false
|
||||
@Published var bootUpInfo = String()
|
||||
@Published var counter = 0
|
||||
|
||||
enum ProjectViewError: LocalizedError {
|
||||
|
|
@ -63,7 +63,6 @@ class BleContentCommands: ObservableObject {
|
|||
@Published var lastTransmit: TransmissionLog? = TransmissionLog(type: .write(size: 334))
|
||||
|
||||
|
||||
@Published var activeAlert: ActiveAlert?
|
||||
|
||||
// Data
|
||||
private let bleManager = BleManager.shared
|
||||
|
|
@ -103,9 +102,6 @@ class BleContentCommands: ObservableObject {
|
|||
self.lastTransmit = TransmissionLog(type: .read(data: data))
|
||||
let str = String(decoding: data, as: UTF8.self)
|
||||
print("Read: \(str)")
|
||||
self.bootUpInfo = str
|
||||
sharedBootinfo = str
|
||||
|
||||
|
||||
case .failure(let error):
|
||||
self.lastTransmit = TransmissionLog(type: .error(message: error.localizedDescription))
|
||||
|
|
@ -8,7 +8,24 @@
|
|||
import SwiftUI
|
||||
import FileTransferClient
|
||||
|
||||
class BleContentTransfer: ObservableObject {
|
||||
protocol BoardInfoDelegate: AnyObject {
|
||||
func boardInfoDidUpdate(to newBoard: Board?)
|
||||
}
|
||||
|
||||
enum ListCommandError: Error {
|
||||
case belowMinimum
|
||||
case isPrime
|
||||
}
|
||||
|
||||
class BleContentTransfer: ObservableObject, BoardInfoDelegate {
|
||||
|
||||
@Published var currentBoard: Board? {
|
||||
didSet {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static let shared = BleContentTransfer()
|
||||
|
||||
private weak var fileTransferClient: FileTransferClient?
|
||||
|
||||
|
|
@ -22,7 +39,6 @@ class BleContentTransfer: ObservableObject {
|
|||
|
||||
@Published var downloadState: DownloadState = .idle
|
||||
|
||||
@State var circuitPythonVersion = String()
|
||||
|
||||
@Published var isTransmiting = false
|
||||
|
||||
|
|
@ -32,18 +48,13 @@ class BleContentTransfer: ObservableObject {
|
|||
|
||||
@Published var downloaderror = false
|
||||
|
||||
@Published var bootUpInfo = ""
|
||||
|
||||
|
||||
|
||||
@Published var contentCommands = BleContentCommands()
|
||||
// CLEAN UP
|
||||
var projectDirectories: [URL] = []
|
||||
var projectFiles: [URL] = []
|
||||
var returnedArray = [[String]]()
|
||||
var fileTransferArray : [URL] = []
|
||||
|
||||
var filesReadyForTransfer : [URL] = []
|
||||
|
||||
@Published var sendingBundle = false
|
||||
@Published var didCompleteTranfer = false
|
||||
|
|
@ -58,10 +69,12 @@ class BleContentTransfer: ObservableObject {
|
|||
@Published var isConnectedToInternet = false
|
||||
@Published var showAlert = false
|
||||
|
||||
var downloadPhases: String = ""
|
||||
|
||||
let directoryPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
|
||||
func boardInfoDidUpdate(to newBoard: Board?) {
|
||||
self.currentBoard = newBoard
|
||||
// Add any other logic you need to handle the new board here.
|
||||
}
|
||||
|
||||
enum ProjectViewError: LocalizedError {
|
||||
case fileTransferUndefined
|
||||
|
|
@ -77,25 +90,9 @@ class BleContentTransfer: ObservableObject {
|
|||
}
|
||||
|
||||
init() {
|
||||
getCPVersion()
|
||||
registerNotification(enabled: true)
|
||||
}
|
||||
|
||||
func getCPVersion() {
|
||||
if sharedBootinfo.contains("CircuitPython 7") {
|
||||
print("circuitPythonVersion = 7")
|
||||
circuitPythonVersion = "7"
|
||||
print(circuitPythonVersion)
|
||||
}
|
||||
|
||||
if sharedBootinfo.contains("CircuitPython 8") {
|
||||
print("circuitPythonVersion = 8")
|
||||
circuitPythonVersion = "8"
|
||||
print(circuitPythonVersion)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private weak var didCompleteZip: NSObjectProtocol?
|
||||
private weak var didEncounterTransferError: NSObjectProtocol?
|
||||
private weak var downloadErrorDidOccur: NSObjectProtocol?
|
||||
|
|
@ -311,13 +308,6 @@ class BleContentTransfer: ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// filterCPVersion(incomingArray: regularFileUrls)
|
||||
// filterCPFiles(filesArray: regularFileUrls)
|
||||
|
||||
|
||||
// pathManipulation(arrayOfAny: filterCPVersion(incomingArray: projectDirectories), regularArray: filterCPVersion(incomingArray: projectFiles))
|
||||
|
||||
projectDirectories.removeFirst()
|
||||
|
||||
DispatchQueue.main.async {
|
||||
|
|
@ -336,57 +326,19 @@ class BleContentTransfer: ObservableObject {
|
|||
|
||||
|
||||
func filterCPVersion(incomingArray: [URL]) -> [URL] {
|
||||
print("project name \(projectName)")
|
||||
|
||||
|
||||
for i in incomingArray {
|
||||
print("incoming Array \(i.absoluteString)")
|
||||
let filteredList = incomingArray.filter {
|
||||
let lastPathComponent = $0.lastPathComponent
|
||||
return lastPathComponent != "CircuitPython 8.x"
|
||||
&& lastPathComponent != "CircuitPython 7.x"
|
||||
&& lastPathComponent != "CircuitPython_Templates"
|
||||
}
|
||||
|
||||
|
||||
|
||||
let listWithoutCP8Folder = incomingArray.filter {
|
||||
$0.lastPathComponent != ("CircuitPython 8.x")
|
||||
}
|
||||
|
||||
let listWithoutCP7Folder = listWithoutCP8Folder.filter {
|
||||
$0.lastPathComponent != ("CircuitPython 7.x")
|
||||
}
|
||||
|
||||
//CircuitPython_Templates
|
||||
|
||||
let removedCPTemplates = listWithoutCP7Folder.filter {
|
||||
$0.lastPathComponent != ("CircuitPython_Templates")
|
||||
|
||||
}
|
||||
|
||||
|
||||
if sharedBootinfo.contains("CircuitPython 8") {
|
||||
let listForCurrentCPVersion = removedCPTemplates.filter {
|
||||
!$0.absoluteString.contains("CircuitPython%207.x")
|
||||
}
|
||||
|
||||
for i in listForCurrentCPVersion {
|
||||
print("listForCurrentCPVersion :- \(i.absoluteString)")
|
||||
let listForCurrentCPVersion = filteredList.filter {
|
||||
$0.absoluteString.contains("CircuitPython%20\(Board.shared.versionNumber).x")
|
||||
}
|
||||
|
||||
return listForCurrentCPVersion
|
||||
|
||||
}
|
||||
|
||||
if sharedBootinfo.contains("CircuitPython 7") {
|
||||
|
||||
let listForCurrentCPVersion = listWithoutCP7Folder.filter {
|
||||
!$0.absoluteString.contains("CircuitPython%208.x")
|
||||
}
|
||||
|
||||
for i in listForCurrentCPVersion {
|
||||
print("listForCurrentCPVersion :- \(i.absoluteString)")
|
||||
}
|
||||
return listForCurrentCPVersion
|
||||
}
|
||||
|
||||
return listWithoutCP7Folder
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -394,12 +346,8 @@ class BleContentTransfer: ObservableObject {
|
|||
print("\(#function) @Line: \(#line)")
|
||||
var recursiveArray = directoryArray
|
||||
|
||||
for i in recursiveArray {
|
||||
print("recursiveArray \(i.absoluteString)")
|
||||
}
|
||||
|
||||
if directoryArray.isEmpty {
|
||||
print("Array is empty. makeDirectory is done - Ready for file transfer!")
|
||||
newTransfer(listOf: regularFilesArray)
|
||||
} else {
|
||||
|
||||
|
|
@ -490,10 +438,7 @@ class BleContentTransfer: ObservableObject {
|
|||
|
||||
}
|
||||
|
||||
enum ListCommandError: Error {
|
||||
case belowMinimum
|
||||
case isPrime
|
||||
}
|
||||
|
||||
|
||||
func checkIfFilesExistOnBoard(url: URL) {
|
||||
|
||||
|
|
@ -527,29 +472,16 @@ class BleContentTransfer: ObservableObject {
|
|||
var tempPathComponents = url.pathComponents
|
||||
print("Incoming URL for makeFileString: \(url.absoluteString)")
|
||||
|
||||
|
||||
if sharedBootinfo.contains("CircuitPython 7") {
|
||||
|
||||
indexOfCP = tempPathComponents.firstIndex(of: "CircuitPython 7.x")!
|
||||
tempPathComponents.removeSubrange(0...indexOfCP)
|
||||
tempPathComponents.removeLast()
|
||||
var joinedArrayPath = tempPathComponents.joined(separator: "/")
|
||||
print("\(#function) @Line: \(#line)")
|
||||
print("Outgoing makeFileString: \(joinedArrayPath) for CP 7")
|
||||
return joinedArrayPath
|
||||
}
|
||||
|
||||
if sharedBootinfo.contains("CircuitPython 8") {
|
||||
indexOfCP = tempPathComponents.firstIndex(of: "CircuitPython 8.x")!
|
||||
indexOfCP = tempPathComponents.firstIndex(of: "CircuitPython \(Board.shared.versionNumber).x")!
|
||||
tempPathComponents.removeSubrange(0...indexOfCP)
|
||||
tempPathComponents.removeLast()
|
||||
var joinedArrayPath = tempPathComponents.joined(separator: "/")
|
||||
print("\(#function) @Line: \(#line)")
|
||||
print("Outgoing makeFileString: \(joinedArrayPath) for CP 8")
|
||||
return joinedArrayPath
|
||||
}
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -561,256 +493,81 @@ class BleContentTransfer: ObservableObject {
|
|||
|
||||
print("Incoming URL: \(url.absoluteString) ")
|
||||
|
||||
|
||||
|
||||
if sharedBootinfo.contains("CircuitPython 7") {
|
||||
print(tempPathComponents)
|
||||
indexOfCP = tempPathComponents.firstIndex(of: "CircuitPython 7.x")!
|
||||
indexOfCP = tempPathComponents.firstIndex(of: "CircuitPython \(Board.shared.versionNumber).x")!
|
||||
|
||||
|
||||
tempPathComponents.removeSubrange(0...indexOfCP)
|
||||
var joinedArrayPath = tempPathComponents.joined(separator: "/")
|
||||
print("\(#function) @Line: \(#line)")
|
||||
print("Outgoing String: \(joinedArrayPath) for CP 7")
|
||||
print("Outgoing Directory String: \(joinedArrayPath) for CP \(Board.shared.versionNumber)")
|
||||
return joinedArrayPath
|
||||
}
|
||||
|
||||
if sharedBootinfo.contains("CircuitPython 8") {
|
||||
indexOfCP = tempPathComponents.firstIndex(of: "CircuitPython 8.x")!
|
||||
tempPathComponents.removeSubrange(0...indexOfCP)
|
||||
var joinedArrayPath = tempPathComponents.joined(separator: "/")
|
||||
print("\(#function) @Line: \(#line)")
|
||||
print("Outgoing String: \(joinedArrayPath) for CP 8")
|
||||
return joinedArrayPath
|
||||
} else {
|
||||
|
||||
guard let projectName = projectName else {
|
||||
return "Unknown"
|
||||
}
|
||||
|
||||
indexOfCP = tempPathComponents.firstIndex(of: projectName)!
|
||||
tempPathComponents.removeSubrange(0...indexOfCP)
|
||||
var joinedArrayPath = tempPathComponents.joined(separator: "/")
|
||||
print("\(#function) @Line: \(#line)")
|
||||
print("Outgoing String: \(joinedArrayPath) for CP 7")
|
||||
return joinedArrayPath
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
func newTransfer(listOf urls: [URL]) {
|
||||
print("\(#function) @Line: \(#line)")
|
||||
var copiedFiles = urls
|
||||
print("Files left for transfer: \(urls.count)")
|
||||
|
||||
print("Attempting to transfer... \(urls.first?.lastPathComponent ?? "No file found")")
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.counter += 1
|
||||
}
|
||||
|
||||
|
||||
if copiedFiles.isEmpty {
|
||||
guard !urls.isEmpty else {
|
||||
print("All Files Transferred! 👍")
|
||||
self.completedTransfer()
|
||||
|
||||
completedTransfer()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2){
|
||||
self.sendingBundle = false
|
||||
self.completedTransfer()
|
||||
self.numOfFiles = 0
|
||||
self.counter = 0
|
||||
self.contentList.removeAll()
|
||||
self.resetTransferParameters()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
print("\(#function) @Line: \(#line)")
|
||||
print("Files left for transfer: \(urls.count)")
|
||||
print("Attempting to transfer... \(urls.first?.lastPathComponent ?? "No file found")")
|
||||
DispatchQueue.main.async { self.counter += 1 }
|
||||
|
||||
guard let data = try? Data(contentsOf: URL(string: copiedFiles.first!.absoluteString)!) else {
|
||||
guard let url = urls.first,
|
||||
let data = try? Data(contentsOf: url) else {
|
||||
print("File not found")
|
||||
return
|
||||
}
|
||||
|
||||
let path = isDirectFile(name: url.lastPathComponent) ? url.lastPathComponent : makeDirectoryString(url: url)
|
||||
|
||||
if copiedFiles.first?.lastPathComponent == "code.py" || copiedFiles.first?.lastPathComponent == "README.txt" {
|
||||
|
||||
print("Input for writeFileCommand: \(copiedFiles.first?.absoluteString)")
|
||||
|
||||
|
||||
self.contentCommands.writeFileCommand(path: copiedFiles.first!.lastPathComponent, data: data) { result in
|
||||
contentCommands.writeFileCommand(path: path, data: data) { result in
|
||||
switch result {
|
||||
|
||||
case .success(_):
|
||||
case .success:
|
||||
print("Success ✅")
|
||||
copiedFiles.removeFirst()
|
||||
self.newTransfer(listOf: copiedFiles)
|
||||
|
||||
self.newTransfer(listOf: Array(urls.dropFirst()))
|
||||
case .failure(let error):
|
||||
print("Transfer Failure \(error)")
|
||||
self.handleTransferError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func handleTransferError(_ error: Error) {
|
||||
DispatchQueue.main.async {
|
||||
print("\(#function) @Line: \(#line)")
|
||||
print(error)
|
||||
DispatchQueue.main.async {
|
||||
print("Transfer Failure \(error)")
|
||||
self.downloadState = .failed
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
self.downloadState = .idle
|
||||
}
|
||||
NotificationCenter.default.post(name: .didEncounterTransferError, object: nil, userInfo: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
print("Checking... 🫥")
|
||||
// print("makeDirectoryString transfer \(makeDirectoryString(url: copiedFiles.first!))")
|
||||
|
||||
let directoryPath = makeDirectoryString(url: copiedFiles.first!)
|
||||
|
||||
print("Input writeFileCommand: \(directoryPath)")
|
||||
self.contentCommands.writeFileCommand(path: directoryPath, data: data) { result in
|
||||
switch result {
|
||||
|
||||
case .success(_):
|
||||
print("Success ✅")
|
||||
copiedFiles.removeFirst()
|
||||
self.newTransfer(listOf: copiedFiles)
|
||||
|
||||
case .failure(let error):
|
||||
print("\(#function) @Line: \(#line)")
|
||||
print(error)
|
||||
DispatchQueue.main.async {
|
||||
print("Transfer Failure \(error)")
|
||||
self.downloadState = .failed
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
self.downloadState = .idle
|
||||
}
|
||||
NotificationCenter.default.post(name: .didEncounterTransferError, object: nil, userInfo: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
private func resetTransferParameters() {
|
||||
sendingBundle = false
|
||||
completedTransfer()
|
||||
numOfFiles = 0
|
||||
counter = 0
|
||||
contentList.removeAll()
|
||||
}
|
||||
|
||||
private func isDirectFile(name: String) -> Bool {
|
||||
return name == "code.py" || name == "README.txt"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
func filePathMod(listOf files: [URL]) {
|
||||
var indexOfCP = 0
|
||||
|
||||
for i in files {
|
||||
print("-\(i.absoluteString)-\n")
|
||||
}
|
||||
|
||||
var tempArray = files
|
||||
|
||||
if files.isEmpty {
|
||||
// Continue
|
||||
print("\(#function) @Line: \(#line)")
|
||||
print("Done!")
|
||||
// print("RETURNED PATHS: \(returnedArray)\n")
|
||||
|
||||
for i in filesReadyForTransfer {
|
||||
print("\(i)")
|
||||
}
|
||||
|
||||
// self.transferFiles(files: fileArray)
|
||||
|
||||
// validateDirectory(directoryArray: returnedArray, fileArray: fileArray)
|
||||
|
||||
} else {
|
||||
|
||||
var tempPath = files[0].pathComponents
|
||||
|
||||
print("temp path \(tempPath)")
|
||||
|
||||
if tempPath.contains("CircuitPython 7.x") {
|
||||
|
||||
print("\(#function) @Line: \(#line)")
|
||||
|
||||
indexOfCP = tempPath.firstIndex(of: "CircuitPython 7.x")!
|
||||
|
||||
tempPath.removeSubrange(0...indexOfCP)
|
||||
|
||||
print("removeSubrange temp path - \(tempPath)")
|
||||
|
||||
|
||||
tempArray.removeFirst()
|
||||
|
||||
var joinedArrayPath = tempPath.joined(separator: "/")
|
||||
|
||||
|
||||
filesReadyForTransfer.append(URL(string: joinedArrayPath)!)
|
||||
|
||||
filePathMod(listOf: tempArray)
|
||||
|
||||
}
|
||||
|
||||
if tempPath.contains("CircuitPython 8.x") {
|
||||
|
||||
print("\(#function) @Line: \(#line)")
|
||||
|
||||
indexOfCP = tempPath.firstIndex(of: "CircuitPython 8.x")!
|
||||
|
||||
tempPath.removeSubrange(0...indexOfCP)
|
||||
|
||||
print("removeSubrange temp path - \(tempPath)")
|
||||
|
||||
|
||||
tempArray.removeFirst()
|
||||
|
||||
var joinedArrayPath = tempPath.joined(separator: "/")
|
||||
|
||||
filesReadyForTransfer.append(URL(string: joinedArrayPath)!)
|
||||
|
||||
filePathMod(listOf: tempArray)
|
||||
|
||||
}
|
||||
|
||||
|
||||
if tempPath.contains(projectName ?? "unknown") {
|
||||
|
||||
print("\(#function) @Line: \(#line)")
|
||||
|
||||
indexOfCP = tempPath.firstIndex(of: projectName!)!
|
||||
|
||||
tempPath.removeSubrange(0...indexOfCP+1)
|
||||
|
||||
print("removeSubrange temp path - \(tempPath)")
|
||||
|
||||
tempArray.removeFirst()
|
||||
|
||||
var joinedArrayPath = tempPath.joined(separator: "/")
|
||||
|
||||
filesReadyForTransfer.append(URL(string: joinedArrayPath)!)
|
||||
|
||||
filePathMod(listOf: tempArray)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
func completedTransfer() {
|
||||
|
||||
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.downloadState = .complete
|
||||
self.didCompleteTranfer = true
|
||||
|
|
@ -825,185 +582,6 @@ class BleContentTransfer: ObservableObject {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func transferFiles(files: [URL]) {
|
||||
print(#function)
|
||||
var copiedFiles = files
|
||||
print("Number of files in filesArray \(files.count)")
|
||||
print(files)
|
||||
|
||||
if files.isEmpty {
|
||||
print("Array of contents empty - Check other directories")
|
||||
self.completedTransfer()
|
||||
|
||||
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2){
|
||||
self.sendingBundle = false
|
||||
self.completedTransfer()
|
||||
self.numOfFiles = 0
|
||||
self.contentList.removeAll()
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
guard let selectedUrl = files.first else {
|
||||
print("No such file exist here")
|
||||
return
|
||||
}
|
||||
|
||||
guard let data = try? Data(contentsOf: URL(fileURLWithPath: selectedUrl.deletingPathExtension().lastPathComponent, relativeTo: selectedUrl).appendingPathExtension(selectedUrl.pathExtension)) else {
|
||||
print("File not found")
|
||||
return
|
||||
}
|
||||
|
||||
if selectedUrl.deletingLastPathComponent().lastPathComponent == "CircuitPython 7.x"{
|
||||
|
||||
print("Selected Path: \(selectedUrl.path)")
|
||||
|
||||
var tempURL = selectedUrl.pathComponents
|
||||
|
||||
tempURL.removeFirst(12)
|
||||
let joined = tempURL.joined(separator: "/")
|
||||
|
||||
|
||||
var newModPath = tempURL
|
||||
newModPath.removeLast()
|
||||
print("Test file path: \(tempURL)")
|
||||
|
||||
print("File transfer modified path xx: \(joined)")
|
||||
|
||||
|
||||
|
||||
self.contentCommands.writeFileCommand(path: joined, data: data) { result in
|
||||
switch result {
|
||||
|
||||
case .success(_):
|
||||
copiedFiles.removeFirst()
|
||||
self.transferFiles(files: copiedFiles)
|
||||
|
||||
case .failure(_):
|
||||
DispatchQueue.main.async {
|
||||
|
||||
print("Transfer Failure")
|
||||
print("\(joined)")
|
||||
self.downloadState = .failed
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
self.downloadState = .idle
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NotificationCenter.default.post(name: .didEncounterTransferError, object: nil, userInfo: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
else if selectedUrl.deletingLastPathComponent().lastPathComponent == "lib" {
|
||||
|
||||
|
||||
|
||||
var tempURL = selectedUrl.pathComponents
|
||||
tempURL.removeFirst(12)
|
||||
let joined = tempURL.joined(separator: "/")
|
||||
print("File transfer modified path 11:\(joined)")
|
||||
|
||||
|
||||
|
||||
print("Updated Path:\(joined)")
|
||||
|
||||
|
||||
|
||||
contentCommands.writeFileCommand(path: joined, data: data) { result in
|
||||
switch result {
|
||||
case .success(_):
|
||||
copiedFiles.removeFirst()
|
||||
self.transferFiles(files: copiedFiles)
|
||||
|
||||
case .failure(_):
|
||||
print("Transfer Failure - 2")
|
||||
self.downloadState = .failed
|
||||
NotificationCenter.default.post(name: .didEncounterTransferError, object: nil, userInfo: nil)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if selectedUrl.lastPathComponent == "README.txt" {
|
||||
print("Got one")
|
||||
copiedFiles.removeFirst()
|
||||
self.transferFiles(files: copiedFiles)
|
||||
|
||||
|
||||
} else {
|
||||
var tempURL = selectedUrl.pathComponents
|
||||
|
||||
tempURL.removeFirst(12)
|
||||
let joined = tempURL.joined(separator: "/")
|
||||
print("File transfer modified path: \(joined)")
|
||||
|
||||
|
||||
|
||||
print("Updated Path:\(joined)")
|
||||
|
||||
|
||||
contentCommands.writeFileCommand(path: joined, data: data) { result in
|
||||
switch result {
|
||||
case .success(_):
|
||||
copiedFiles.removeFirst()
|
||||
self.transferFiles(files: copiedFiles)
|
||||
case .failure(let error):
|
||||
print("Failed: \(error): \(result)")
|
||||
NotificationCenter.default.post(name: .didEncounterTransferError, object: nil, userInfo: nil)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.sendingBundle = true
|
||||
}
|
||||
}
|
||||
|
||||
func readMyStatus() {
|
||||
///model.readFile(filename: "boot_out.txt")
|
||||
print(#function)
|
||||
|
||||
print("BOOT INFO: \(bootUpInfo)")
|
||||
|
||||
switch bootUpInfo.description {
|
||||
|
||||
case let str where str.contains("CircuitPython 7"):
|
||||
print("CircuitPython 7")
|
||||
circuitPythonVersion = "CircuitPython 7"
|
||||
|
||||
case let str where str.contains("CircuitPython 8"):
|
||||
print("CircuitPython 8")
|
||||
circuitPythonVersion = "CircuitPython 8"
|
||||
default:
|
||||
print("Unknown Device")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// MARK: System
|
||||
|
||||
struct TransmissionProgress {
|
||||
|
|
@ -1047,7 +625,6 @@ class BleContentTransfer: ObservableObject {
|
|||
@Published var lastTransmit: TransmissionLog? = TransmissionLog(type: .write(size: 334))
|
||||
|
||||
|
||||
@Published var activeAlert: ActiveAlert?
|
||||
|
||||
// Data
|
||||
private let bleManager = BleManager.shared
|
||||
|
|
@ -1088,8 +665,7 @@ class BleContentTransfer: ObservableObject {
|
|||
let str = String(decoding: data, as: UTF8.self)
|
||||
print("\(#function) @Line: \(#line)")
|
||||
print("Read: \(str)")
|
||||
//self.readMyStatus()
|
||||
self.bootUpInfo = str
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -12,28 +12,36 @@ class ExpandedBLECellState: ObservableObject {
|
|||
@Published var currentCell = ""
|
||||
}
|
||||
|
||||
class Board: Equatable {
|
||||
|
||||
static func == (lhs: Board, rhs: Board) -> Bool {
|
||||
return lhs.name == rhs.name && lhs.versionNumber == rhs.versionNumber
|
||||
}
|
||||
|
||||
static let shared = Board(name: "Unrecognized Board", versionNumber: "8")
|
||||
|
||||
var name: String
|
||||
var versionNumber: String
|
||||
|
||||
private init(name: String, versionNumber: String) {
|
||||
self.name = name
|
||||
self.versionNumber = versionNumber
|
||||
}
|
||||
}
|
||||
|
||||
struct BleModuleView: View {
|
||||
|
||||
// Data
|
||||
enum ActiveAlert: Identifiable {
|
||||
case confirmUnpair(blePeripheral: BlePeripheral)
|
||||
|
||||
var id: Int {
|
||||
switch self {
|
||||
case .confirmUnpair: return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@State var boardInfoForView: Board?
|
||||
|
||||
@Environment(\.presentationMode) var presentationMode
|
||||
@EnvironmentObject var expandedState : ExpandedBLECellState
|
||||
@ObservedObject var connectionManager = FileTransferConnectionManager.shared
|
||||
|
||||
|
||||
@State var unknownBoardName: String?
|
||||
|
||||
let selectedPeripheral = FileTransferConnectionManager.shared.selectedPeripheral
|
||||
|
||||
@StateObject var viewModel = BleModuleViewModel()
|
||||
@StateObject var vm = BleModuleViewModel()
|
||||
@EnvironmentObject var rootViewModel: RootViewModel
|
||||
|
||||
|
||||
|
|
@ -44,7 +52,6 @@ struct BleModuleView: View {
|
|||
@State var isExpanded = true
|
||||
|
||||
@State private var scrollViewID = UUID()
|
||||
@State private var activeAlert: ActiveAlert?
|
||||
@State private var boardBootInfo = ""
|
||||
@State private var inConnectedInSelectionView = true
|
||||
|
||||
|
|
@ -118,12 +125,7 @@ struct BleModuleView: View {
|
|||
.lineLimit(2)
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
|
||||
if boardBootInfo == "clue_nrf52840_express" {
|
||||
} else if boardBootInfo == "clue_nrf52840_express" {
|
||||
Image("clue")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
|
|
@ -138,6 +140,20 @@ struct BleModuleView: View {
|
|||
.lineLimit(2)
|
||||
.padding(.horizontal, 20)
|
||||
|
||||
} else {
|
||||
Image("Placeholder Board Image")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 200, height: 200)
|
||||
.padding(.horizontal, 60)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
||||
Text(unknownBoardName ?? "")
|
||||
.font(Font.custom("ReadexPro-Regular", size: 30))
|
||||
.minimumScaleFactor(0.01)
|
||||
.multilineTextAlignment(.center)
|
||||
.lineLimit(2)
|
||||
.padding(.horizontal, 20)
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -173,86 +189,11 @@ struct BleModuleView: View {
|
|||
|
||||
VStack {
|
||||
|
||||
|
||||
|
||||
if boardBootInfo == "circuitplayground_bluefruit" {
|
||||
HStack {
|
||||
|
||||
Image("bluetoothLogo")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 16, height: 16)
|
||||
|
||||
|
||||
Text("Circuit Playground Bluefruit.")
|
||||
.font(Font.custom("ReadexPro-Regular", size: 14))
|
||||
.minimumScaleFactor(0.1)
|
||||
|
||||
|
||||
Button {
|
||||
BleBannerView(deviceName: boardInfoForView?.name ?? "Unknown Device", disconnectAction: {
|
||||
showConfirmationPrompt()
|
||||
} label: {
|
||||
Text("Disconnect")
|
||||
.font(Font.custom("ReadexPro-Bold", size: 14))
|
||||
.underline()
|
||||
.minimumScaleFactor(0.1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if boardBootInfo == "clue_nrf52840_express" {
|
||||
VStack {
|
||||
|
||||
HStack {
|
||||
Image("bluetoothLogo")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 16, height: 16)
|
||||
|
||||
Text("Adafruit CLUE.")
|
||||
.font(Font.custom("ReadexPro-Regular", size: 14))
|
||||
|
||||
Button {
|
||||
showConfirmationPrompt()
|
||||
|
||||
|
||||
} label: {
|
||||
Text("Disconnect")
|
||||
.font(Font.custom("ReadexPro-Bold", size: 14))
|
||||
.underline()
|
||||
//.minimumScaleFactor(0.1)
|
||||
}
|
||||
|
||||
}
|
||||
// Expandable
|
||||
VStack {
|
||||
Text("More Info")
|
||||
}
|
||||
.background(GeometryReader {
|
||||
Color.clear.preference(key: ViewHeightKey.self,
|
||||
value: $0.frame(in: .local).size.height)
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
.onPreferenceChange(ViewHeightKey.self) { subviewHeight = $0 }
|
||||
.frame(height: isExpanded ? subviewHeight : 50, alignment: .top)
|
||||
|
||||
.clipped()
|
||||
.frame(maxWidth: .infinity)
|
||||
.transition(.move(edge: .bottom))
|
||||
|
||||
|
||||
.onTapGesture {
|
||||
withAnimation(.easeIn(duration: 0.5)) {
|
||||
isExpanded.toggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.padding(.all, 0.0)
|
||||
.frame(maxWidth: .infinity)
|
||||
|
|
@ -270,14 +211,32 @@ struct BleModuleView: View {
|
|||
MainSubHeaderView(device: "Adafruit CLUE")
|
||||
}
|
||||
|
||||
if boardBootInfo == "circuitplayground_bluefruit" {
|
||||
else if boardInfoForView?.name == "Circuitplayground Bluefruit" {
|
||||
MainSubHeaderView(device: "Circuit Playground")
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
MainSubHeaderView(device: unknownBoardName ?? "device")
|
||||
}
|
||||
|
||||
|
||||
let check = vm.pdemos.filter {
|
||||
|
||||
if boardInfoForView?.name == "Circuitplayground Bluefruit" {
|
||||
let cpbProjects = $0.compatibility.contains("circuitplayground_bluefruit")
|
||||
print("Returned \(cpbProjects) for circuitplayground_bluefruit")
|
||||
return cpbProjects
|
||||
}
|
||||
|
||||
else if boardInfoForView?.name == "Clue Nrf52840 Express" {
|
||||
let clueProjects = $0.compatibility.contains("clue_nrf52840_express")
|
||||
return clueProjects
|
||||
}
|
||||
else {
|
||||
return true
|
||||
}
|
||||
|
||||
let check = viewModel.pdemos.filter {
|
||||
$0.compatibility.contains(boardBootInfo)
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -311,6 +270,9 @@ struct BleModuleView: View {
|
|||
.id(self.scrollViewID)
|
||||
}
|
||||
.environmentObject(expandedState)
|
||||
.refreshable {
|
||||
vm.fetchAndLoadProjectsFromStorage()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -318,49 +280,36 @@ struct BleModuleView: View {
|
|||
.background(Color.white)
|
||||
|
||||
|
||||
.onChange(of: viewModel.bootUpInfo, perform: { newValue in
|
||||
viewModel.readMyStatus()
|
||||
.onChange(of: vm.bootUpInfo, perform: { newValue in
|
||||
vm.readMyStatus()
|
||||
|
||||
print("newValue \(newValue)")
|
||||
boardBootInfo = newValue
|
||||
})
|
||||
|
||||
.onChange(of: connectionManager.selectedClient) { selectedClient in
|
||||
viewModel.setup(fileTransferClient: selectedClient)
|
||||
vm.setup(fileTransferClient: selectedClient)
|
||||
}
|
||||
|
||||
.onAppear(){
|
||||
print("Opened BleModuleView")
|
||||
// networkServiceModel.fetch()
|
||||
.onChange(of: vm.connectedBoard, perform: { newValue in
|
||||
dump(newValue)
|
||||
boardInfoForView = newValue
|
||||
unknownBoardName = newValue?.name
|
||||
})
|
||||
|
||||
viewModel.setup(fileTransferClient:connectionManager.selectedClient)
|
||||
.onAppear(){
|
||||
|
||||
|
||||
vm.setup(fileTransferClient:connectionManager.selectedClient)
|
||||
|
||||
connectionManager.isSelectedPeripheralReconnecting = true
|
||||
|
||||
viewModel.readFile(filename: "boot_out.txt")
|
||||
}
|
||||
vm.readFile(filename: "boot_out.txt")
|
||||
|
||||
print("x\(boardBootInfo)")
|
||||
|
||||
}
|
||||
|
||||
struct Alerts: ViewModifier {
|
||||
@Binding var activeAlert: ActiveAlert?
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.alert(item: $activeAlert, content: { alert in
|
||||
switch alert {
|
||||
case .confirmUnpair(let blePeripheral):
|
||||
return Alert(
|
||||
title: Text("Confirm disconnect \(blePeripheral.name ?? "")"),
|
||||
message: nil,
|
||||
primaryButton: .destructive(Text("Disconnect")) {
|
||||
//BleAutoReconnect.clearAutoconnectPeripheral()
|
||||
BleManager.shared.disconnect(from: blePeripheral)
|
||||
},
|
||||
secondaryButton: .cancel(Text("Cancel")) {})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -11,19 +11,46 @@ import FileTransferClient
|
|||
|
||||
class BleModuleViewModel: ObservableObject {
|
||||
|
||||
weak var delegate: BoardInfoDelegate?
|
||||
|
||||
@Published var boardInfoForView: Board? {
|
||||
didSet {
|
||||
print("Changed")
|
||||
delegate?.boardInfoDidUpdate(to: boardInfoForView)
|
||||
}
|
||||
}
|
||||
|
||||
private weak var fileTransferClient: FileTransferClient?
|
||||
@StateObject var contentTransfer = BleContentTransfer()
|
||||
@State var contentTransfer = BleContentTransfer()
|
||||
|
||||
@Published var entries = [BlePeripheral.DirectoryEntry]()
|
||||
@Published var isTransmiting = false
|
||||
@Published var bootUpInfo = ""
|
||||
|
||||
let dataStore = DataStore()
|
||||
|
||||
@Published var pdemos : [ResultItem] = []
|
||||
var boardDataProvider = BoardDataProvider()
|
||||
var connectedBoard: Board?
|
||||
|
||||
let dataStore = DataStore()
|
||||
@ObservedObject var networkModel = NetworkService()
|
||||
|
||||
|
||||
@Published var pdemos : [PyProject] = []
|
||||
|
||||
func loadProjectsFromStorage() {
|
||||
self.pdemos = self.dataStore.loadDefaultList()
|
||||
}
|
||||
|
||||
func fetchAndLoadProjectsFromStorage() {
|
||||
self.networkModel.fetch {
|
||||
self.pdemos = self.dataStore.loadDefaultList()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
init() {
|
||||
pdemos = dataStore.loadDefaultList()
|
||||
loadProjectsFromStorage()
|
||||
self.delegate = contentTransfer
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -71,7 +98,6 @@ class BleModuleViewModel: ObservableObject {
|
|||
|
||||
@Published var transmissionProgress: TransmissionProgress?
|
||||
@Published var lastTransmit: TransmissionLog? = TransmissionLog(type: .write(size: 334))
|
||||
@Published var activeAlert: ActiveAlert?
|
||||
// Data
|
||||
private let bleManager = BleManager.shared
|
||||
|
||||
|
|
@ -121,6 +147,28 @@ class BleModuleViewModel: ObservableObject {
|
|||
|
||||
}
|
||||
|
||||
|
||||
func setupBoardInfoForDisplay(_ boardInfo: String?) -> Board {
|
||||
// First, safely unwrap the optional 'boardInfo' string
|
||||
guard let info = boardInfo else {
|
||||
print("boardInfo is nil")
|
||||
return Board.shared
|
||||
}
|
||||
|
||||
let boardID = boardDataProvider.getBoardID(from: info) ?? "Unrecognized Board"
|
||||
// Board default version is set to 8
|
||||
let boardVersion = boardDataProvider.getCircuitPythonMajorVersion(from: info) ?? "8"
|
||||
|
||||
Board.shared.name = boardID
|
||||
Board.shared.versionNumber = boardVersion
|
||||
|
||||
// Create a new Board object with the acquired name and version
|
||||
let board = Board.shared
|
||||
|
||||
return board
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
func readFile(filename: String) {
|
||||
|
|
@ -135,8 +183,10 @@ class BleModuleViewModel: ObservableObject {
|
|||
let str = String(decoding: data, as: UTF8.self)
|
||||
|
||||
print("Read: \(str)")
|
||||
self.bootUpInfo = str
|
||||
sharedBootinfo = str
|
||||
|
||||
self.connectedBoard = self.setupBoardInfoForDisplay(str)
|
||||
self.boardInfoForView = self.connectedBoard
|
||||
|
||||
|
||||
case .failure(let error):
|
||||
self.lastTransmit = TransmissionLog(type: .error(message: error.localizedDescription))
|
||||
|
|
@ -344,18 +394,4 @@ class BleModuleViewModel: ObservableObject {
|
|||
completion?(result)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public var sharedBootinfo = ""
|
||||
|
||||
enum ActiveAlert: Identifiable {
|
||||
case error(error: Error)
|
||||
|
||||
var id: Int {
|
||||
switch self {
|
||||
case .error: return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,13 +10,13 @@ import FileTransferClient
|
|||
|
||||
struct DemoSubview: View {
|
||||
|
||||
@Binding var bindingString: String
|
||||
|
||||
let result: ResultItem
|
||||
let result: PyProject
|
||||
|
||||
@EnvironmentObject var rootViewModel: RootViewModel
|
||||
@StateObject var viewModel = SubCellViewModel()
|
||||
@StateObject var contentTransfer = BleContentTransfer()
|
||||
//@StateObject var contentTransfer = BleContentTransfer()
|
||||
@StateObject var contentTransfer = BleContentTransfer.shared
|
||||
|
||||
|
||||
@ObservedObject var connectionManager = FileTransferConnectionManager.shared
|
||||
|
||||
|
|
@ -150,15 +150,6 @@ Try again later
|
|||
|
||||
if isConnected {
|
||||
|
||||
if result.compatibility.contains(bindingString) {
|
||||
|
||||
// Button {
|
||||
// viewModel.deleteStoredFilesInFM()
|
||||
// } label: {
|
||||
// Text("Delete File Manager Contents")
|
||||
// .bold()
|
||||
// .padding(12)
|
||||
// }
|
||||
|
||||
if contentTransfer.downloadState == .idle {
|
||||
|
||||
|
|
@ -210,7 +201,7 @@ Try again later
|
|||
CompleteButton()
|
||||
.padding(.top, 20)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -231,8 +222,6 @@ Try again later
|
|||
|
||||
print("On Appear")
|
||||
contentTransfer.contentCommands.setup(fileTransferClient: connectionManager.selectedClient)
|
||||
|
||||
// viewModel.readFile(filename: "boot_out.txt")
|
||||
}
|
||||
|
||||
.onChange(of: contentTransfer.transferError, perform: { newValue in
|
||||
|
|
@ -247,14 +236,8 @@ Try again later
|
|||
}
|
||||
})
|
||||
|
||||
|
||||
// .onChange(of: connectionManager.selectedClient) { selectedClient in
|
||||
// viewModel.setup(fileTransferClient: selectedClient)
|
||||
// }
|
||||
|
||||
.onAppear(perform: {
|
||||
|
||||
contentTransfer.readMyStatus()
|
||||
viewModel.searchPathForProject(nameOf: result.projectName)
|
||||
|
||||
if viewModel.projectDownloaded {
|
||||
|
|
@ -11,7 +11,7 @@ struct DemoViewCell: View {
|
|||
|
||||
@EnvironmentObject var expandedState : ExpandedBLECellState
|
||||
|
||||
let result : ResultItem
|
||||
let result : PyProject
|
||||
|
||||
@State var isExpanded: Bool = false {
|
||||
didSet {
|
||||
|
|
@ -36,7 +36,7 @@ struct DemoViewCell: View {
|
|||
if isExpanded {
|
||||
|
||||
Group {
|
||||
DemoSubview(bindingString: $deviceInfo, result: result, isConnected: $isConnected)
|
||||
DemoSubview(result: result, isConnected: $isConnected)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -54,8 +54,7 @@ struct RootView: View {
|
|||
case .selection:
|
||||
SelectionView()
|
||||
|
||||
case .wifiSelection:
|
||||
WifiSelection()
|
||||
|
||||
|
||||
case .wifiPairingTutorial:
|
||||
WifiPairingView()
|
||||
|
|
@ -47,7 +47,7 @@ public class RootViewModel: ObservableObject {
|
|||
}
|
||||
|
||||
func goToWiFiSelection() {
|
||||
destination = .wifiSelection
|
||||
destination = .wifiServiceSelection
|
||||
}
|
||||
|
||||
func goToWifiView() {
|
||||
|
|
@ -16,8 +16,6 @@ struct WifiHeaderView: View {
|
|||
|
||||
VStack {
|
||||
|
||||
|
||||
|
||||
HStack (alignment: .center, spacing: 0) {
|
||||
|
||||
Image(systemName: "gearshape")
|
||||
143
PyLeap/Features/Unpaired View/MainSelectionView.swift
Normal file
143
PyLeap/Features/Unpaired View/MainSelectionView.swift
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
//
|
||||
// MainSelectionView.swift
|
||||
// PyLeap
|
||||
//
|
||||
// Created by Trevor Beaton on 10/16/21.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import FileTransferClient
|
||||
|
||||
enum AdafruitDevices {
|
||||
case clue_nrf52840_express
|
||||
case circuitplayground_bluefruit
|
||||
case esp32s2
|
||||
}
|
||||
|
||||
struct MainSelectionView: View {
|
||||
|
||||
@State private var showWebViewPopover: Bool = false
|
||||
|
||||
@State private var inConnectedInSelectionView = false
|
||||
@State private var boardBootInfo = ""
|
||||
@EnvironmentObject var expandedState : ExpandedBLECellState
|
||||
|
||||
@ObservedObject var vm = MainSelectionViewModel()
|
||||
|
||||
|
||||
@State private var isConnected = false
|
||||
|
||||
@State private var test = ""
|
||||
|
||||
@State private var nilBinder = DownloadState.idle
|
||||
@EnvironmentObject var rootViewModel: RootViewModel
|
||||
|
||||
@AppStorage("shouldShowOnboarding") var shouldShowOnboarding: Bool = true
|
||||
|
||||
var body: some View {
|
||||
|
||||
VStack(alignment: .center, spacing: 0) {
|
||||
MainHeaderView()
|
||||
|
||||
HStack(alignment: .center, spacing: 8, content: {
|
||||
Text("Not Connected to a Device.")
|
||||
.font(Font.custom("ReadexPro-Regular", size: 16))
|
||||
Button {
|
||||
rootViewModel.goToSelection()
|
||||
} label: {
|
||||
Text("Connect Now")
|
||||
.font(Font.custom("ReadexPro-Regular", size: 16))
|
||||
.underline()
|
||||
}
|
||||
|
||||
})
|
||||
.padding(.all, 0.0)
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(maxHeight: 40)
|
||||
.background(Color("pyleap_burg"))
|
||||
.foregroundColor(.white)
|
||||
|
||||
ScrollView {
|
||||
|
||||
MainSubHeaderView(device: "Adafruit device")
|
||||
|
||||
if vm.pdemos.isEmpty {
|
||||
HStack{
|
||||
Spacer()
|
||||
ProgressView()
|
||||
.scaleEffect(2)
|
||||
Spacer()
|
||||
}
|
||||
.padding(0)
|
||||
|
||||
}
|
||||
|
||||
ScrollViewReader { scroll in
|
||||
|
||||
ForEach(vm.pdemos) { demo in
|
||||
|
||||
if demo.bundleLink == expandedState.currentCell {
|
||||
|
||||
DemoViewCell(result: demo, isExpanded: true, isConnected: $inConnectedInSelectionView, deviceInfo: $boardBootInfo, onViewGeometryChanged: {
|
||||
})
|
||||
.onAppear(){
|
||||
print("Cell Appeared")
|
||||
withAnimation {
|
||||
scroll.scrollTo(demo.id)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
DemoViewCell(result: demo, isExpanded: false, isConnected: $inConnectedInSelectionView, deviceInfo: $boardBootInfo, onViewGeometryChanged: {
|
||||
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
.refreshable {
|
||||
vm.pdemos = []
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
vm.networkModel.fetch {
|
||||
|
||||
vm.loadProjectsFromStorage()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.onAppear() {
|
||||
|
||||
|
||||
print("Opened MainSelectionView")
|
||||
}
|
||||
|
||||
.fullScreenCover(isPresented: $shouldShowOnboarding, content: {
|
||||
ExampleView(shouldShowOnboarding: $shouldShowOnboarding)
|
||||
})
|
||||
.preferredColorScheme(.light)
|
||||
.background(Color.white)
|
||||
.navigationBarColor(UIColor(named: "pyleap_gray"))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -57,32 +57,43 @@ class MainSelectionViewModel: ObservableObject {
|
|||
|
||||
let dataStore = DataStore()
|
||||
|
||||
@Published var pdemos : [ResultItem] = []
|
||||
@Published var pdemos: [PyProject] = []
|
||||
|
||||
var networkMonitorCancellable: AnyCancellable?
|
||||
|
||||
init() {
|
||||
let fileURL = documentsDirectory.appendingPathComponent("StandardPyLeapProjects.json")
|
||||
startUp()
|
||||
}
|
||||
|
||||
|
||||
networkMonitorCancellable = networkMonitor.$isConnected.sink { isConnected in
|
||||
if isConnected {
|
||||
print("The device is currently connected to the internet.")
|
||||
// Perform some action when the device is connected to the internet.
|
||||
func loadProjectsFromStorage() {
|
||||
self.pdemos = self.dataStore.loadDefaultList()
|
||||
}
|
||||
|
||||
func fetchAndLoadProjectsFromStorage() {
|
||||
self.networkModel.fetch {
|
||||
self.pdemos = self.dataStore.loadDefaultList()
|
||||
}
|
||||
}
|
||||
|
||||
func startUp(){
|
||||
networkMonitorCancellable = networkMonitor.$isConnected.sink { isConnected in
|
||||
|
||||
if isConnected {
|
||||
// Perform some action when the device is connected to the internet.
|
||||
self.fetchAndLoadProjectsFromStorage()
|
||||
print("The device is currently connected to the internet.")
|
||||
|
||||
} else {
|
||||
print("The device is not currently connected to the internet.")
|
||||
// Perform some action when the device is not connected to the internet.
|
||||
print("Loading cached remote data.")
|
||||
self.pdemos = self.dataStore.loadDefaultList()
|
||||
|
||||
self.loadProjectsFromStorage()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ struct SelectionView: View {
|
|||
Button {
|
||||
rootViewModel.goToWiFiSelection()
|
||||
} label: {
|
||||
Text("Wifi")
|
||||
Text("WiFi")
|
||||
.font(Font.custom("ReadexPro-Regular", size: 25))
|
||||
.foregroundColor(Color.white)
|
||||
.frame(width: 270, height: 50, alignment: .center)
|
||||
|
|
@ -110,6 +110,9 @@ struct SelectionView: View {
|
|||
|
||||
}
|
||||
.padding(.bottom, 60)
|
||||
.onAppear() {
|
||||
print("In Selection view")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ struct WifiCell: View {
|
|||
|
||||
@EnvironmentObject var expandedState : ExpandedState
|
||||
|
||||
let result : ResultItem
|
||||
let result : PyProject
|
||||
|
||||
@State var isExpanded: Bool = false {
|
||||
didSet {
|
||||
|
|
@ -15,7 +15,7 @@ struct WifiSubViewCell: View {
|
|||
|
||||
@StateObject var wifiFileTransfer = WifiFileTransfer()
|
||||
@StateObject var wifiTransferService = WifiTransferService()
|
||||
let result : ResultItem
|
||||
let result : PyProject
|
||||
|
||||
@Binding var bindingString: String
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ Remove device from USB. Press "Reset" on the device.
|
|||
|
||||
|
||||
|
||||
func testOperation() {
|
||||
func startOperationQueue() {
|
||||
let operationQueue = OperationQueue()
|
||||
|
||||
let operation1 = BlockOperation {
|
||||
|
|
@ -158,48 +158,17 @@ Remove device from USB. Press "Reset" on the device.
|
|||
.font(Font.custom("ReadexPro-Bold", size: 18))
|
||||
.padding(.top, 5)
|
||||
|
||||
ForEach(result.compatibility, id: \.self) { device in
|
||||
HStack {
|
||||
Image(systemName: "checkmark")
|
||||
.resizable()
|
||||
.frame(width: 25, height: 22, alignment: .center)
|
||||
.foregroundColor(.green)
|
||||
Text("ESP32-S2")
|
||||
Text(formatDeviceName(device))
|
||||
.font(Font.custom("ReadexPro-Regular", size: 18))
|
||||
.foregroundColor(.black)
|
||||
}
|
||||
.padding(.top, 10)
|
||||
|
||||
|
||||
ForEach(result.compatibility, id: \.self) { string in
|
||||
if string == "circuitplayground_bluefruit" {
|
||||
|
||||
HStack {
|
||||
Image(systemName: "checkmark")
|
||||
.resizable()
|
||||
.frame(width: 25, height: 22, alignment: .center)
|
||||
.foregroundColor(.green)
|
||||
Text("Circuit Playground Bluefruit")
|
||||
.font(Font.custom("ReadexPro-Regular", size: 18))
|
||||
.foregroundColor(.black)
|
||||
}
|
||||
.padding(.top, 10)
|
||||
}
|
||||
|
||||
|
||||
|
||||
if string == "clue_nrf52840_express" {
|
||||
|
||||
HStack {
|
||||
Image(systemName: "checkmark")
|
||||
.resizable()
|
||||
.frame(width: 25, height: 22, alignment: .center)
|
||||
.foregroundColor(.green)
|
||||
Text("Adafruit CLUE")
|
||||
.font(Font.custom("ReadexPro-Regular", size: 18))
|
||||
.foregroundColor(.black)
|
||||
}
|
||||
.padding(.top, 10)
|
||||
}
|
||||
}
|
||||
})
|
||||
.ignoresSafeArea(.all)
|
||||
|
|
@ -219,18 +188,15 @@ Remove device from USB. Press "Reset" on the device.
|
|||
|
||||
|
||||
|
||||
if isConnected {
|
||||
|
||||
if result.compatibility.contains(bindingString) {
|
||||
|
||||
|
||||
if wifiFileTransfer.testIndex.downloadState == .idle {
|
||||
|
||||
|
||||
Button {
|
||||
// NotificationCenter.default.post(name: .didCompleteZip, object: nil, userInfo: projectResponse)
|
||||
|
||||
testOperation()
|
||||
startOperationQueue()
|
||||
|
||||
} label: {
|
||||
RunItButton()
|
||||
|
|
@ -274,18 +240,6 @@ Remove device from USB. Press "Reset" on the device.
|
|||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Button {
|
||||
rootViewModel.goTobluetoothPairing()
|
||||
} label: {
|
||||
ConnectButton()
|
||||
.padding(.top, 20)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Spacer()
|
||||
.frame(height: 30)
|
||||
.ignoresSafeArea(.all)
|
||||
|
|
@ -11,7 +11,7 @@ import Combine
|
|||
|
||||
struct WifiView: View {
|
||||
|
||||
@StateObject var viewModel = WifiViewModel()
|
||||
@StateObject var vm = WifiViewModel()
|
||||
private let kPrefix = Bundle.main.bundleIdentifier!
|
||||
|
||||
// User Defaults
|
||||
|
|
@ -38,12 +38,12 @@ struct WifiView: View {
|
|||
@State private var showPopover: Bool = false
|
||||
|
||||
func toggleViewModelIP() {
|
||||
viewModel.isInvalidIP.toggle()
|
||||
vm.isInvalidIP.toggle()
|
||||
}
|
||||
|
||||
|
||||
func scanNetworkWifi() {
|
||||
viewModel.wifiServiceManager.findService()
|
||||
vm.wifiServiceManager.findService()
|
||||
}
|
||||
|
||||
func printArray(array: [Any]) {
|
||||
|
|
@ -59,9 +59,9 @@ struct WifiView: View {
|
|||
|
||||
} else {
|
||||
hostName = userDefaults.object(forKey: kPrefix+".storeResolvedAddress.hostName") as! String
|
||||
viewModel.ipAddressStored = true
|
||||
vm.ipAddressStored = true
|
||||
print("storeResolvedAddress - is stored")
|
||||
viewModel.connectionStatus = .connected
|
||||
vm.connectionStatus = .connected
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,28 +71,40 @@ struct WifiView: View {
|
|||
hintText: "IP Address...",
|
||||
primaryTitle: "Done",
|
||||
secondaryTitle: "Cancel") { text in
|
||||
viewModel.checkServices(ip: text)
|
||||
vm.checkServices(ip: text)
|
||||
|
||||
} secondaryAction: {
|
||||
print("Cancel")
|
||||
}
|
||||
}
|
||||
|
||||
func showConfirmationPrompt() {
|
||||
comfirmationAlertMessage(title: "Are you sure you want to disconnect?", exitTitle: "Cancel", primaryTitle: "Disconnect") {
|
||||
rootViewModel.goToSelection()
|
||||
} cancel: {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func showAlertMessage() {
|
||||
alertMessage(title: "IP address Not Found", exitTitle: "Ok") {
|
||||
showValidationPrompt()
|
||||
}
|
||||
}
|
||||
|
||||
@State var boardInfoForView = Board.shared
|
||||
|
||||
var body: some View {
|
||||
|
||||
VStack(spacing: 0) {
|
||||
WifiHeaderView()
|
||||
|
||||
Group{
|
||||
switch viewModel.connectionStatus {
|
||||
switch vm.connectionStatus {
|
||||
case .connected:
|
||||
WifiStatusConnectedView(hostName: $hostName)
|
||||
WifiStatusConnectedView(hostName: $hostName, disconnectAction: {
|
||||
showConfirmationPrompt()
|
||||
})
|
||||
case .noConnection:
|
||||
WifiStatusNoConnectionView()
|
||||
case .connecting:
|
||||
|
|
@ -100,16 +112,14 @@ struct WifiView: View {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
ScrollView(.vertical, showsIndicators: false) {
|
||||
|
||||
ScrollViewReader { scroll in
|
||||
|
||||
SubHeaderView()
|
||||
|
||||
|
||||
let check = viewModel.pdemos.filter {
|
||||
$0.compatibility.contains(boardBootInfo)
|
||||
let check = vm.pdemos.filter {
|
||||
$0.wifiCompatible
|
||||
}
|
||||
|
||||
ForEach(check) { demo in
|
||||
|
|
@ -117,48 +127,43 @@ struct WifiView: View {
|
|||
if demo.bundleLink == test.currentCell {
|
||||
WifiCell(result: demo,isExpanded: trueTog, isConnected: $inConnectedInWifiView, bootOne: $boardBootInfo, stateBinder: $downloadState, onViewGeometryChanged: {
|
||||
|
||||
|
||||
})
|
||||
.onAppear(){
|
||||
|
||||
withAnimation {
|
||||
scroll.scrollTo(demo.id)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
WifiCell(result: demo, isExpanded: falseTog, isConnected: $inConnectedInWifiView, bootOne: $boardBootInfo, stateBinder: $downloadState, onViewGeometryChanged: {
|
||||
withAnimation {
|
||||
// scroll.scrollTo(demo.id)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.id(self.scrollViewID)
|
||||
}
|
||||
.foregroundColor(.black)
|
||||
.environmentObject(test)
|
||||
.refreshable {
|
||||
vm.fetchAndLoadProjectsFromStorage()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.onChange(of: viewModel.connectionStatus, perform: { newValue in
|
||||
.onChange(of: vm.connectionStatus, perform: { newValue in
|
||||
if newValue == .connected {
|
||||
hostName = userDefaults.object(forKey: kPrefix+".storeResolvedAddress.hostName") as! String
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
.onChange(of: viewModel.wifiServiceManager.resolvedServices, perform: { newValue in
|
||||
.onChange(of: vm.wifiServiceManager.resolvedServices, perform: { newValue in
|
||||
print("Credential Check!")
|
||||
print(newValue)
|
||||
|
||||
|
|
@ -173,7 +178,7 @@ struct WifiView: View {
|
|||
|
||||
})
|
||||
|
||||
.onChange(of: viewModel.isInvalidIP, perform: { newValue in
|
||||
.onChange(of: vm.isInvalidIP, perform: { newValue in
|
||||
print("viewModel.isInvalidIP .onChange")
|
||||
if newValue {
|
||||
showAlertMessage()
|
||||
|
|
@ -185,8 +190,8 @@ struct WifiView: View {
|
|||
|
||||
.onAppear(){
|
||||
checkForStoredIPAddress()
|
||||
viewModel.printStoredInfo()
|
||||
viewModel.read()
|
||||
vm.printStoredInfo()
|
||||
vm.read()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -18,51 +18,6 @@ struct TestIndex {
|
|||
|
||||
class WifiFileTransfer: ObservableObject {
|
||||
|
||||
|
||||
// func fetchDocuments<T: Sequence>(in sequence: T) where T.Element == Int {
|
||||
// var documentNumbers = sequence.map { String($0) }
|
||||
//
|
||||
// let timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { [weak self] timer in
|
||||
// guard
|
||||
// let self = self,
|
||||
// let documentNumber = documentNumbers.first
|
||||
// else {
|
||||
// timer.invalidate()
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// self.fetchDocument(byNumber: documentNumber)
|
||||
// documentNumbers.removeLast()
|
||||
// }
|
||||
// timer.fire() // if you don't want to wait 2 seconds for the first one to fire, go ahead and fire it manually
|
||||
// }
|
||||
|
||||
|
||||
func fetchDocumentsq<T: Sequence>(in sequence: T) where T.Element == URL {
|
||||
|
||||
print(sequence)
|
||||
|
||||
guard let value = sequence.first(where: { _ in true }) else {
|
||||
print("Complete - fetchDocumentsq")
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// let docNumber = String(value)
|
||||
// fetchDocument(byNumber: docNumber)
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
|
||||
// self?.fetchDocuments(in: sequence.dropFirst())
|
||||
|
||||
print(value)
|
||||
self?.fetchDocumentsq(in: sequence.dropFirst())
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct TestIndex {
|
||||
var count = 0
|
||||
var numberOfFiles = 0
|
||||
|
|
@ -74,13 +29,10 @@ class WifiFileTransfer: ObservableObject {
|
|||
downloadState = .idle
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
var testIndex = TestIndex()
|
||||
|
||||
|
||||
func copy(with zone: NSZone? = nil) -> Any {
|
||||
let copy = WifiFileTransfer()
|
||||
copy.counter = counter
|
||||
|
|
@ -125,6 +77,7 @@ class WifiFileTransfer: ObservableObject {
|
|||
|
||||
func printArray(array: [Any]) {
|
||||
|
||||
print("From print array:")
|
||||
for i in array {
|
||||
print("\(i)")
|
||||
}
|
||||
|
|
@ -339,34 +292,20 @@ class WifiFileTransfer: ObservableObject {
|
|||
|
||||
func filterOutCPDirectories(urls: [URL]) -> [URL] {
|
||||
// Removes - CircuitPython 8.x directory at the lastPathComponent
|
||||
let removingCP8FromArray = urls.filter {
|
||||
$0.lastPathComponent != ("CircuitPython 8.x")
|
||||
let filteredList = urls.filter {
|
||||
let lastPathComponent = $0.lastPathComponent
|
||||
return lastPathComponent != "CircuitPython 8.x"
|
||||
&& lastPathComponent != "CircuitPython 7.x"
|
||||
&& lastPathComponent != "CircuitPython_Templates"
|
||||
}
|
||||
|
||||
// Removes - CircuitPython 7.x directory at the lastPathComponent
|
||||
let removingCP7FromArray = removingCP8FromArray.filter {
|
||||
$0.lastPathComponent != ("CircuitPython 7.x")
|
||||
let listForCurrentCPVersion = filteredList.filter {
|
||||
$0.absoluteString.contains("CircuitPython%20\(Board.shared.versionNumber).x")
|
||||
}
|
||||
|
||||
if WifiCPVersion.versionNumber == 8 {
|
||||
let listForCurrentCPVersion = removingCP7FromArray.filter {
|
||||
!$0.absoluteString.contains("CircuitPython%207.x")
|
||||
printArray(array: listForCurrentCPVersion)
|
||||
|
||||
}
|
||||
return listForCurrentCPVersion
|
||||
}
|
||||
|
||||
if WifiCPVersion.versionNumber == 7 {
|
||||
let listForCurrentCPVersion = removingCP7FromArray.filter {
|
||||
!$0.absoluteString.contains("CircuitPython%208.x")
|
||||
|
||||
}
|
||||
return listForCurrentCPVersion
|
||||
}
|
||||
|
||||
|
||||
|
||||
return removingCP7FromArray
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -419,8 +358,6 @@ class WifiFileTransfer: ObservableObject {
|
|||
DispatchQueue.main.async {
|
||||
self.numOfFiles = tempArray.count
|
||||
self.makeFile(files: tempArray)
|
||||
// self.testIndex.numberOfFiles = self.numOfFiles
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -618,7 +555,6 @@ class WifiFileTransfer: ObservableObject {
|
|||
printArray(array: files)
|
||||
var copiedArray = files
|
||||
|
||||
// self.fetchDocumentsq(in: files)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.counter += 1
|
||||
99
PyLeap/Features/Wifi Module/WifiServiceCellSubView.swift
Normal file
99
PyLeap/Features/Wifi Module/WifiServiceCellSubView.swift
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
//
|
||||
// WifiServiceCellSubView.swift
|
||||
// PyLeap
|
||||
//
|
||||
// Created by Trevor Beaton on 3/29/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Foundation
|
||||
|
||||
struct WifiServiceCellSubView: View {
|
||||
let resolvedService: ResolvedService
|
||||
|
||||
@EnvironmentObject var rootViewModel: RootViewModel
|
||||
|
||||
let userDefaults = UserDefaults.standard
|
||||
private let kPrefix = Bundle.main.bundleIdentifier!
|
||||
|
||||
|
||||
func storeResolvedAddress(service: ResolvedService) {
|
||||
print("Storing resolved address")
|
||||
userDefaults.set(service.ipAddress, forKey: kPrefix+".storeResolvedAddress.ipAddress" )
|
||||
userDefaults.set(service.hostName, forKey: kPrefix+".storeResolvedAddress.hostName" )
|
||||
userDefaults.set(service.device, forKey: kPrefix+".storeResolvedAddress.device" )
|
||||
|
||||
print("Stored UserDefaults")
|
||||
|
||||
print(userDefaults.object(forKey: kPrefix+".storeResolvedAddress.ipAddress"))
|
||||
print(userDefaults.object(forKey: kPrefix+".storeResolvedAddress.hostName"))
|
||||
print(userDefaults.object(forKey: kPrefix+".storeResolvedAddress.device"))
|
||||
}
|
||||
|
||||
func showConfirmationPrompt(service: ResolvedService, hostName: String) {
|
||||
comfirmationAlertMessage(title: "Would you like to connect to \(hostName)?", exitTitle: "Cancel", primaryTitle: "Connect") {
|
||||
storeResolvedAddress(service: service)
|
||||
rootViewModel.goToWifiView()
|
||||
} cancel: {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
VStack {
|
||||
|
||||
|
||||
|
||||
HStack {
|
||||
VStack {
|
||||
|
||||
Text("Device ID: \(resolvedService.hostName)")
|
||||
.font(Font.custom("ReadexPro-Regular", size: 18))
|
||||
.multilineTextAlignment(.leading)
|
||||
.minimumScaleFactor(0.1)
|
||||
|
||||
Text("Device IP: \(resolvedService.ipAddress)")
|
||||
.font(Font.custom("ReadexPro-Regular", size: 18))
|
||||
.multilineTextAlignment(.leading)
|
||||
.minimumScaleFactor(0.1)
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal, 30)
|
||||
.padding(.vertical, 30)
|
||||
|
||||
HStack (
|
||||
alignment: .center,
|
||||
spacing: 0
|
||||
) {
|
||||
Spacer()
|
||||
Button {
|
||||
showConfirmationPrompt(service: resolvedService, hostName: resolvedService.hostName)
|
||||
|
||||
} label: {
|
||||
Text("Connect")
|
||||
.font(Font.custom("ReadexPro-Regular", size: 25))
|
||||
.foregroundColor(Color.white)
|
||||
.frame(width: 270, height: 50, alignment: .center)
|
||||
.background(Color("pyleap_pink"))
|
||||
.clipShape(Capsule())
|
||||
.padding(.bottom, 30)
|
||||
}
|
||||
Spacer()
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//struct WifiServiceCellSubView_Previews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// WifiServiceCellSubView(resolvedService: .con)
|
||||
// }
|
||||
//}
|
||||
81
PyLeap/Features/Wifi Module/WifiServiceCellView.swift
Normal file
81
PyLeap/Features/Wifi Module/WifiServiceCellView.swift
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
//
|
||||
// WifiServiceCellView.swift
|
||||
// PyLeap
|
||||
//
|
||||
// Created by Trevor Beaton on 11/7/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct WifiServiceCellView: View {
|
||||
|
||||
let resolvedService: ResolvedService
|
||||
|
||||
@State private var isExpanded: Bool = false {
|
||||
didSet {
|
||||
onViewGeometryChanged()
|
||||
}
|
||||
}
|
||||
|
||||
let onViewGeometryChanged: ()->Void
|
||||
|
||||
var body: some View {
|
||||
content
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
|
||||
private var content: some View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
header
|
||||
|
||||
if isExpanded {
|
||||
|
||||
Group {
|
||||
WifiServiceCellSubView(resolvedService: resolvedService)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeAdafruitString(text: String) -> String {
|
||||
if text.contains("Adafruit") {
|
||||
let parsed = text.replacingOccurrences(of: "Adafruit", with: "")
|
||||
return parsed
|
||||
} else {
|
||||
return text
|
||||
}
|
||||
}
|
||||
|
||||
private var header: some View {
|
||||
|
||||
|
||||
|
||||
HStack {
|
||||
Text(removeAdafruitString(text:resolvedService.device))
|
||||
.font(Font.custom("ReadexPro-Regular", size: 24))
|
||||
.minimumScaleFactor(0.1)
|
||||
.lineLimit(1)
|
||||
// .padding(.horizontal, 30)
|
||||
.foregroundColor(.white)
|
||||
|
||||
Spacer()
|
||||
|
||||
Image(systemName: "chevron.down")
|
||||
.resizable()
|
||||
.frame(width: 30, height: 15, alignment: .center)
|
||||
.foregroundColor(.white)
|
||||
.padding(.trailing, 30)
|
||||
}
|
||||
|
||||
//.padding(.vertical, 5)
|
||||
.padding(.leading)
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 50)
|
||||
.background(Color("alt-gray"))
|
||||
.onTapGesture { isExpanded.toggle() }
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
// PyLeap
|
||||
//
|
||||
// Created by Trevor Beaton on 10/24/22.
|
||||
//
|
||||
// Testing
|
||||
|
||||
import SwiftUI
|
||||
|
||||
|
|
@ -10,18 +10,15 @@ import Foundation
|
|||
|
||||
struct WifiStatusConnectedView: View {
|
||||
|
||||
let userDefaults = UserDefaults.standard
|
||||
private let kPrefix = Bundle.main.bundleIdentifier!
|
||||
@EnvironmentObject var rootViewModel: RootViewModel
|
||||
|
||||
@Binding var hostName: String
|
||||
|
||||
func showConfirmationPrompt() {
|
||||
comfirmationAlertMessage(title: "Are you sure you want to disconnect?", exitTitle: "Cancel", primaryTitle: "Disconnect") {
|
||||
rootViewModel.goToSelection()
|
||||
} cancel: {
|
||||
var disconnectAction: () -> Void
|
||||
|
||||
}
|
||||
func removeAdafruitString(from boardName: String) -> String {
|
||||
let removeString = "Adafruit"
|
||||
let updatedText = boardName.replacingOccurrences(of: removeString, with: "")
|
||||
|
||||
return updatedText
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
|
|
@ -33,16 +30,13 @@ struct WifiStatusConnectedView: View {
|
|||
.frame(width: 20, height: 20)
|
||||
.padding(5)
|
||||
|
||||
Text("Connected to \(hostName). ")
|
||||
Text("Connected to \(hostName) ")
|
||||
.font(Font.custom("ReadexPro-Regular", size: 14))
|
||||
|
||||
Button {
|
||||
showConfirmationPrompt()
|
||||
} label: {
|
||||
Button(action: disconnectAction) {
|
||||
Text("Disconnect")
|
||||
.font(Font.custom("ReadexPro-Bold", size: 14))
|
||||
.underline()
|
||||
.minimumScaleFactor(0.1)
|
||||
}
|
||||
|
||||
})
|
||||
|
|
@ -71,31 +71,6 @@ class WifiSubViewCellModel: ObservableObject {
|
|||
|
||||
|
||||
|
||||
|
||||
// if success.contains("GET, OPTIONS, PUT, DELETE, MOVE") {
|
||||
//
|
||||
// print("USB not in use.")
|
||||
// DispatchQueue.main.async {
|
||||
// self.usbInUse = false
|
||||
// }
|
||||
//
|
||||
// // DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
||||
// // if wifiFileTransfer.projectDownloaded {
|
||||
// //
|
||||
// // wifiFileTransfer.testFileExistance(for: result.projectName, bundleLink: result.bundleLink)
|
||||
// //
|
||||
// // } else {
|
||||
// // downloadModel.trueDownload(useProject: result.bundleLink, projectName: result.projectName)
|
||||
// // }
|
||||
// // }
|
||||
//
|
||||
// } else {
|
||||
// DispatchQueue.main.async {
|
||||
// self.usbInUse = true
|
||||
// }
|
||||
// print("USB in use - files cannot be tranferred or moved while USB is in use. Show Error")
|
||||
// }
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
|
@ -173,7 +173,7 @@ class WifiTransferService: ObservableObject {
|
|||
}
|
||||
let base64LoginString = loginData.base64EncodedString()
|
||||
|
||||
// var request = URLRequest(url: URL(string: "http://cpy-9cbe10.local/fs/")!,timeoutInterval: Double.infinity)
|
||||
|
||||
var request = URLRequest(url: URL(string: "http://\(hostName).local/fs/")!,timeoutInterval: Double.infinity)
|
||||
|
||||
request.addValue("application/json", forHTTPHeaderField: "Accept")
|
||||
|
|
@ -226,7 +226,6 @@ class WifiTransferService: ObservableObject {
|
|||
|
||||
let loginData = loginString.data(using: String.Encoding.utf8)
|
||||
|
||||
|
||||
let base64LoginString = loginData!.base64EncodedString()
|
||||
|
||||
print("Host Name: \(hostName)")
|
||||
|
|
@ -27,6 +27,7 @@ class WifiViewModel: ObservableObject {
|
|||
@Published var ipInputValidation = false
|
||||
//Dependencies
|
||||
var networkMonitor = NetworkMonitor()
|
||||
|
||||
var networkAuth = LocalNetworkAuthorization()
|
||||
|
||||
public var wifiNetworkService = WifiNetworkService()
|
||||
|
|
@ -34,7 +35,7 @@ class WifiViewModel: ObservableObject {
|
|||
@Published var wifiTransferService = WifiTransferService()
|
||||
|
||||
@Published var wifiServiceManager = WifiServiceManager()
|
||||
|
||||
@ObservedObject var networkModel = NetworkService()
|
||||
var circuitPythonVersion = Int()
|
||||
|
||||
@Published var webDirectoryInfo = [WebDirectoryModel]()
|
||||
|
|
@ -45,9 +46,19 @@ class WifiViewModel: ObservableObject {
|
|||
|
||||
let dataStore = DataStore()
|
||||
|
||||
@Published var pdemos : [ResultItem] = []
|
||||
@Published var pdemos : [PyProject] = []
|
||||
|
||||
|
||||
func loadProjectsFromStorage() {
|
||||
self.pdemos = self.dataStore.loadDefaultList()
|
||||
}
|
||||
|
||||
func fetchAndLoadProjectsFromStorage() {
|
||||
self.networkModel.fetch {
|
||||
self.pdemos = self.dataStore.loadDefaultList()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// File Manager Data
|
||||
let directoryPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
|
|
@ -59,11 +70,10 @@ class WifiViewModel: ObservableObject {
|
|||
var ipAddressStored = false
|
||||
|
||||
init() {
|
||||
pdemos = dataStore.loadDefaultList()
|
||||
loadProjectsFromStorage()
|
||||
checkIP()
|
||||
registerNotifications(enabled: true)
|
||||
wifiServiceManager.findService()
|
||||
//read()
|
||||
}
|
||||
|
||||
/// Makes a network call to populate our project list
|
||||
|
|
@ -71,29 +81,39 @@ class WifiViewModel: ObservableObject {
|
|||
// networkModel.fetch()
|
||||
}
|
||||
|
||||
@Published var pyleapProjects = [ResultItem]()
|
||||
@Published var pyleapProjects = [PyProject]()
|
||||
|
||||
var boardDataProvider = BoardDataProvider()
|
||||
|
||||
|
||||
// This function reads the boards the boot_out.txt file to then set the current board's name and version number for file transfer.
|
||||
|
||||
func setBoardToDefault() {
|
||||
Board.shared.name = "Unrecognized Board"
|
||||
Board.shared.versionNumber = "8"
|
||||
}
|
||||
|
||||
func read() {
|
||||
setBoardToDefault()
|
||||
// This method can't be used until the device has permission to communicate.
|
||||
print("READING CP Vers.")
|
||||
wifiTransferService.getRequest(read: "boot_out.txt") { result in
|
||||
|
||||
if result.contains("CircuitPython 7") {
|
||||
WifiCPVersion.versionNumber = 7
|
||||
print("WifiCPVersion.versionNumber set to: \(WifiCPVersion.versionNumber)")
|
||||
}
|
||||
let boardID = self.boardDataProvider.getBoardID(from: result) ?? "Unrecognized Board"
|
||||
// Board default version is set to 8
|
||||
let boardVersion = self.boardDataProvider.getCircuitPythonMajorVersion(from: result) ?? "8"
|
||||
|
||||
if result.contains("CircuitPython 8") {
|
||||
WifiCPVersion.versionNumber = 8
|
||||
print("WifiCPVersion.versionNumber set to: \(WifiCPVersion.versionNumber)")
|
||||
}
|
||||
Board.shared.name = boardID
|
||||
Board.shared.versionNumber = boardVersion
|
||||
dump(Board.shared)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private weak var invalidIPObserver: NSObjectProtocol?
|
||||
|
||||
private weak var testObserver: NSObjectProtocol?
|
||||
|
|
@ -146,11 +166,6 @@ class WifiViewModel: ObservableObject {
|
|||
connectionStatus = .connected
|
||||
}
|
||||
|
||||
// @Published var connectionStatus: ConnectionStatus = AppEnvironment.isRunningTests ? .connected : .noConnection
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
func printStoredInfo() {
|
||||
print("======Stored UserDefaults======")
|
||||
53
PyLeap/Helpers/BoardDataProvider.swift
Normal file
53
PyLeap/Helpers/BoardDataProvider.swift
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// BoardDataProvider.swift
|
||||
// PyLeap
|
||||
//
|
||||
// Created by Trevor Beaton on 5/17/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
final class BoardDataProvider {
|
||||
|
||||
|
||||
func getBoardID(from prompt: String) -> String? {
|
||||
print("getBoardID function: \(prompt)")
|
||||
|
||||
let boardIDPrefix = "Board ID:"
|
||||
let uidSuffix = "UID"
|
||||
|
||||
if let startRange = prompt.range(of: boardIDPrefix) {
|
||||
let start = startRange.upperBound
|
||||
var end = prompt.endIndex
|
||||
if let endRange = prompt.range(of: uidSuffix) {
|
||||
end = endRange.lowerBound
|
||||
}
|
||||
|
||||
let range = start..<end
|
||||
let boardID = prompt[range].trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
let boardIDWithSpaces = boardID.replacingOccurrences(of: "_", with: " ")
|
||||
|
||||
let capitalizedBoardID = boardIDWithSpaces.capitalized
|
||||
print("Outgoing: \(capitalizedBoardID)")
|
||||
return capitalizedBoardID
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getCircuitPythonMajorVersion(from prompt: String) -> String? {
|
||||
print("From getCircuitPythonMajorVersion function: \(prompt)")
|
||||
let regexPattern = "CircuitPython (\\d+)"
|
||||
if let regex = try? NSRegularExpression(pattern: regexPattern) {
|
||||
let range = NSRange(location: 0, length: prompt.utf16.count)
|
||||
if let match = regex.firstMatch(in: prompt, options: [], range: range) {
|
||||
if let range = Range(match.range(at: 1), in: prompt) {
|
||||
return String(prompt[range])
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ import Foundation
|
|||
/// This is a DataStore class that is used for saving and loading data to/from the file system using the FileManager class.
|
||||
*/
|
||||
|
||||
public class DataStore {
|
||||
public class DataStore: ObservableObject {
|
||||
|
||||
let fileManager = FileManager.default
|
||||
|
||||
|
|
@ -27,8 +27,8 @@ public class DataStore {
|
|||
/// This method writes it to a file named "StandardPyLeapProjects.json" in the documents directory.
|
||||
*/
|
||||
|
||||
func save(content: [ResultItem], completion: @escaping () -> Void) {
|
||||
|
||||
func save(content: [PyProject], completion: @escaping () -> Void) {
|
||||
print(#function)
|
||||
let encoder = JSONEncoder()
|
||||
if let encodedProjectData = try? encoder.encode(content) {
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ public class DataStore {
|
|||
/// This method reads the "StandardPyLeapProjects.json" file in the documents directory and decodes it as an array of ResultItem objects, and then appends the customProjects array to it and saves it back to the file.
|
||||
*/
|
||||
|
||||
func save(customProjects: [ResultItem], completion: @escaping () -> Void) {
|
||||
func save(customProjects: [PyProject], completion: @escaping () -> Void) {
|
||||
|
||||
var temp = customProjects
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ public class DataStore {
|
|||
let savedData = try? Data(contentsOf: fileURL)
|
||||
|
||||
if let savedData = savedData,
|
||||
let savedProjects = try? JSONDecoder().decode([ResultItem].self, from: savedData) {
|
||||
let savedProjects = try? JSONDecoder().decode([PyProject].self, from: savedData) {
|
||||
NotificationCenter.default.post(name: .didCollectCustomProject, object: nil, userInfo: nil)
|
||||
temp.append(contentsOf: savedProjects)
|
||||
|
||||
|
|
@ -76,24 +76,24 @@ public class DataStore {
|
|||
let savedData = try? Data(contentsOf: fileURL)
|
||||
|
||||
if let savedData = savedData,
|
||||
let savedProjects = try? JSONDecoder().decode([ResultItem].self, from: savedData) {
|
||||
let savedProjects = try? JSONDecoder().decode([PyProject].self, from: savedData) {
|
||||
loadCustomProjectList(contents: savedProjects)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/// : This method reads the "StandardPyLeapProjects.json" file in the documents directory, decodes it as an array of ResultItem objects, and returns it.
|
||||
/// This method reads the "StandardPyLeapProjects.json" file in the documents directory, decodes it as an array of ResultItem objects, and returns it.
|
||||
*/
|
||||
|
||||
func loadDefaultList() -> [ResultItem] {
|
||||
func loadDefaultList() -> [PyProject] {
|
||||
|
||||
var result = [ResultItem]()
|
||||
var result = [PyProject]()
|
||||
let fileURL = documentsDirectory.appendingPathComponent("StandardPyLeapProjects.json")
|
||||
|
||||
let savedData = try? Data(contentsOf: fileURL)
|
||||
|
||||
if let savedData = savedData,
|
||||
let savedProjects = try? JSONDecoder().decode([ResultItem].self, from: savedData) {
|
||||
let savedProjects = try? JSONDecoder().decode([PyProject].self, from: savedData) {
|
||||
result = savedProjects
|
||||
}
|
||||
return result
|
||||
|
|
@ -107,14 +107,14 @@ public class DataStore {
|
|||
/// This method reads the "CustomProjects.json" file in the documents directory, decodes it as an array of ResultItem objects, appends it to the input array, and then calls
|
||||
*/
|
||||
|
||||
func loadCustomProjectList(contents: [ResultItem]) {
|
||||
func loadCustomProjectList(contents: [PyProject]) {
|
||||
var temp = contents
|
||||
|
||||
let fileURL = documentsDirectory.appendingPathComponent("CustomProjects.json")
|
||||
let savedData = try? Data(contentsOf: fileURL)
|
||||
|
||||
if let savedData = savedData,
|
||||
let savedProjects = try? JSONDecoder().decode([ResultItem].self, from: savedData) {
|
||||
let savedProjects = try? JSONDecoder().decode([PyProject].self, from: savedData) {
|
||||
temp.append(contentsOf: savedProjects)
|
||||
removeDuplicates(projectList: temp)
|
||||
|
||||
|
|
@ -129,9 +129,9 @@ public class DataStore {
|
|||
/// This method uses the reduce(into:_:) method to iterate over the array, and it builds a new array that only contains unique ResultItem objects based on their bundleLink property. It then calls the save(content:completion:) method to save the new array to "StandardPyLeapProjects.json" file.
|
||||
*/
|
||||
|
||||
func removeDuplicates(projectList: [ResultItem]) {
|
||||
func removeDuplicates(projectList: [PyProject]) {
|
||||
|
||||
let combinedLists = projectList.reduce(into: [ResultItem]()) { (result, projectList) in
|
||||
let combinedLists = projectList.reduce(into: [PyProject]()) { (result, projectList) in
|
||||
|
||||
if !result.contains(where: { $0.bundleLink == projectList.bundleLink }) {
|
||||
result.append(projectList)
|
||||
|
|
@ -146,7 +146,7 @@ public class DataStore {
|
|||
let savedData = try? Data(contentsOf: fileURL)
|
||||
|
||||
if let savedData = savedData,
|
||||
let savedProjects = try? JSONDecoder().decode([ResultItem].self, from: savedData) {
|
||||
let savedProjects = try? JSONDecoder().decode([PyProject].self, from: savedData) {
|
||||
|
||||
for project in savedProjects {
|
||||
print("CustomProjects name: \(project.projectName)")
|
||||
|
|
|
|||
|
|
@ -8,11 +8,24 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
struct RootResults: Decodable {
|
||||
let projects: [ResultItem]
|
||||
|
||||
struct RootResults: Codable {
|
||||
let formatVersion: Int
|
||||
let fileVersion: Int
|
||||
let projects: [PyProject]
|
||||
}
|
||||
|
||||
struct ResultItem: Codable, Identifiable, Equatable {
|
||||
struct PyProject: Codable, Identifiable, Equatable {
|
||||
var id: UUID = UUID()
|
||||
let projectName: String
|
||||
let projectImage: String
|
||||
let description: String
|
||||
let bundleLink: String
|
||||
let learnGuideLink: String
|
||||
let compatibility: [String]
|
||||
let bluetoothCompatible: Bool
|
||||
let wifiCompatible: Bool
|
||||
|
||||
enum CodingKeys: CodingKey {
|
||||
case projectName
|
||||
case projectImage
|
||||
|
|
@ -20,15 +33,21 @@ struct ResultItem: Codable, Identifiable, Equatable {
|
|||
case bundleLink
|
||||
case learnGuideLink
|
||||
case compatibility
|
||||
case bluetoothCompatible
|
||||
case wifiCompatible
|
||||
}
|
||||
|
||||
var id = UUID()
|
||||
let projectName: String
|
||||
let projectImage: String
|
||||
let description: String
|
||||
let bundleLink: String
|
||||
let learnGuideLink: String
|
||||
let compatibility: [String]
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.projectName = try container.decode(String.self, forKey: .projectName)
|
||||
self.projectImage = try container.decode(String.self, forKey: .projectImage)
|
||||
self.description = try container.decode(String.self, forKey: .description)
|
||||
self.bundleLink = try container.decode(String.self, forKey: .bundleLink)
|
||||
self.learnGuideLink = try container.decode(String.self, forKey: .learnGuideLink)
|
||||
self.compatibility = try container.decode([String].self, forKey: .compatibility)
|
||||
self.bluetoothCompatible = try container.decode(Bool.self, forKey: .bluetoothCompatible)
|
||||
self.wifiCompatible = try container.decode(Bool.self, forKey: .wifiCompatible)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import Foundation
|
|||
import SwiftUI
|
||||
|
||||
class NetworkService: ObservableObject {
|
||||
|
||||
let dataStore = DataStore()
|
||||
|
||||
let thirdPartyBackgroundQueue = DispatchQueue(label: "com.PyLeap.thirdPartyBackgroundQueue", qos: .background, attributes: .concurrent)
|
||||
|
|
@ -34,39 +35,40 @@ class NetworkService: ObservableObject {
|
|||
|
||||
func fetch(completion: @escaping() -> Void) {
|
||||
print("Attempting Network Request")
|
||||
let request = URLRequest(url: URL(string: AdafruitInfo.baseURL)!, cachePolicy: URLRequest.CachePolicy.returnCacheDataElseLoad, timeoutInterval: 60.0)
|
||||
let request = URLRequest(url: URL(string: AdafruitInfo.baseURL)!)
|
||||
let task = session.dataTask(with: request) { data, response, error in
|
||||
|
||||
if let error = error {
|
||||
print("error: \(error)")
|
||||
}
|
||||
|
||||
if let data = data {
|
||||
|
||||
print("Updating UIList with new data...")
|
||||
if let projectData = try? JSONDecoder().decode(RootResults.self, from: data) {
|
||||
|
||||
DispatchQueue.main.async {
|
||||
|
||||
self.dataStore.save(content: projectData.projects, completion: self.dataStore.loadDefaultProjectList)
|
||||
|
||||
completion()
|
||||
}
|
||||
} else {
|
||||
print("No data found")
|
||||
}
|
||||
} else {
|
||||
print("Updating UIList with Cached data...")
|
||||
DispatchQueue.main.async {
|
||||
self.dataStore.loadDefaultProjectList()
|
||||
completion()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if let data = data {
|
||||
print("Updating storage with new data.")
|
||||
do {
|
||||
let projectData = try JSONDecoder().decode(RootResults.self, from: data)
|
||||
dump(projectData.projects)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.dataStore.save(content: projectData.projects, completion: self.dataStore.loadDefaultProjectList)
|
||||
completion()
|
||||
}
|
||||
} catch {
|
||||
print("Decoding error: \(error)")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
task.resume()
|
||||
}
|
||||
|
||||
|
||||
|
||||
func fetchThirdPartyProject(urlString: String?) {
|
||||
|
||||
thirdPartyBackgroundQueue.async {
|
||||
|
|
|
|||
|
|
@ -175,6 +175,9 @@ Find more information on adding your own project here:
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
extension View {
|
||||
|
||||
func comfirmationAlertMessage(title: String, exitTitle: String, primaryTitle: String,disconnect: @escaping() -> (),cancel: @escaping() -> ()){
|
||||
|
|
@ -31,5 +31,10 @@ extension View {
|
|||
}
|
||||
}
|
||||
|
||||
func formatDeviceName(_ name: String) -> String {
|
||||
let replaced = name.replacingOccurrences(of: "_", with: " ").replacingOccurrences(of: "-", with: " ")
|
||||
let formatted = replaced.capitalized
|
||||
return formatted
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
BIN
PyLeap/Views/.DS_Store
vendored
BIN
PyLeap/Views/.DS_Store
vendored
Binary file not shown.
|
|
@ -1,246 +0,0 @@
|
|||
//
|
||||
// MainSelectionView.swift
|
||||
// PyLeap
|
||||
//
|
||||
// Created by Trevor Beaton on 10/16/21.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import FileTransferClient
|
||||
|
||||
enum AdafruitDevices {
|
||||
case clue_nrf52840_express
|
||||
case circuitplayground_bluefruit
|
||||
case esp32s2
|
||||
}
|
||||
|
||||
struct MainSelectionView: View {
|
||||
|
||||
@State private var showWebViewPopover: Bool = false
|
||||
|
||||
@State private var inConnectedInSelectionView = true
|
||||
@State private var boardBootInfo = ""
|
||||
@EnvironmentObject var expandedState : ExpandedBLECellState
|
||||
|
||||
@ObservedObject var viewModel = MainSelectionViewModel()
|
||||
|
||||
|
||||
@State private var isConnected = false
|
||||
|
||||
@State private var test = ""
|
||||
|
||||
@State private var nilBinder = DownloadState.idle
|
||||
@EnvironmentObject var rootViewModel: RootViewModel
|
||||
|
||||
@AppStorage("shouldShowOnboarding") var shouldShowOnboarding: Bool = true
|
||||
|
||||
var body: some View {
|
||||
|
||||
VStack(alignment: .center, spacing: 0) {
|
||||
MainHeaderView()
|
||||
|
||||
HStack(alignment: .center, spacing: 8, content: {
|
||||
Text("Not Connected to a Device.")
|
||||
.font(Font.custom("ReadexPro-Regular", size: 16))
|
||||
Button {
|
||||
rootViewModel.goToSelection()
|
||||
} label: {
|
||||
Text("Connect Now")
|
||||
.font(Font.custom("ReadexPro-Regular", size: 16))
|
||||
.underline()
|
||||
}
|
||||
|
||||
})
|
||||
.padding(.all, 0.0)
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(maxHeight: 40)
|
||||
.background(Color("pyleap_burg"))
|
||||
.foregroundColor(.white)
|
||||
|
||||
ScrollView {
|
||||
|
||||
MainSubHeaderView(device: "Adafruit device")
|
||||
|
||||
if viewModel.pdemos.isEmpty {
|
||||
HStack{
|
||||
Spacer()
|
||||
ProgressView()
|
||||
.scaleEffect(2)
|
||||
Spacer()
|
||||
}
|
||||
.padding(0)
|
||||
|
||||
}
|
||||
|
||||
ScrollViewReader { scroll in
|
||||
|
||||
|
||||
|
||||
|
||||
ForEach(viewModel.pdemos) { demo in
|
||||
|
||||
if demo.bundleLink == expandedState.currentCell {
|
||||
|
||||
DemoViewCell(result: demo, isExpanded: true, isConnected: $inConnectedInSelectionView, deviceInfo: $boardBootInfo, onViewGeometryChanged: {
|
||||
})
|
||||
.onAppear(){
|
||||
print("Cell Appeared")
|
||||
withAnimation {
|
||||
scroll.scrollTo(demo.id)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
DemoViewCell(result: demo, isExpanded: false, isConnected: $inConnectedInSelectionView, deviceInfo: $boardBootInfo, onViewGeometryChanged: {
|
||||
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.onDisappear() {
|
||||
|
||||
}
|
||||
|
||||
/// **Pull down to Refresh feature**
|
||||
// ScrollRefreshableView(title: "Refresh", tintColor: .purple) {
|
||||
// HStack{
|
||||
// Spacer()
|
||||
// MainSubHeaderView()
|
||||
// Spacer()
|
||||
// }
|
||||
// .padding(0)
|
||||
//
|
||||
// if networkModel.pdemos.isEmpty {
|
||||
// HStack{
|
||||
// Spacer()
|
||||
// ProgressView()
|
||||
// .scaleEffect(2)
|
||||
// Spacer()
|
||||
// }
|
||||
// .padding(0)
|
||||
//
|
||||
// }
|
||||
//
|
||||
// }// } onRefresh: {
|
||||
// self.networkModel.fetch()
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
.onChange(of: viewModel.pdemos, perform: { newValue in
|
||||
print("Update")
|
||||
|
||||
|
||||
})
|
||||
.onAppear() {
|
||||
|
||||
|
||||
print("Opened MainSelectionView")
|
||||
}
|
||||
|
||||
.fullScreenCover(isPresented: $shouldShowOnboarding, content: {
|
||||
ExampleView(shouldShowOnboarding: $shouldShowOnboarding)
|
||||
})
|
||||
.preferredColorScheme(.light)
|
||||
.background(Color.white)
|
||||
.navigationBarColor(UIColor(named: "pyleap_gray"))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//struct MainSelectionView_Previews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// MainSelectionView()
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//struct MainSelectionView: View {
|
||||
//
|
||||
// @State private var showWebViewPopover: Bool = false
|
||||
// @ObservedObject var networkModel = NetworkService()
|
||||
// @ObservedObject var viewModel = MainSelectionViewModel()
|
||||
// @State private var test = ""
|
||||
// @State private var nilBinder = DownloadState.idle
|
||||
// @EnvironmentObject var rootViewModel: RootViewModel
|
||||
// @AppStorage("shouldShowOnboarding") var shouldShowOnboarding: Bool = true
|
||||
//
|
||||
// var body: some View {
|
||||
// VStack(alignment: .center, spacing: 0) {
|
||||
// MainHeaderView()
|
||||
// connectionMessageView()
|
||||
// ScrollView {
|
||||
// MainSubHeaderView(device: "Adafruit device")
|
||||
// if networkModel.pdemos.isEmpty {
|
||||
// loadingIndicatorView()
|
||||
// }
|
||||
// ScrollViewReader { scroll in
|
||||
// ForEach(networkModel.pdemos) { demo in
|
||||
// demoViewCell(demo: demo, scroll: scroll)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private func connectionMessageView() -> some View {
|
||||
// HStack(alignment: .center, spacing: 8) {
|
||||
// Text("Not Connected to a Device.")
|
||||
// .font(Font.custom("ReadexPro-Regular", size: 16))
|
||||
// Button {
|
||||
// rootViewModel.goToSelection()
|
||||
// } label: {
|
||||
// Text("Connect Now")
|
||||
// .font(Font.custom("ReadexPro-Regular", size: 16))
|
||||
// .underline()
|
||||
// }
|
||||
// }
|
||||
// .padding(.all, 0.0)
|
||||
// .frame(maxWidth: .infinity)
|
||||
// .frame(maxHeight: 40)
|
||||
// .background(Color("pyleap_burg"))
|
||||
// .foregroundColor(.white)
|
||||
// }
|
||||
//
|
||||
// private func loadingIndicatorView() -> some View {
|
||||
// HStack{
|
||||
// Spacer()
|
||||
// ProgressView()
|
||||
// .scaleEffect(2)
|
||||
// Spacer()
|
||||
// }
|
||||
// .padding(0)
|
||||
// }
|
||||
//
|
||||
// private func demoViewCell(demo: Demo, scroll: ScrollViewProxy) -> some View {
|
||||
// if demo.bundleLink == expandedState.currentCell {
|
||||
// DemoViewCell(result: demo, isExpanded: true, isConnected: $inConnectedInSelectionView, deviceInfo: $boardBootInfo, onViewGeometryChanged: {
|
||||
// })
|
||||
// .onAppear(){
|
||||
// print("Cell Appeared")
|
||||
// withAnimation {
|
||||
// scroll.scrollTo(demo.id)
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// DemoViewCell(result: demo, isExpanded: false, isConnected: $inConnectedInSelectionView, deviceInfo: $boardBootInfo, onViewGeometryChanged: {
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in a new issue