Cocoa Message with no action required - objective-c

I'm trying to figure out a way to give a user feedback when they have saved settings. similar to Microsoft's "File Saved" dialog Is there a class for this type of dialog? I do not want to require any action by the user. Just "Your setting have been saved" then disappears after a short delay. Maybe a better way to describe would be like a jQuery message box with a fade in fade out type thing

Is there a class for this type of dialog?
That isn't a "dialog", because you're not accepting input from the user. At best, it's an alert, and you could therefore use NSAlert (see also "Dialogs and Special Panels") however, what you are contemplating is contrary to the recommendations given in the HIG for "Alerts":
Avoid using an alert merely to give users information. Although it’s important to tell users about serious problems, such as the potential for data loss, users don’t appreciate being interrupted by alerts that are informative but not actionable. Instead of displaying an alert that merely informs, give users the information in another way, such as in an altered status indicator.
In other words, this probably wouldn't be considered a good user experience by the OS X-using population.
You can still do this, if you absolutely must, by creating a sheet or alert window and setting a timer to dismiss it.
A much better plan would be to have a label somewhere in your interface whose text could display this information, again using a timer to clear the notice after an appropriate duration.
Yet another option (possibly the best) would be to put this notice somewhere that the user only sees it upon request. The HIG mentions Mail.app's information area at the bottom of its sidebar, for example.

