How can I have auto fill functionality as default in my custom codes? - swift

As you know we can just type Button( in SwiftUI and chose (action:label) on options and press Enter key, then Xcode make us a ready default code for start editing, it would be like this:
Button(action: {}, label: { Text("Button") })
I want same functionality in my code, therefore I just tried to re-create Button, but I do not know how could I possibly make it happen, I am getting this code after pressing Enter as default, which missing {} for action and { Text("Button") } for label:
CustomButton(action: () -> Void, label: () -> _)
My Goal: Which I would like get autofilled default like this:
CustomButton(action: {}, label: { Text("CustomButton") })
How could I make it possible? also I know about code Snippet, I do not want use that, I like my codes have default value from start, for editing them.
my used code:
struct CustomButton<Content: View>: View {
var action: () -> Void
var label: () -> Content
var body: some View {
return label()
.foregroundColor(Color.blue)
.onTapGesture { action() }
}
}

I know you said you didn't want to use code snippets, but I think that's the only way. You can get very close to the default behavior though. The trick is to use /*#START_MENU_TOKEN#*/ and /*#END_MENU_TOKEN#*/. These tell Xcode that everything between them should be autofilled.
So I assume you want something like this?
Original Xcode Button
Custom Button
First, let's see what Xcode does for a normal Button. Type in Button(, then copy what Xcode autofills into a text editor:
Button(action: /*#START_MENU_TOKEN#*/{}/*#END_MENU_TOKEN#*/, label: {
/*#START_MENU_TOKEN#*/Text("Button")/*#END_MENU_TOKEN#*/
})
As you can see, there are /*#START_MENU_TOKEN#*/ and /*#END_MENU_TOKEN#*/ surrounding the autofill text. You can customize this to your need, like this:
Button(action: /*#START_MENU_TOKEN#*/{}/*#END_MENU_TOKEN#*/, label: {
/*#START_MENU_TOKEN#*/Text("CustomButton")/*#END_MENU_TOKEN#*/
})
Try pasting this back into Xcode. It will look just as expected!
Now you can make this into a code snippet. Highlight the button text, right click, then click Create Code Snippet.
Then, enter something into the Completion field. This will be what Xcode will replace with your autofilled button code.
Finally, you can use it!
1. Type CustomBut
2. Press Enter

Related

SetFocusFilterIntent macOS system extension doesn't run perform() function

I am writing a Focus system extension (sandboxed, Cocoa, entitlements set) for macOS 13/Ventura using Xcode 14.2
I have the extension loading it's UI into the macOS system settings > Focus pane.
so here are the issues:
Even though it is loaded, it doesn't seem to ever run the perform() function when the UI is changed by the user or the user invokes Focus > Do Not Disturb.
What can be done in the perform() function? Like, what is supposed to go there? Nothing seems to work.
import AppIntents
struct MacOSFocus: SetFocusFilterIntent {
static var title: LocalizedStringResource {
return "Focus Settings"
}
// The description as it appears in the Settings app
static var description: LocalizedStringResource? = "Focus Settings" // name under Minus icon in options list
// How a configured filter appears on the Focus details screen
var displayRepresentation: DisplayRepresentation {
return DisplayRepresentation(stringLiteral: "Focus Settings") // name under filter once added to Foucs
}
#Parameter(title: "Show Task Bar", default: false)
var showDefaultTaskBar: Bool
#Parameter(title: "Start Timer")
var startTimer: Bool
func perform() async throws -> some IntentResult {
// This doesnt seem to run
// What can I put here?
// I need to write string data to a text file somewhere or communicate with the host app in some way.
return .result()
}
}
Just trying to get unstuck. Thanks for any help.
Tried adding an NSLog() call in the perform() function for debugging. Even tried using NSSound.beep() just to check that it is getting called. Didn't work.

Is there a way to pass functions into views as optional parameters?

I am making an application in SwiftUI that involves answering yes or no questions. Because of this I have created a subview call YesOrNoView. This subview has two buttons, one labeled yes and the other labeled no. The view accepts a binding variable of question that returns true or false based on the users answer. It also accepts a binding variable of questionsAnswered and increments it whenever either button is pressed. This behavior works for most questions in the game, but for the final question I want it to execute custom logic to take the user to a different view. To do this I am trying to make the view accept a custom action/method that I can call from either buttons action logic. Ideally, the action would also be optional so that I don't have to pass it in the 99% percent of the time when I'm not using it.
How do I pass a function as an optional parameter into a view and then run that action when a button within said view is pressed?
I tried adding actions using
struct YesOrNoView<Content: Action>: View {
...
but it couldn't find action or Action within it's scope.
I also tried using
struct YesOrNoView<Content>: View {
But I got an error saying that the Content variables type could not be inferred.
Any help would be greatly appreciated.
It return clickAction back to the view
struct GenericButton<Title: StringProtocol>: View {
let title: Title
let action: () -> Void
var body: some View {
Button(action: action) {
Text(title)
}.frame(width: 200, height: 40)
}
}
}
Usage:
GenericButton("Button") {
// Button tapped action
}
I managed to figure it out with help from #JoakimDanielson. The trick is to pass in an empty function as the default.
var myFunction: () -> Void = {}
Thanks for the help everyone.

Issue with giving a title to a menu

I want to give a text name for this menu but it won't let me saying there's an Extra argument in call what's wrong ? PS: I'm a beginner in coding
Divider()
Menu("\(buttonTitle)" ) {
Button("Riyadh",action: {SelectRiyadh()})
Button("Dammam",action: {SelectDammam()})
Button("Jeddah",action: {SelectJeddah()})
Button("Mecca",action: {SelectMecca()})
}
We need to see the ContentView page, but try to wrap all that code in some group or into stack, for example VStack.
Anyway, read this article first: How to show a menu when a button is pressed
VStack{
Divider()
Menu("\(buttonTitle)" ) {
Button("Riyadh",action: {option()})
}
}

Swift UI TextField onCommit called when lost focus (macOS)

I am having the following text field in content view:
func doCommit(){
print("\(self.status.textValue)")
}
var body : some View {
TextField("Your input:", text: self.$status.textValue, onCommit:{
self.doCommit()
}).lineLimit(1).focusable(true, onFocusChange: { focused in
print ("\(focused) changed")
})
...
}
When the text field got focus, and type return , the doCommit got called, which is what I want,
but when I click on something else, and then click the text field and click somewhere else, the doCommit got called again, and the focusable onFocusChange is not call.
I do not want the func been called when lost focus , but only when return/entry
It appears onFocusChange only gets called when you use the tab key to iterate through different UI elements, not when you click into and away from the TextField

Selecting a picker value to lead to a text field, SwiftUI

Im trying to implement a feature in my app.
When I click on my picker:
Picker(selection: $profileViewModel.education,
label: Text("Education Level")) {
ForEach(Education.levels, id: \.self) { level in
Text(level).tag(level)
}
}
This takes me to a screen and then I select the value (this is fine - it works as expected)
How could I select the value which then takes my to let's say another screen so I can fill in more details regarding the selected value.
For example the above picker has a values to select eduction level, after selecting it, how could I get an action sheet/another screen appear so I can have a text field there to save this extra data to or once the selection is made, a text field appears for me to save some extra data, and then clicking a button which would take me to the original screen of the picker (hope that makes sense)?
I've tried researching online for a problem similar to this but can't seem to find one/or if you can point me in the direction of what I should be looking into?.
Tried the following:
If I correctly understood your scenario here is a possible approach (replication tested with Xcode 12 / iOS 14)
Picker(selection: $profileViewModel.education,
label: Text("Education Level")) {
ForEach(Education.levels, id: \.self) { level in
Text(level).tag(level)
}
}
.onChange(of: profileViewModel.education) { _ in
DispatchQueue.main.async {
self.showSheet = true
}
}
.sheet(isPresented: $showSheet) {
// put here your text editor or anything
Text("Editor for \(profileViewModel.education)")
}