Understanding Interface Builder - Swift - class

Alright, so I'm not trying to do a whole lot at this stage. I have created a Swift class that is supposed to update an NSPopUpButton with a list of available serial ports. I've finalized the code for retrieving the list of ports and created a window in interface builder including the popup button but I can't get the two to work together.
I've tried editing the 'custom class' field of the window to 'Serial' to match my class but that gives me errors in the debugging window when running the program. I've tried to link the two with the command+drag tool with varying success but no matter what I try, I can't manage to update the button of my program.
How should I be doing this? What am I missing?
import Foundation
import Cocoa
class Serial {
init() {
}
#IBOutlet weak var serialListPullDown: NSPopUpButton!
func refreshSerialList(defaultprompt: String) {
//Initialize ORSSerialPortManager
let portManager : ORSSerialPortManager = ORSSerialPortManager.sharedSerialPortManager()
var availablePorts : NSArray = portManager.availablePorts
//Erase entries from popup field
serialListPullDown?.removeAllItems()
for port in availablePorts as [ORSSerialPort] {
//Add ports to popup window
var Port = "\(port.path)"
serialListPullDown?.insertText(Port)
}
}
}

You need to change Serial to a subclass of UIViewController (assuming that That window is a UIViewController)
class Serial: UIViewController {}
then change the Custom class to Serial again. It shouldn't have errors anymore
Then start cmd+drag to connect your NSPopupButton object

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.

Kotlin Multiplatform Compose ~ How to use events to control views

I have a Kotlin Multiplatform project where I want to use Events to control views.
The basic idea is this:
Buttons & Co fire an Event when clicked
These events get caught and handled by the responsible program components, which will in turn fire other events
Eventually, some kind of ViewEvent is fired, which is subscribed to by the ViewController
The ViewController then tells the program what should be drawn on the screen
In theory, that sounds like it should work. In practice, what happens is that while it gets to the point where the ViewController receives the event and reacts accordingly, the actual views are unaffected.
My ViewController looks like this:
import androidx.compose.runtime.Composable
import com.tri_tail.ceal_chronicler.events.OpenCharacterSelectionViewEvent
import com.tri_tail.ceal_chronicler.ui.main_view.MainView
import com.tri_tail.ceal_chronicler.ui.main_view.MainViewState
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
class ViewController {
private var mainViewState = MainViewState.TITLE
init {
val eventBus = EventBus.getDefault()
eventBus.register(this)
}
#Composable
fun draw() {
MainView(mainViewState)
}
#Subscribe
fun onOpenCharacterSelectionViewEvent(event: OpenCharacterSelectionViewEvent) {
mainViewState = MainViewState.CHARACTER
}
}
I debugged that, and was able to see that the mainViewState changes, as expected. However, the draw() function is never called again, and so the changed mainViewState never arrives in the MainView.
I've already tried making mainViewState a mutableStateOf(mainViewState), but that didn't change anything.
Furthermore, I can't just call draw() inside the onOpenCharacterSelectionViewEvent, because it is not #Composable, and adding that annotation to the method causes the build to fail.
At this point, I am not even sure whether what I am trying to do here can work this way. Can someone please help me out here?
I have also published a version of the code with the current non-working solution here: https://github.com/KiraResari/ceal-chronicler/tree/event-system
For my KMM project i use open source viewModel for KMM.
This one https://github.com/adeo-opensource/kviewmodel--mpp
I suggest transfer your MVC architecture to MVI and use this KMM viewModel to control your state as in usual android app.
Okay, so after worrying at this for several days, I have now come up with a solution that works.
Basically, the reason why it doesn't work as I tried it is that the frontend lives in its own little world, and it is very difficult for something from outside that world to affect it.
However, it can be done using delegates. Basically, what I called the ViewController in above is more of a MainViewModel, and it needs to look like this:
import com.tri_tail.ceal_chronicler.events.OpenCharacterSelectionViewEvent
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
class MainViewModel {
var state = MainViewState.TITLE
var updateState: ((MainViewState) -> Unit) = { }
set(value) {
field = value
updateState(state)
}
init {
val eventBus = EventBus.getDefault()
eventBus.register(this)
}
#Subscribe
fun onOpenCharacterSelectionViewEvent(event: OpenCharacterSelectionViewEvent) {
state = MainViewState.CHARACTER
updateState(state)
}
}
The other part of the magic happens in the MainView, where the state needs to be a remember with a mutableStateOf(..., policy = neverEqualPolicy()), and the delegate needs to be set like this:
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.*
import com.tri_tail.ceal_chronicler.models.main_view.MainViewModel
import com.tri_tail.ceal_chronicler.models.main_view.MainViewState
import com.tri_tail.ceal_chronicler.theme.AppTheme
import com.tri_tail.ceal_chronicler.ui.TitleScreen
import com.tri_tail.ceal_chronicler.ui.characters.DisplayCharacterSelector
#Composable
fun MainView(model: MainViewModel = MainViewModel()) {
var state by remember {
mutableStateOf(
model.state,
policy = neverEqualPolicy()
)
}
model.updateState = {
state = it
}
AppTheme {
when (state) {
MainViewState.TITLE -> TitleScreen()
MainViewState.CHARACTER -> DisplayCharacterSelector()
}
}
}
And that's all there is to it! Works like a charm, no extra libraries required.

