Compare commits

...

3 commits

Author SHA1 Message Date
TrevKnows
a34e2bf6d3 Board ID Fix - Pass 1
BLE boards running CircuitPython 7+ are now compatible with PyLeap.

It was tested using Circuit Playground Bluefruit Express, CLUE nRF52840 Express, and Feather nRF52840.

I also added a placeholder for boards without specific images.
2023-05-24 00:59:59 -04:00
TrevKnows
e5bb6df771 First Commit 2023-05-17 12:08:13 -04:00
TrevKnows
976bf512fa Removed local reference from source file 2023-03-29 15:34:07 -04:00
19 changed files with 561 additions and 818 deletions

View file

@ -12,10 +12,10 @@
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 */; };
@ -84,6 +84,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 */; };
@ -119,10 +121,10 @@
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>"; };
@ -194,6 +196,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>"; };
@ -278,6 +282,7 @@
D59DFDB5268CD052001737F6 /* AppEnvironment.swift */,
D534F3FB280B59090053699C /* ExampleView.swift */,
D544A2502822D4730038D483 /* Spotlight Extension.swift */,
D5BBD12A2A15389400961B68 /* Helpers */,
D567E2B428B80DC10009F768 /* Outline.md */,
D5C74DF027EB92E900730505 /* Model */,
D59DFDB2268CCEAC001737F6 /* Views */,
@ -388,8 +393,8 @@
D5269C07291AB75800C0CE4B /* WifiPairingView.swift */,
D52A926E29078E0A00973B6B /* WifiServiceSelectionView.swift */,
D5269BFF291960A300C0CE4B /* WifiSelection.swift */,
D5269C01291997DE00C0CE4B /* WifiServiceCellView.swift */,
D5269C032919985400C0CE4B /* WifiServiceCellSubView.swift */,
D520D68F29D4C9380022048D /* WifiServiceCellView.swift */,
D520D69129D4C9900022048D /* WifiServiceCellSubView.swift */,
D5BA1F7E28B66F280012FC62 /* WifiServiceManager.swift */,
D5DD39A628D11817000FAEB8 /* WifiFileTransfer.swift */,
D5DD39A828D11962000FAEB8 /* WifiTransferService.swift */,
@ -438,6 +443,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 +548,7 @@
children = (
D59E31A9281B8DD300D24211 /* DownloadState.swift */,
D5507ACB26C668BC00512BAA /* BleModuleView.swift */,
D5BBD12D2A1C6AB300961B68 /* BleBannerView.swift */,
D5507ACC26C668BC00512BAA /* BleModuleViewModel.swift */,
D5199A2E28DD16F100ACC34C /* BleContentTransfer.swift */,
D5D5BB3828DD19F000E5D93F /* BleContentCommands.swift */,
@ -659,6 +673,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 +693,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 */,
@ -743,14 +758,15 @@
D56B75D4294BAAB400D008E7 /* BLESettingsView.swift 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;
};
@ -881,21 +897,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 = 16.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.1.1;
MARKETING_VERSION = 2.1.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;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "PyLeap/Views/Wifi View/PyLeap-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@ -911,21 +928,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 = 16.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.1.1;
MARKETING_VERSION = 2.1.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;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "PyLeap/Views/Wifi View/PyLeap-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";

View 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
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -0,0 +1,56 @@
//
// 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
}
}

BIN
PyLeap/Views/.DS_Store vendored

Binary file not shown.

View 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")
})
}
}

View file

@ -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
@ -102,10 +101,7 @@ class BleContentCommands: ObservableObject {
case .success(let data):
self.lastTransmit = TransmissionLog(type: .read(data: data))
let str = String(decoding: data, as: UTF8.self)
print("Read: \(str)")
self.bootUpInfo = str
sharedBootinfo = str
print("Read: \(str)")
case .failure(let error):
self.lastTransmit = TransmissionLog(type: .error(message: error.localizedDescription))

View file

@ -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
@ -31,19 +47,14 @@ class BleContentTransfer: ObservableObject {
@Published var transferError = false
@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
@ -57,11 +68,13 @@ 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?
@ -310,14 +307,7 @@ class BleContentTransfer: ObservableObject {
}
}
}
// filterCPVersion(incomingArray: regularFileUrls)
// filterCPFiles(filesArray: regularFileUrls)
// pathManipulation(arrayOfAny: filterCPVersion(incomingArray: projectDirectories), regularArray: filterCPVersion(incomingArray: projectFiles))
projectDirectories.removeFirst()
DispatchQueue.main.async {
@ -336,70 +326,28 @@ 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)")
}
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)")
}
let listForCurrentCPVersion = filteredList.filter {
$0.absoluteString.contains("CircuitPython%20\(Board.shared.versionNumber).x")
}
return listForCurrentCPVersion
}
return listWithoutCP7Folder
}
func makeDirectory(directoryArray: [URL], regularFilesArray: [URL]) {
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")!
print(tempPathComponents)
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()
}
} else {
guard let data = try? Data(contentsOf: URL(string: copiedFiles.first!.absoluteString)!) else {
print("File not found")
return
}
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
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)
}
}
}
} 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)
}
}
}
}
return
}
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 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)
contentCommands.writeFileCommand(path: path, data: data) { result in
switch result {
case .success:
print("Success ✅")
self.newTransfer(listOf: Array(urls.dropFirst()))
case .failure(let error):
print("Transfer Failure \(error)")
self.handleTransferError(error)
}
}
}
func filePathMod(listOf files: [URL]) {
var indexOfCP = 0
for i in files {
print("-\(i.absoluteString)-\n")
}
var tempArray = files
if files.isEmpty {
// Continue
private func handleTransferError(_ error: Error) {
DispatchQueue.main.async {
print("\(#function) @Line: \(#line)")
print("Done!")
// print("RETURNED PATHS: \(returnedArray)\n")
for i in filesReadyForTransfer {
print("\(i)")
print(error)
self.downloadState = .failed
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.downloadState = .idle
}
// 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)
}
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 completedTransfer() {
DispatchQueue.main.async {
self.downloadState = .complete
self.didCompleteTranfer = true
@ -824,186 +581,7 @@ 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

View file

@ -12,24 +12,31 @@ 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: "DefaultName", versionNumber: "DefaultVersion")
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
@ -44,7 +51,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 +124,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 +139,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)
}
@ -170,89 +185,14 @@ struct BleModuleView: View {
HeaderView()
VStack {
BleBannerView(deviceName: boardInfoForView?.name ?? "Unknown Device", disconnectAction: {
showConfirmationPrompt()
})
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 {
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 +210,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 = viewModel.pdemos.filter {
$0.compatibility.contains(boardBootInfo)
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
}
}
@ -329,39 +287,24 @@ struct BleModuleView: View {
viewModel.setup(fileTransferClient: selectedClient)
}
.onChange(of: viewModel.connectedBoard, perform: { newValue in
dump(newValue)
boardInfoForView = newValue
unknownBoardName = newValue?.name
})
.onAppear(){
print("Opened BleModuleView")
// networkServiceModel.fetch()
viewModel.setup(fileTransferClient:connectionManager.selectedClient)
connectionManager.isSelectedPeripheralReconnecting = true
viewModel.readFile(filename: "boot_out.txt")
}
}
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")) {})
}
})
}
}
}
struct ViewHeightKey: PreferenceKey {

View file

@ -10,30 +10,45 @@ import Zip
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 = ""
var boardDataProvider = BoardDataProvider()
var connectedBoard: Board?
let dataStore = DataStore()
@Published var pdemos : [ResultItem] = []
init() {
pdemos = dataStore.loadDefaultList()
pdemos = dataStore.loadDefaultList()
self.delegate = contentTransfer
}
enum ProjectViewError: LocalizedError {
case fileTransferUndefined
}
func readMyStatus() {
print("BOOT INFO: \(bootUpInfo)")
switch bootUpInfo.description {
@ -41,11 +56,11 @@ class BleModuleViewModel: ObservableObject {
case let str where str.contains("circuitplayground_bluefruit"):
print("Circuit Playground Bluefruit device")
bootUpInfo = "circuitplayground_bluefruit"
case let str where str.contains("clue_nrf52840_express"):
print("Clue device")
bootUpInfo = "clue_nrf52840_express"
default:
print("Unknown Device")
}
@ -71,7 +86,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
@ -100,7 +114,7 @@ class BleModuleViewModel: ObservableObject {
return modeText
}
}
// MARK: - Setup
func onAppear() {
//registerNotifications(enabled: true)
@ -121,6 +135,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 +171,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 +382,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
}
}
}

View file

@ -10,13 +10,13 @@ import FileTransferClient
struct DemoSubview: View {
@Binding var bindingString: String
let result: ResultItem
@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,16 +150,7 @@ 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 {
Button(action: {
@ -210,7 +201,7 @@ Try again later
CompleteButton()
.padding(.top, 20)
}
}
} else {
@ -231,9 +222,7 @@ 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
if newValue {
@ -246,15 +235,9 @@ Try again later
showDownloadErrorMessage()
}
})
// .onChange(of: connectionManager.selectedClient) { selectedClient in
// viewModel.setup(fileTransferClient: selectedClient)
// }
.onAppear(perform: {
contentTransfer.readMyStatus()
viewModel.searchPathForProject(nameOf: result.projectName)
if viewModel.projectDownloaded {

View file

@ -36,7 +36,7 @@ struct DemoViewCell: View {
if isExpanded {
Group {
DemoSubview(bindingString: $deviceInfo, result: result, isConnected: $isConnected)
DemoSubview(result: result, isConnected: $isConnected)
}
}

View file

@ -16,8 +16,6 @@ struct WifiHeaderView: View {
VStack {
HStack (alignment: .center, spacing: 0) {
Image(systemName: "gearshape")

View file

@ -18,7 +18,7 @@ enum AdafruitDevices {
@State private var showWebViewPopover: Bool = false
@State private var inConnectedInSelectionView = true
@State private var inConnectedInSelectionView = false
@State private var boardBootInfo = ""
@EnvironmentObject var expandedState : ExpandedBLECellState
@ -162,85 +162,6 @@ enum AdafruitDevices {
}
//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: {
// })
// }
// }
//}

View 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)
// }
//}

View file

@ -0,0 +1,87 @@
//
// 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() }
}
}
//struct WifiServiceCellView_Previews: PreviewProvider {
// static var previews: some View {
// WifiServiceCellView()
// }
//}

View file

@ -69,32 +69,7 @@ class WifiSubViewCellModel: ObservableObject {
print("Failure")
}
// 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")
// }
})

View file

@ -63,7 +63,6 @@ class WifiViewModel: ObservableObject {
checkIP()
registerNotifications(enabled: true)
wifiServiceManager.findService()
//read()
}
/// Makes a network call to populate our project list