Hide NSUserNotification after certain time - cocoa

Currently when i create a NSUserNotification using Alert style it won't hide unless i manually close it.
Is there a way i can auto close/hide it say after 2 sec?
NSUserNotification code is for reference :
let notification:NSUserNotification = NSUserNotification()
notification.title = "Title"
notification.subtitle = "Subtitle"
notification.informativeText = "Informative text"
notification.soundName = NSUserNotificationDefaultSoundName
notification.deliveryDate = NSDate(timeIntervalSinceNow: 10)
notification.hasActionButton = false
let notificationcenter:NSUserNotificationCenter = NSUserNotificationCenter.defaultUserNotificationCenter()
notificationcenter.scheduleNotification(notification)

It's actually very simple to do this, using NSObject's
performSelector:withObject:afterDelay: method.
Because you're scheduling the notification delivery after a certain time interval, you need to add the additional delay before dismissing, to the initial delay before delivering. Here, I've written them out as constants of 10 seconds before delivery, and 2 seconds before dismissal:
let delayBeforeDelivering: NSTimeInterval = 10
let delayBeforeDismissing: NSTimeInterval = 2
let notification = NSUserNotification()
notification.title = "Title"
notification.deliveryDate = NSDate(timeIntervalSinceNow: delayBeforeDelivering)
let notificationcenter = NSUserNotificationCenter.defaultUserNotificationCenter()
notificationcenter.scheduleNotification(notification)
notificationcenter.performSelector("removeDeliveredNotification:",
withObject: notification,
afterDelay: (delayBeforeDelivering + delayBeforeDismissing))
And for Swift 5 you can use the following:
let delayBeforeDelivering: TimeInterval = 10
let delayBeforeDismissing: TimeInterval = 2
let notification = NSUserNotification()
notification.title = "Title"
notification.deliveryDate = Date(timeIntervalSinceNow: delayBeforeDelivering)
let notificationcenter = NSUserNotificationCenter.default
notificationcenter.scheduleNotification(notification)
notificationcenter.perform(#selector(NSUserNotificationCenter.removeDeliveredNotification(_:)),
with: notification,
afterDelay: (delayBeforeDelivering + delayBeforeDismissing))

You can use removeDeliveredNotification: or removeAllDeliveredNotifications with timer
// Clear a delivered notification from the notification center. If the notification is not in the delivered list, nothing happens.
- (void)removeDeliveredNotification:(NSUserNotification *)notification;
// Clear all delivered notifications for this application from the notification center.
- (void)removeAllDeliveredNotifications;
OS X (10.8 and later)

Blockquote Is there a way i can auto close/hide it say after 2 sec?
No, you do not have any such option till OSX 10.11, may be in future Apple may provide.
There are three ways a user can customise the NSUserNotification also known as Growl notification:
None
Banner
Alert
You as a developer can not control over the system settings. This is upto the user to enable or disable and choose what kind of notification he likes.
If you want any alert to be shown to user you can create your own alert window and show it in that corner. You can set a timer to close, or provide action button to close it once you need.
Update 1:
Cocoa provides NSWindow & NSPanel(HUD and normal panel). You can either customize Window or panel according to your need. Check there are multiple options that would help you to form as per your requirement.
If you can't get, say you wanted a rounded corner then you need to customize the window/view etc.

Related

Mac Catalyst - control window resize

I have an app for ipad/iphone, now adding also mac support by Mac Catalyst. On Mac, I want to control window resizing, in order to allow only some sizes and aspects. It goes beyond simple minimal height and weight, or aspect. I want to allow user to resize window freely, but when app gets too high and narrow, I want to also seemlessly increase width, to keep some minimal aspect.
I believe that in AppKit it can be done through NSWindowDelegate.windowWillResize() (get user defined size, count required size and return it). However I am getting error "NSWindowDelegate is unavailable in Mac Catalyst" . Is it possible to achieve the result I want by Catalyst means?
Answering my own question. It is NOT possible to create own NSWindowDelegate with windowWillResize() implemented in Catalyst. However, it IS possible to create a new target only for mac, and use it as a plugin from catalyst target.
First I load mac-only plugin (using Bundle.load() ), and instantiate its principalClass. Then I get NSWindow from UIWindow, which is easy through Dynamic library. Then I pass NSWindow to method of a plugin, which then can set own NSWindowDelegate, because it does not run in catalyst.
Sample code:
guard let bundle = Bundle(url: bundleURL) else { return }
let succ = bundle.load()
if (succ) {
let macUtilsClass = bundle.principalClass! as! MacUtilsProtocol.Type
self.macUtils = macUtilsClass.init()
var dnsw: NSObject? = nil
if (ProcessInfo.processInfo.isOperatingSystemAtLeast(
OperatingSystemVersion(majorVersion: 11, minorVersion: 0, patchVersion: 0))) {
dnsw = Dynamic.NSApplication.sharedApplication.delegate.hostWindowForUIWindow(AppDelegate.ref!.window).attachedWindow
}
else {
dnsw = Dynamic.NSApplication.sharedApplication.delegate.hostWindowForUIWindow(AppDelegate.ref!.window)
}
self.macUtils.SetupMainWindow(win: dnsw!)
}

Kill the current Toast Notificatoin

Is there any option to kill/hide/cancel current Toast Notification under Android 10 + TNS?
I want to show the meaning of some words by tapping on them, but under Android 10 user needs to wait until previous Toast Notification times out until he/she can see the next one.
The answer is found!
just store the Toast.makeText( var ) in a variabile like myToast and use cancel() function to remove it.
let myToast = Toast.makeText( var ); // show() function shouldn't be used here!
myToast.show();
...
myToast.cancel();