validateMenuItem not called for every menu item

I have main menu that has several menu items (File, Edit, View, Window - and more). All menu items have their action set to an operation in FirstResponder.
The application has a single window and that window is of the type MyWindow that inherits from NSWindow (see below).
Note that NSWindow implements NSMenuValidation and hence it is flagged as an error when MyWindow would declare conformance to NSMenuValidation.
I have overriden the function validateMenuItem as follows:
class MyWindow: NSWindow, NSMenuDelegate {
...
override func validateMenuItem(_ item: NSMenuItem) -> Bool {
Log.atDebug?.log("\(item.title)")
....
}
}
When I run the application the validateMenuItem function is called for the File and the Window menu items but not for the Edit and View items.
Note: Log is an instance of a logging framework (SwifterLog).
The actions for all menu items are called correctly. (Also for the menu items for which the validateMenuItem is not called)
It is not difficult for me to work around this problem (the function menuNeedsUpdate is called for all menu's and can be used for this), but I would like to know why this behaviour occurs.
Answer can be found here:
validateMenuItem or menuWillOpen not called for NSMenu
validateMenuItem: belongs to the NSMenuValidation informal protocol;
for it to be called the relevant menu items must have a target.
This is not an answer, but to anyone interested in a work-around:
#objc func menuNeedsUpdate(_ menu: NSMenu) {
Log.atDebug?.log("\(menu.title)")
... // do other stuff
menu.items.forEach( { $0.isEnabled = validateMenuItem($0) } )
}
You must als set the delegate of each menu that must be handled to the MyWindow object (in this example). In my example, the menu of the menu item View must have its delegate set to MyWindow.

Side menu controller

I am working on a YouTube project and the problem is that I want to add a side menu and I know how to do that. However, when I press a cell I don't want it to load a new view. Instead, I want it to update my table view because I don't want 20 different views that do nearly the same thing and just load different videos. Any idea how I can achieve my goal?
I was thinking of using this side menu: https://github.com/John-Lluch/SWRevealViewController
Coding in swift
You could create a custom class that does all the tableview initialization as a BaseClass and make childClass for different Menus. Instead of:
class menu1: UITableViewController {
}
class menu2: UITableViewController {
}
Use this:
class BaseTableViewController: UITableViewController {
}
class menu1: BaseTableViewController {
}
class menu2: BaseTableViewController {
}
Reuse the class and make a fetch function content for cell with customizable input parameters. You could refer letsbuildthatapp youtube tutorial series for reference. It has a letsbuildyoutube app series.

Xcode Markup Link Reference Within Same File

I want to make a link reference within the same file in Swift kind of like the way you can in JavaDoc, but I can't seem to find documentation describing how to do this. You can only reference external URLS. I want to be able to do something like this:
class myClass : UIView {
/// The label that displays the scale of this view
/// - seealso: [showScaleView](showScaleView())
private lazy var scaleView: UIView = UIView()
/// Shows the scale view
/// - seealso: [scaleView](scaleView)
private func showScaleView() {
...
}
}
This known issue in Xcode since Jan 2018... :(
Here is radar: https://github.com/lionheart/openradar-mirror/issues/19263