It is simple to fade a window in and out using the NSViewAnimation see also NSAnimation Class
An example I use something like this.
- (void)fadeWindowIn{
//--make sure the window starts from 0 alpha. Or you may get it jumping in view then try and fade in.
[theWindow setAlphaValue:0.0];
//-- set up the dictionary for the animation options
NSDictionary *dictIn = [NSDictionary dictionaryWithObjectsAndKeys:
theWindow,NSViewAnimationTargetKey,
NSViewAnimationFadeInEffect,NSViewAnimationEffectKey,nil];
NSViewAnimation * fadeWindowIntAnim = [[[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dictIn]] autorelease];
[fadeWindowIntAnim setAnimationCurve:NSAnimationLinear];
[fadeWindowIntAnim setDuration:2];
[fadeWindowIntAnim setFrameRate:20.0];
//--start the animation
[fadeWindowIntAnim startAnimation];
//--set the timer for the fade out animation
[NSTimer scheduledTimerWithTimeInterval:4.8 target:self selector:#selector(fadeWindowOut) userInfo:nil repeats:NO];
}
-(void)fadeWindowOut{
//-- fade the window.
NSDictionary *dictOut = [NSDictionary dictionaryWithObjectsAndKeys:
theWindow,NSViewAnimationTargetKey,
NSViewAnimationFadeOutEffect,NSViewAnimationEffectKey,nil];
NSViewAnimation * fadeOutAnim = [[[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObject:dictOut]] autorelease];
[fadeOutAnim setAnimationCurve:NSAnimationLinear];
[fadeOutAnim setDuration:1.2];
[fadeOutAnim setFrameRate:20.0];
[fadeOutAnim startAnimation];
}
theWindow is the NSWindow or NSView you want to fade in and out. Read the references to understand the options.

You can create your own such popup (using NSTimer to dismiss as needed), but perhaps an easier way would be to use the existing third-party library at http://code.google.com/p/toast-notifications-ios/. This library emulates Android's "toast" functionality.
Note that this library is for iOS development (not OSX), but wasn't sure which platform you were planning to target. Regardless, it should be adaptable with a little work.

The other answers about timers and such cover that aspect of it pretty well. I just wanted to jump in and suggest you take a look at the Growl framework. This seems to be the preferred way to do this sort of passive notification until Apple builds it into the OS.
Among other things, it gives the user a lot of control over how the notifications look, where they live on the screen, how long they stay up, and which apps are even allowed to display them. And they do this without you having to write any code. The downside is that it's another thing for your users to have to install, which could be a deal breaker for your app.
They also recently moved into the App Store and started charging a nominal fee ($2 or $3, I think) which could be seen as a downside but I think of it as a more positive thing: users will have a much easier time installing it now.
Some apps that make use of Growl notifications include BBEdit, Transmission, Scrivener, Twitteriffic, etc. Which is to say that it's not a fly-by-night thing.
As a user, I hate it when apps try to roll their own notifications since I lose all of the control that I get with Growl.
Just a thought, anyway.

Related

Flip UIAlertView

I have not found a way to do this without using private APIs, which is quite a shame, as it is something my app and many others could benefit from. I have an UIAlertView with a Details... button on it, which I want to sort of 'flip' to the other side and show a different UIAlertView, much like UITwoSidedAlertViewController, but not using any private APIs.
First of all, is this even possible? I looked over the UIAlertView header, but I couldn't see anything relating to this. UIAlertView does inherit from UIView, so I suppose that simple view animation might just be the key, but as I said, I've never done anything like view animation flips.
Why not just use one of the several UIAlertView replacements that have been created and then add the flip functionality yourself?
You can find a UIAlertView replacement here: https://github.com/TomSwift/TSAlertView
The flip can be created using a standard flip animation block via [UIView transitionWithView ...]

Make NSWindow Front But Not In Focus

I'm looking to bring a new NSWindow in front of all other windows, but not have it take focus.
I can make it appear in front with focus with the following:
NSApplication *thisApp = [NSApplication sharedApplication];
[thisApp activateIgnoringOtherApps:YES];
[self makeKeyAndOrderFront:self];
Any clues on how to make it appear on top but not take focus away from another application?
Instead of makeKeyAndOrderFront:, try just orderFront: (docs)
Try something like this:
[window setLevel:NSScreenSaverWindowLevel + 1];
[window orderFront:nil];
This will show the window above other application's windows, but without making it active. A window with a normal window level in application A cannot be shown in front of a window of application B, if application B is the active application. (There is good reason for this, btw).
Please use this method with discretion. In many cases, it will likely violate the human interface guidelines. If misused, it can have a tendency to piss a user off. (For example, in my testing just now, the window appeared placed directly over the location I happened to be looking at in Safari. The fact that it was in the way of what I was doing, yet had the audacity to not become key, made it even more irritating. If it were up out of the way in a corner of my screen, it might be a different story).
The order front methods and level to the screensaver +1 didn't work for me. This answer from The-Kenny did, though:
[yourPanel setLevel:kCGMaximumWindowLevel];
In case you're using orderFront, try orderFrontRegardless instead. The former isn't consistent every time it's called. The latter seems to work consistently.

How should the model update the UI of its progress?

I am trying to solve a problem in Objective-C, but I don't think the question is language specific.
I have to do some processing down in a model class that has no notion of UI. However, this processing takes some time and I want to let the user know the status via a progress bar.
My first attempt at this was defining a notion of a progress handler protocol/interface with some methods like
-startOperation;
-updateProgress:(double)currentValue ofMax:(double)maxValue
-endOperation;
This way my UI can implement that the the model need not know details about what goes on other than someone wants progress updates. Currently my UI unhides a progress bar, and updates it, then hides it when done. So far so good.
However, it turns out that sometimes this operation processing is very fast. Such that the UI updates result in a pretty disconcerting flicker as they execute. I don't know if the operation will be fast or slow beforehand.
One idea I had was to force the operation to take at least a certain duration to avoid the UI changes being so jarring to the eye, but this seemed to put knowledge of the UI in the model class, which must be wrong.
This would seem to be a common issue with (hopefully) some known pattern.
How would you address this?
Jonathan's and Darren's answers cover your actual problem, but I would add something regarding the question in the title: "How should the model update the UI of its progress?"
The answer, of course, is that it shouldn't. The model shouldn't have to know anything about any protocols for displaying data. There should be one uniform bindings layer taking care about propagating information from the model to the interface. Fortunately, Cocoa already includes such a bindings mechanism: Key-Value Observing.
What you should do is define a property on any model class where the concept of progress makes sense, something like #property (assign) float progress. Then you make sure the class is KVO compliant. Controller code that want to keep track of the progress simply registers to observe this value with something like:
[theObject addObserver:self forKeyPath:#"progress" options:0 context:NULL];
Make sure to read the documentation for the NSKeyValueObserving (KVO) informal protocol.
Also, you might want to have a look at Mike Ash's KVO-related notes and code: Key-Value Observing Done Right.
You can use NSTimer to delay the display of your progress bar until your operation had run for a given amount of time, say half a second:
-(void)startOperation {
// Show the progress bar in 0.5 seconds
if (!_timer) {
_timer = [[NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:#selector(showProgressBar:)
userInfo:nil
repeats:NO] retain];
}
}
In -endOperation, you cancel the timer and hide progress bar:
-(void)endOperation {
[_timer invalidate]; // cancel the timer
[_timer release];
_timer = nil;
[self hideProgressBar];
}
If the operation completes in less than 0.5 seconds, the timer is canceled before the progress bar is displayed.
One thing commonly done is to have your progress bar implementation not show itself right away, and apply some heuristic based on the first couple of updates (or a timeout) to determine whether it needs to show itself at all. That's how the Java ProgressMonitor behaves, for example. (The ProgressMonitor is a nice abstraction that separates the knowledge of progress from its graphical representation).
Once the progress widget is showing, you could repaint it on a leisurely timer, say 10 times per second, rather than reacting to every progress change event with a repaint.

Is using subviews in Alert undocumented

I have asked a similar question here and got some answers, so first of all sorry for making you people bother once again.
But I have an argument this time. First I will show my piece of code
- (void) showTheAlert{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Hey!" message:#"?" delegate:self cancelButtonTitle:nil otherButtonTitles:#"Yes",#"No",#"Don't know eaxactly.",nil];
[alertView setTag:101];
[alertView show];
}
- (void)willPresentAlertView:(UIAlertView *)alertView{
if(alertView.tag == 101){
[[[alertView subviews] objectAtIndex:2] setBackgroundColor:[UIColor colorWithRed:0.5 green:0.0f blue:0.0f alpha:0.5f]];
[[[alertView subviews] objectAtIndex:3] setBackgroundColor:[UIColor colorWithRed:0.0 green:0.5f blue:0.0f alpha:0.5f]];
}
}
And my final alert looks like
Now my confusion is that, [alertView subviews] is not documented as some people may say but alertview is a subclass of UIView, which has a property called subviews.
So I am using the documented property of a superclass which is definitely allowed.
So if this alertview may cause rejection of my app or not? ( I don't think apple will have any base to say I am using the undocumented or a private api. The look and feel is also alike to alertview.)
Apples iPhone Human Interface Guidelines about alert views clearly states:
The infrequency with which alerts appear helps users take them seriously. Be sure to > minimize the number of alerts your application displays and ensure that each one offers > critical information and useful choices. In general, try to avoid creating alerts that:
Update users on tasks that are
progressing normally.
Instead, consider using a progress
view or an activity indicator to
provide progress-related feedback to
users (these controls are described
in “Progress Views” and “Activity
Indicators”).
Ask for confirmation of
user-initiated actions.To get confirmation for an action the user initiated, even a potentially risky action such as deleting a contact, you should use an action sheet (described next in “Using Action Sheets”).
Inform users of errors or problems
about which they can do nothing.
Although it might be necessary to use an alert to tell users about a
critical problem they can’t fix, it’s
better to integrate such information
into the user interface, if possible.
For example, instead of telling users
every time a server connection fails,
display the time of the last
successful connection.
So, my advice, the time waiting for a potential rejection isn't worth your time. Don't risk it.
To follow on Henrik's reply, in the iPhone Human Interface Guidelines section "Designing an Alert", they say the following:
Although you can choose the number of
buttons to place in an alert, a
two-button alert is often the most
useful, because it is easiest for
users to choose between two
alternatives. It is rarely a good idea
to display an alert with a single
button because such an alert cannot
give users any control over the
situation; instead, it can only
display information and provide a
dismiss button. An alert that contains
three or more buttons is significantly
more complex than a two-button alert,
and should be avoided if possible. In
fact, if you find that you need to
offer users more than two choices, you
should consider using an action sheet
instead (see “Using Action Sheets” and
“Designing an Action Sheet” for more
information on this type of view).
Because users sometimes respond to
alerts without reading them carefully,
be sure to provide an appropriate
default choice. To help guide
inattentive users towards this choice,
make the light-colored, right-hand
button the safe, default alternative.
For example, you might choose to make
this button the Cancel button, to help
users avoid inadvertently causing a
dangerous action, or you might make it
represent the most common response, if
the resulting action isn’t
destructive.
The following guidelines describe how
buttons are configured in an alert:
In an alert with two buttons, the button on the left is always
dark-colored and the button on the
right is never dark-colored.
In a two-button alert that proposes a potentially risky action, the button
that cancels the action should be on
the right and light-colored.
In a two-button alert that proposes a benign action, the button that
cancels the action should be on the
left (and therefore dark-colored).
In an alert with a single button, the button is light-colored.
You are clearly violating the guidelines in size, shape, number, and color of the buttons in your alert view (red has a very clear meaning as a destructive action, not a confirmation). Even if Apple doesn't reject your application in review (which they tend to do for clear violations of the Human Interface Guidelines), this would be extremely confusing to your users.
Also, navigating the hidden view hierarchy for any Apple-supplied user interface element is a very bad practice. The view hierarchies are undocumented, and do change often. Many of the applications that started crashing when people upgraded to iPhone OS 3.0 did so because those applications did something funky with subviews of UI elements, and those elements changed in the new OS version. Apple even specifically called this out in the iPhone OS 3.0 migration documents (which I can't find now).
Because of the problems this caused, they appear to have cracked down on this practice and have been rejecting applications because of it. Even if they don't, it shows contempt for your users if you do this, because it means that you don't care if your application breaks with future OS upgrade.
I'm fairly sure altering UIAlertView by digging through the view hierarchy is a no-no. Firstly because it "uses standard iPhone screen images in a non-standard way, potentially resulting in user confusion", and secondly because if they change the view hierarchy your app is broken.
I might be wrong, I've never tried to get something like this onto the store, but my gut says don't risk it.
You can get a red button using a standard UIActionSheet, can you not?

NSStatusItem to be always left?

I'm working on an app that displays certain information on the status menu, and I was wondering if there's any Cocoa API that can make my NSStatusItem always placed on the most-left, no matter when it's started or if other apps are started after it.
NSStatusBar *bar = [NSStatusBar systemStatusBar];
barItem = [[bar statusItemWithLength:NSVariableStatusItemLength] retain];
Thanks.
Taking you ultra-literally for a moment, what if two applications used such an API? They would fight and roll off the end of the menu bar. ☺
There is no supported way to do it, but there is an undocumented/unsupported way to specify the “priority” of the status item when you create it. Of course, use at your own risk, and be sure to do a respondsToSelector: check to fall back on the supported way if the unsupported way goes away.