UI Testing in Xcode 7: Selecting a row number in a UIPickerView / PickerWheel

Is there a way in Xcode 7 UI Testing to select the 3rd row in a UIPickerView?
I have tried various things like this to identify the rows in each picker but all the requests below return 0 found:
XCUIApplication().pickers.element.cells.count
XCUIApplication().pickers.element.staticTexts.count
Any ideas?
Updated: I am aware of adjustToPickerWheelValue method where you can select a particular value you already know, but I am trying to select the 3rd value (index = 4) when I don't know the values that exist in the picker.
You can use -adjustToPickerWheelValue: to select items on a UIPickerView.
When there is one UIPickerView on the screen you can select the element directly, like so.
let app = XCUIApplication()
app.launch()
app.pickerWheels.element.adjustToPickerWheelValue("Books")
If the picker has multiple wheels you will need to first select the wheel via it's accessibility identifier, then adjust it.
app.pickerWheels["Feet"].adjustToPickerWheelValue("5")
Here's a GitHub repo with a working example. And some more information in a blog post I wrote.
Workaround:
let pickerWheel = XCUIApplication().pickers.pickerWheels.element
let appWindowHeight = XCUIApplication().windows.elementBoundByIndex(0).frame.height
let pickerWheelCellHeight = GFloat(44)
func advancePickerWheelOneValue() -> Self {
let topScrollPoint = Double(pickerWheel.frame.midY/appWindowHeight)
let bottomScrollPoint = Double((pickerWheel.frame.midY + pickerWheelCellHeight)/appWindowHeight)
let topScreenPoint = XCUIApplication().windows.elementBoundByIndex(0).coordinateWithNormalizedOffset(CGVector(dx: 0.5, dy: topScrollPoint))
let bottomScreenPoint = XCUIApplication().windows.elementBoundByIndex(0).coordinateWithNormalizedOffset(CGVector(dx: 0.5, dy: bottomScrollPoint))
bottomScreenPoint.pressForDuration(0, thenDragToCoordinate: topScreenPoint)
return self
}
You may need to adjust the dx value depending on where the picker is.
.coordinateWithNormalizedOffset(CGVector(dx: 0.5,
But 0.5 works if the picker occupies the width of the screen.
With this method you an move the picker on value at a time. Call it multiple times and you get to the value you want.
Its not ideal but it can help if you want to check certain indexes. Hopefully you would have to use it on a picker with hundreds of values ;)
Example with Date picker (UIDatePicker)
XCUIApplication().datePickers.pickerWheels.elementBoundByIndex(0).adjustToPickerWheelValue("March")
XCUIApplication().datePickers.pickerWheels.elementBoundByIndex(1).adjustToPickerWheelValue("24")
XCUIApplication().datePickers.pickerWheels.elementBoundByIndex(2).adjustToPickerWheelValue("2000")
And here is example with Picker view (UIPickerView)
XCUIApplication().pickerWheels.element.adjustToPickerWheelValue("Male")

Swift alarm clock UIswitch

when creating an alarm clock, is it the right way to directly display all scheduled local notifications on a table view? If so, After the notifications have fired they disappear. How can i stop them from disappearing so i can use switches to set them on and off?
What i understood about UIswitch is that i have to cancel the notification when off then reschedule them when on.
#IBAction func addAlarm(sender: UIButton) {
let notification = UILocalNotification()
notification.fireDate = timePicker.date.fireDate
notification.timeZone = NSTimeZone.localTimeZone()
notification.alertBody = "Its time"
notification.applicationIconBadgeNumber = UIApplication.sharedApplication().applicationIconBadgeNumber + 1
notification.hasAction = true
notification.alertAction = "View"
UIApplication.sharedApplication().scheduleLocalNotification(notification)
alarmTable.reloadData()
}
Use an array to store the times of the alarms.
Then you can easily show and manage them and create UILocalNotifications based on them.
You have to define the timezone before defining the firedate

Swift - using timers/system clock/background threads to do something in my application every hour

I'm using:
var alarm = NSUserNotification()
var currentTime = NSDate()
alarmTime = currentTime.dateByAddingTimeInterval(60)
alarm.deliveryDate = alarmTime
NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification(alarm)
To get a notification that will fire an hour from the current time, the problem is I want the app to automatically set up another alarm after the first one finishes. NSTimer doesn't seem like it will work because once the app goes to the background it kills the timer. What can I do to achieve this? Can I piggy back another method onto a NSUserNotification
Edit: it also needs to be dynamic, I can't just set the repeat variable of the notification because I need to be able to switch how far out the alarm will be each time it resets.
You just have to set your deliveryRepeatInterval and deliveryTimeZone, as follow:
// set your deliveryTimeZone to localTimeZone
alarm.deliveryTimeZone = NSTimeZone.localTimeZone()
// The date components that specify how a notification is to be repeated.
// This value may be nil if the notification should not repeat.
// alarm.deliveryRepeatInterval = nil
// The date component values are relative to the date the notification was delivered.
// If the calendar value of the deliveryRepeatInterval is nil
// the current calendar will be used to calculate the repeat interval.
// alarm.deliveryRepeatInterval?.calendar = NSCalendar.currentCalendar()
// to repeat every day, set .deliveryRepeatInterval.day to 1.
alarm.deliveryRepeatInterval?.day = 1
// to repeat every hour, set .deliveryRepeatInterval.hour to 1.
alarm.deliveryRepeatInterval?.hour = 1
alarm.deliveryDate = NSDate().dateByAddingTimeInterval(60)
NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification(alarm)

Resources