Posts

Post not yet marked as solved
1 Replies
319 Views
I have a state var: @State var gameType: Int = 1 and I have two radio buttons that set it to either 1 or 2: gameTypeRadioButtonView(index: 1, selectedIndex: $gameType) gameTypeRadioButtonView(index: 2, selectedIndex: $gameType) did a record UI Unit test that launches the app and clicks the button to set gameType from its initial default of 1 to 2 How do I validate that in the unit test? Like there's plenty of samples for statictext and others, but I can't find anything for just verifying that the radio button did the thing. related: how would one test that text that should only be visible when gameType is 2 is working? i.e.: if gameType != 1 { Text("Blue Score") Text(String(bluePlayerScore)) .frame(width: 25, height: 22, alignment: .center) } (yes, I know I can test this other ways, but it's a class project and they want unit tests so...)
Posted Last updated
.
Post not yet marked as solved
6 Replies
602 Views
apologies for the title, but I can't think of a more descriptive one. This is a bit long, apologies. I have my SOS game: https://github.com/johncwelch/SOS-Swift Now, there's one thing making me a bit batty. So I have my grid: Grid (horizontalSpacing: 0, verticalSpacing: 0){ ForEach(0..<boardSize, id: \.self) { row in GridRow { ForEach(0..<boardSize, id: \.self) { col in GeometryReader { gridCellSize in Button { var theTuple = buttonClickStuff(for: gridCellArr[myIndex].index, theTitle: gridCellArr[myIndex].title, myArray: gridCellArr) gridCellArr[myIndex].title = theTuple.myTitle buttonBlank = theTuple.myCommitButtonStatus lastButtonClickedIndex = gridCellArr[myIndex].index } label: { Text(gridCellArr[myIndex].title) .font(.system(size: 36, weight: .heavy, design: .serif)) .frame(width: gridCellSize.frame(in: .global).width,height: gridCellSize.frame(in: .global).height, alignment: .center) } .background(gridCellArr[myIndex].backCol) .border(Color.black) .onAppear(perform: { gridCellArr[myIndex].xCoord = col gridCellArr[myIndex].yCoord = row }) } } } } } } and here's the function buttonClickStuff(): func buttonClickStuff(for myIndex: Int, theTitle: String, myArray: [Cell]) -> (myColor: Color, myTitle:String, myCommitButtonStatus: Bool) { var theCommitButtonStatus: Bool = false var theCellTitle: String = "" switch theTitle { case "": theCellTitle = "S" theCommitButtonStatus = false case "S": theCellTitle = "O" theCommitButtonStatus = false case "O": theCellTitle = "" theCommitButtonStatus = true default: print("Something went wrong, try restarting the app") } let theColor: Color = Color.blue let theReturnTuple = (myColor: theColor, myTitle: theCellTitle, myCommitButtonStatus: theCommitButtonStatus) return theReturnTuple } and just for completeness sake, here's Cell that makes up the cell array: @Observable class Cell: Identifiable { let id = UUID() var title: String = "" var buttonToggled: Bool = false var index: Int = 0 var xCoord: Int = 0 var yCoord: Int = 0 var backCol: Color = .gray } so now I have a button that I need to be disabled or enabled based on the contents of a cell: Button { gridCellArr[lastButtonClickedIndex].backCol = .green } label: { Text("Commit Move") } .disabled(buttonBlank) and buttonBlank is an @State var along with boardSize: @State var boardSize: Int = 3 @State var buttonBlank: Bool = true so the idea is, the board is built, all cells have a title of "" (blank) and Commit Move is disabled: the first time a button is clicked, its title should change to S and commit move is enabled second click, title changes to O, commit move is still enabled third click, title changes to "", commit move is disabled. So a three-click rotation: "", "S", "O" what i'm actually getting is a four click rotation: first click, button doesn't visibly change, but it thinks the title is now "S" and the commit move button is enabled second click, Button does visibly change to "S", title is STILL "S", and the commit move button is enabled third click, button visibly changes to "O", title is "O" and the commit move button is enabled fourth click, button visibly changes to "", title is "" and the commit move button is disabled that's the cycle, but it gets weirder. suppose on button 0, i leave it at "S" or "O". Then i click on button 1. I get: first click: button does visibly change to "S", title is "S", and the commit move button is enabled second click: button visibly changes to "O", title is "O" and the commit move button is enabled third click: BOTH buttons change to "", title for both is "" and the commit move button is disabled if I keep clicking, it goes back to a four-click cycle if I move the buttonBlank @state var underneath body, the "all buttons blank" problem goes away, it's a three click cycle as I expect, but buttonBlank never changes so the commit move button is always disabled. what the heck? I am SO confused right now.
Posted Last updated
.
Post not yet marked as solved
0 Replies
232 Views
Okay, was able to create a much smaller repro. ContentView.swift: import SwiftUI struct ContentView: View { @State var gridSize = 3 @State var selected = 0 @State var aCount = 0 @State var theToggle = true var theTitle = "test" @State var buttonBlank: Bool = true var body: some View { @State var gridCellArr = buildStructArray(theGridSize: gridSize) HStack { Button { } label: { Text("Commit Move") } .disabled(buttonBlank) } Grid(horizontalSpacing: 0, verticalSpacing: 0) { ForEach(0..<gridSize, id: \.self) { row in GridRow { ForEach(0..<gridSize, id: \.self) { col in GeometryReader { proxy in let index = row * gridSize + col Button { var theTuple = doSomethingElseOnClick(for: gridCellArr[index].index, myArray: gridCellArr) gridCellArr[index].backCol = theTuple.myColor gridCellArr[index].title = theTuple.myTitle } label: { Text(gridCellArr[index].title) .font(.system(size: 36, weight: .heavy, design: .serif)) .frame(width: proxy.frame(in: .global).width,height: proxy.frame(in: .global).height) } .background(gridCellArr[index].backCol) .border(Color.black) .onAppear(perform: { gridCellArr[index].xCoord = col gridCellArr[index].yCoord = row }) } } } } } } } and the class + two other functions used: import SwiftUI import Foundation @Observable class Cell: Identifiable { let id = UUID() var title: String = "" var buttonToggled: Bool = false var index: Int = 0 var xCoord: Int = 0 var yCoord: Int = 0 var backCol: Color = .gray } func buildStructArray(theGridSize: Int) -> [Cell] { var myStructArray: [Cell] = [] let arraySize = (theGridSize * theGridSize) - 1 for i in 0...arraySize { myStructArray.append(Cell()) } for i in 0...arraySize { myStructArray[i].index = i } return myStructArray } func doSomethingElseOnClick(for myIndex: Int, myArray: [Cell]) -> (myColor: Color, myTitle: String, myCommitButtonStatus: Bool) { var theCommitButtonStatus: Bool = true switch myArray[myIndex].title { case "": myArray[myIndex].title = "S" theCommitButtonStatus = false case "S": myArray[myIndex].title = "O" theCommitButtonStatus = false case "O": myArray[myIndex].title = "" theCommitButtonStatus = true default: print("Something went wrong, try restarting the app") } if myArray[myIndex].title == "Button" { print("it's a button") } var theColor: Color if myIndex <= 7 { let testIndex = myIndex + 1 print("\(myArray[testIndex].index)") theColor = Color.green } else { let testIndex = myIndex - 1 print("\(myArray[testIndex].index)") theColor = Color.blue } let theReturnTuple = (myColor: theColor, myTitle: myArray[myIndex].title, myCommitButtonStatus: theCommitButtonStatus) return theReturnTuple //return theColor } same issue with this as before: the idea is, the board is built, all cells have a title of "" (blank) and Commit Move is disabled: the first time a button is clicked, its title should change to S and commit move is enabled second click, title changes to O, commit move is still enabled third click, title changes to "", commit move is disabled. So a three-click rotation: "", "S", "O". What i'm actually getting is a four click rotation: first click, button doesn't visibly change, but it thinks the title is now "S" and the commit move button is enabled second click, Button does visibly change to "S", title is STILL "S", and the commit move button is enabled third click, button visibly changes to "O", title is "O" and the commit move button is enabled fourth click, button visibly changes to "", title is "" and the commit move button is disabled That's the cycle, but it gets weirder. suppose on button 0, i leave it at "S" or "O". Then i click on button 1. I get: first click: button does visibly change to "S", title is "S", and the commit move button is enabled second click: button visibly changes to "O", title is "O" and the commit move button is enabled third click: BOTH buttons change to "", title for both is "" and the commit move button is disabled if I keep clicking, it goes back to a four-click cycle if I move the buttonBlank @state var underneath body, the "all buttons blank" problem goes away, it's a three click cycle as I expect, but buttonBlank never changes so the commit move button is always disabled. i am absolutely sure it's related to how I manipulate buttonBlank, because even if I have a line in the grid button click action block that just reads buttonBlank = false or self.buttonBlank = false I get the same behavior. i am absolutely confused as to why though.
Posted Last updated
.
Post not yet marked as solved
6 Replies
722 Views
I have a fairly simple grid layout: @State var gridSize = 3 @State var selected = 0 @State var aCount = 0 var body: some View { Grid (horizontalSpacing: 0, verticalSpacing: 0) { ForEach(0..<gridSize, id: \.self) { row in GridRow{ ForEach(0..<gridSize, id: \.self) { col in Rectangle() .foregroundColor(.gray) .overlay(Text("\(aCount)")) .border(Color.black) .bold() } } } } } } This creates a grid of gridSize x gridsize grey rectangles, so 3x3 in this version and in a class file I have a fairly simple function that increments an int passed to it by 1 and returns that new value: let theCounter = theCount + 1 return theCounter } how do I use that function to increment aCount in the inner foreach loop? This does not seem like it should be impossible, and yet... any help is appreciated (Background: aCount is needed because I need to be able to have a click action in button 0,0 read the states of say, buttons 0,1 and 0,2 and have another function possibly change the state of all three depending on what is in 0,0, so aCount is used to help me manage an array of buttons. (i have been told there's easier ways than an array of buttons to do this, but none of the explanations have worked for my level of inexperience, so an array of buttons is something I at least understand.
Posted Last updated
.
Post not yet marked as solved
0 Replies
880 Views
I'm specifically talking about macOS because the others are very different beasts. Since, well literally the first release of OS X 10.0, there has not been a coherent automation framework on the Mac. The last OS to offer that was Mac OS 9.X To define terms, by coherent, I mean from the command line environment up through the user interface. A single, coherent automation framework that is usable across the entire OS, ala PowerShell on windows. That doesn't exist for current macOS, nor has it ever existed for any variant of macOS since again, Mac OS 9.X At best it has been a pastiche of completely different frameworks, operating modalities and languages all desperately trying to work together via osascript and do shell script. That any of it works at all is like a talking dog: the fact the dog talks is a miracle, bad grammar is minor. Yes, I know Shortcuts exist, but shortcuts are a developer managed bit of pseudo-automation. If I limit myself to Shortcuts, then I have little to no ability to do anything beyond what the developer of that application chooses to allow me to do. For example, at least as of Ventura, Dictionary, Font Book, iMovie and others have no shortcuts. I can't create my own shortcut for those apps, the devs have to do that. (the fact that Apple is not flooding us with Shortcuts shows how little Apple cares as a company about this. Individual teams wax good and bad, but clearly, Apple doesn't think dogfooding here is important.) (Note: if your only comment is to ask why anyone would care about automating , that's absolutely not the point. The idea is to make it possible for everyone, not just developers, to create in ways no one can predict outside of an application's constraints.) "Well, there's always AppleScript/JXA" I will not write down the laughter here, but there is laughter. As of Ventura, there are no less than 32 Apple applications with no scripting dictionary at all, so neither AppleScript/JXA can work. You might be able to use UI scripting, but no guarantee there, and UI scripting is a fragile thing, at best suited to a last resort option. Again, Apple could lead the way, they choose not to. But that's only the UI levels. Below the UI, then there's no coherency at all. You're stuck with shell scripts and whatever a given utility's author chose to allow, and sharing data and information is no better than at the UI level, and neither the command line level nor the UI level know the other exists. The only way to combine the two is again: Do Shell Script Osascript That is not a coherent automation framework. Then of course, there's the lack of documentation. AppleScript has inherited at least the language guide, which is well-written and usable, but the command line level has man pages. Which are the most inconsistent things. Some utilities' man pages are remarkably useful, others don't even have man pages. At all. Other utilities man pages have syntax errors for the command that brings up the help page and that is all the man page does. Ponder the disconnect there: --help provides detailed usage information that is not in the man page. The man page says use ---help which is bad syntax. This seems odd, but why is the --help output not also in the man page? Is that not the purpose of the man page? Man page inconsistencies aside, Apple developer support has only ever barely acknowledged automation/scripting and really never supported it except for accidentally. Even in a language like AppleScriptObjecttiveC, (ASOC) which one can use for real apps in the MAS, the response from DTS for help was "use the mailing list." (not that DTS is that good anyway, I had an issue with CoreWLAN in ventura, and have since been ghosted on any notification that the OS bug that was causing me problems has been fixed. Maybe it has, maybe it hasn't. I can test for it, but why did DTS ghost an actual SwiftUI issue for an app written in Swift? ¯_(ツ)_/¯ This is a solveable problem, Microsoft has solved it in terms of language, documentation and coherency, with PowerShell. Leaving aside architectural issues that make it almost impossible to properly secure windows, the way MS treats PowerShell is the example. Windows as an OS has excellent support for automation, the documentation for PowerShell is amazing, (the documentation for a scripting language is better than Apple's entire developer docs, which is just inexcusable.) The difference between automating either platform is night and day, and in a race with two horses, Apple is a distant fifth. The language syntax here is almost a non-issue. In fact, I think using a "powershell'd" version of Swift would be an excellent idea. Create a simpler version of swift in the way PowerShell is a simpler version of C#. Make it so if you need to call a framework outside of the main automation framework, you can do so with ease, ala PowerShell. For example, PowerShell has no GUI primitives the way AppleScript does, so to create a file choose browser in PowerShell, you instead invoke the correct .NET framework: Add-Type -AssemblyName System.Windows.Forms $FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{ InitialDirectory = [Environment]::GetFolderPath('Desktop') } $null = $FileBrowser.ShowDialog() Ironically, you can do this with ASOC, but only for items that have ObjC interfaces, which will be shrinking. Having a coherent automation framework with a primary language that allows people using it to more easily use "full" Swift and its frameworks as needed is a force-multiplier for Apple. It would help people do more with macOS and maybe other platforms depending on implementation, not less. It would not force people to beg the developers of their apps to write Yet Another Shortcut to do this thing that they can't do, (or have to do the dance to convince the dev that their need is worth the trouble), and it would allow people to solve their problems in their own ways for their own needs. But, it requires Apple to care about this at all, and that is where the problem is. This is fixable, Apple has the resources to fix it, what they lack is interest and desire. But creating and fully supporting a proper automation framework would add so much to macOS and the other platforms by extension that there's no logic behind not doing so. Maybe next year. (in the best lol of all, you can't even create an automation tag for a post. sigh.)
Posted Last updated
.
Post not yet marked as solved
3 Replies
1.6k Views
Has anyone else seen in Ventura B3 where you have a URL path as a source and you want to use the filename for that, aka lastPathComponent in a destination URL, so you have something like: let destinationURL = destinationDIrectory.appendingPathExtension(sourceURL.lastPathComponent) and lastPathComponent is a file name but what you get for destinationURL is: destinationDirectory.lastPathComponent instead of destinationDirectory/lastPathComponent or is it just me?
Posted Last updated
.
Post not yet marked as solved
2 Replies
3.1k Views
That's pretty much the post. How does one go about locking down window resizing for a mac app with swiftUI? (I've no intention of this running on anything but macOS, so I don't actually care how it will look on i(Pad)OS.) I've tried the width/height in the frame parameters, min/max width, etc. none of that worked.
Posted Last updated
.
Post not yet marked as solved
1 Replies
1.1k Views
Sorry about the title, it's kind of awkward. Basically, I have an ASOC app that I'd like to port to swift as a learning excercise. it's pretty straightforward, it grabs the computer name, local host name, and host name via the scutil --get operations and lets you change those via the --set. doing this in ASOC is dead simple, yay do shell script, and I mostly found a way to do it via NSAppleScript, but it feels very...awkward. Is there a better framework to use for getting and setting this info? thanks! john
Posted Last updated
.
Post not yet marked as solved
0 Replies
715 Views
is there any sample code showing how to put multiple controls in a tab for a macOS app? I have an app that I'd like to use as a basis for swiftUi work, but it's not "oh look, here's some scrolly things and it's all really iOS navigation". It's a macOS app, it has specific window sizes, multiple buttons in specific places in a tab, multiple text fields, table views, popup lists, etc. Each tab is different. I can't find any good info that isn't so targeted at iOS to be useless for my needs.
Posted Last updated
.