Design Preamble Mac OS X Mas - macos

I recently packaged my app for MAC Store and was rejected. Below is the message sent to me by review team. When i testing using development mode everything works fine but I can't picture where i am getting something wrong. Any idea would be appreciated. App was built using Electron.
Design Preamble
The user interface of your app is not consistent with the macOS Human
Interface Guidelines.
Specifically, we found that when the user closes the main application
window there is no menu item to re-open it.
Next Steps
It would be appropriate for the app to implement a Window menu that
lists the main window so it can be reopened, or provide similar
functionality in another menu item. macOS Human Interface Guidelines
state that "The menu bar [a]lways contains [a] Window menu".
Alternatively, if the application is a single-window app, it might be
appropriate to save data and quit the app when the main window is
closed.
For information on managing windows in macOS, please review the
following sections in Apple Human Interface Guidelines:
The Menu Bar and Its Menus
The Window Menu
The File Menu
Clicking in the Dock
Window Behavior
Please evaluate how you can
implement the appropriate changes, and resubmit your app for review.

The Problem is that after the Application is minimized by pressing the x button, there is no way for the user to open it again from the dock.
One way to fix this is to just terminate the Application when the x button is clicked.
I had the same issue and fixed it by adding this function in AppDelegate. This solution is for Swift 4.2
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
Now the Application terminates, when the x button is clicked.

If you are working with Xamarin, edit your AppDelegate.cs to create a menu to reopen the main window:
public class AppDelegate : FormsApplicationDelegate
{
NSWindow window;
public override NSWindow MainWindow
{
get
{
return window;
}
}
public AppDelegate()
{
var style = NSWindowStyle.Closable | NSWindowStyle.Resizable | NSWindowStyle.Titled;
var rect = new CoreGraphics.CGRect(100, 100, 1024, 768);
window = new NSWindow(rect, style, NSBackingStore.Buffered, false);
window.TitleVisibility = NSWindowTitleVisibility.Hidden;
}
private NSMenu MakeMainMenu()
{
// top bar app menu
NSMenu menubar = new NSMenu();
NSMenuItem appMenuItem = new NSMenuItem();
menubar.AddItem(appMenuItem);
NSMenu appMenu = new NSMenu();
appMenuItem.Submenu = appMenu;
// add separator
NSMenuItem separator = NSMenuItem.SeparatorItem;
appMenu.AddItem(separator);
// add open menu item
string openTitle = String.Format("Open {0}", "MyApp");
var openMenuItem = new NSMenuItem(openTitle, "o", delegate
{
// Get new window
window.MakeKeyAndOrderFront(this);
});
appMenu.AddItem(openMenuItem);
// add quit menu item
string quitTitle = String.Format("Quit {0}", "MyApp");
var quitMenuItem = new NSMenuItem(quitTitle, "q", delegate
{
NSApplication.SharedApplication.Terminate(menubar);
});
appMenu.AddItem(quitMenuItem);
return menubar;
}
public override void DidFinishLaunching(NSNotification notification)
{
// finally add menu
NSApplication.SharedApplication.MainMenu = MakeMainMenu();
// Insert code here to initialize your application
Forms.Init();
//Load Application
LoadApplication(new App());
//Did Finish Launching
base.DidFinishLaunching(notification);
}
public override void WillTerminate(NSNotification notification)
{
// Insert code here to tear down your application
}
}
If you are workwing with Cocoa do the same but in the specific language.
Reopen the window with this instruction:
[window makeKeyAndOrderFront:self];

For electron apps you can add this code to your index.js or main.js to resolve the issue:
app.on('window-all-closed', () => {
app.quit();
});

Related

How to keep newly opened macOS window in front & prevent being hidden with SwiftUI?

I am using SwiftUI to create a macOS app and need to create a new window that opens with an image inside of it, which I am successfully accomplishing currently.
However, if I click back on the main app window, the newly opened window goes to the background and is hidden (normal behavior), however, I want the newly opened window to always be on top of the main app window AFTER if I click back on the main application window.
The reason is that the new window (WindowGroup) opened contains an image with the information I need to enter in the main app so if it goes behind the main app window, I can't see the image anymore.
Is there a WindowGroup modifier I can implement so that after the WindowGroup("imageView") window opens, it is always on top & how can I integrate into my existing code?
Thank you!
#main
struct customApp: App {
#StateObject var session = SessionStore()
var body: some Scene {
WindowGroup("mainView") {
ContentView().environmentObject(session)
}.handlesExternalEvents(matching: ["mainView"])
WindowGroup("imageView") {
ImageView(url: SessionStore.imageUrl)
}.handlesExternalEvents(matching: ["imageView"])
}
}
View that opens new window
struct ImageViews: View {
#Environment(\.openURL) var openURL
var body: some View {
HStack {
WebImage(string: idUrl)
.onTapGesture {
guard let url = URL(string: "app://imageView") else { return }
openURL(url)
}
}
}
}
Set the window.level to always on top .floating. You can access it via NSApplication.shared.windows.
Button("Window level") {
for window in NSApplication.shared.windows {
window.level = .floating
}
}

Xamarin (Visual Studio), View mapped MKMapView, not a control on view, will not show navigation bars added to view

I created a View and mapped it to a MKMapView via code, but I cannot seem to have the Navigation Bar show up (it's the 2nd view in the stack, so it should have some ability to show the bar).
The map creates well with all functionality I want, BUT, it takes up the entire view space on the View
public override void LoadView()
{
CoreGraphics.CGRect r = new Rectangle(0, 40, (int)UIScreen.MainScreen.Bounds.Right, (int)UIScreen.MainScreen.Bounds.Bottom);
map = new MKMapView(r);
View = map;
}
any ideas?
To show Navigation Bar , you need make sure that the RootViewController of the Application is an UINavigationController (not an UIViewController) .
in Appdeledate.cs
public bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
// Override point for customization after application launch.
// If not required for your application you can safely delete this method
Window = new UIWindow(UIScreen.MainScreen.Bounds);
Window.RootViewController = new UINavigationController(new YourViewController());
Window.MakeKeyAndVisible();
return true;
}
in SceneDelegate (if your app contains it)
public void WillConnect (UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
{
Window = new UIWindow(scene as UIWindowScene);
Window.RootViewController = new UINavigationController(new YourViewController()) ;
Window.MakeKeyAndVisible();
}
And when you navigate from the first page to the map page
NavigationController.PushViewController(new YourMapController(),true);

Hide iOS navigation bar in Xamarin but retain ability to swipe back

I'm trying to hide the navigation bar on iOS from Xamarin but I want to keep the ability to swipe back to the last page.
I've tried doing this:
this.ViewController.NavigationController.NavigationBar.Hidden = true;
and this:
this.ViewController.NavigationController.NavigationBarHidden = true;
in a custom PageRenderer but neither of those hide the navigation bar. If I remove the navigation bar when I'm pushing the page, I also lose the ability to swipe back.
Any suggestions?
Try this:
public class PageCustomRenderer : PageRenderer, IUIGestureRecognizerDelegate
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
if (NavigationController != null)
{
NavigationController.NavigationBarHidden = true;
NavigationController.InteractivePopGestureRecognizer.Delegate = this;
NavigationController.InteractivePopGestureRecognizer.Enabled = true;
}
}
}
this in a PageRender in iOS is already the ViewController so you can access the NavigationController from there.
You will need to make your PageRenderer implement the IUIGestureRecognizerDelegate so you can make it the delegate for the InteractivePopGestureRecognizer of the NavigationController
Hope this helps.-

Should I be thinking differently about cancelling the back button in Xamarin Forms

I have a Prism based Xamarin Forms app that contains an edit page that is wrapped in a Navigation page so there is a back button at top left on both Android and iOS. To avoid the user accidentally losing an edit in progress by accidentally clicking the back button (in particular on Android) we want to prompt them to confirm that they definitely want to cancel.
Thing is, this seems like something that is not baked in to Xamarin forms. You can override OnBackButtonPressed in a navigation page, but that only gets called for the hardware/software back button on Android. There are articles detailing techniques to intercept the actual arrow button at the top left on Android (involving overriding OnOptionsItemSelected in the Android MainActivity), but on iOS I'm not sure it is even possible.
So I can't help but wonder if I am going about this the wrong way? Should I not be intercepting the top left / hardware / software back button in this way? Seems like a pretty common thing to do (e.g. press back when editing a new contact in the android built in Contacts app and you get a prompt) but it really feels like I am fighting the system here somehow.
There are previous questions around this, most relevant appears to be How to intercept Navigation Bar Back Button Clicked in Xamarin Forms? - but I am looking for some broad brush suggestions for an approach here. My objective is to show the user a page with the <- arrow at top left for Android, "Cancel" for iOS but I would like to get some views about the best way to go about it that does not involve me fighting against prism / navigation pages / xamarin forms and (where possible) not breaking the various "best practices" on Android and iOS.
After going down the same path as you and being told not to prevent users from going back, I decided on showing an alert after they tap the back button (within ContentPage.OnDisappearing()) that says something like Would you like to save your work?.
If you go with this approach, be sure to use Application.MainPage.DisplayAlert() instead of just this.DisplayAlert() since your ContentPage might not be visible at that point.
Here is how I currently handle saving work when they click the back button (I consolidated a good bit of code and changed some things):
protected override async void OnDisappearing() {
base.OnDisappearing();
// At this point the page is gone or is disappearing, but all properties are still available
#region Auto-save Check and Execution
/*
* Checks to see if any edits have been made and if a save is not in progress, if both are true, it asks if they want to save, if yes, it checks for validation errors.
* If it finds them, it marks it as such in the model before saving the model to the DB and showing an alert stating what was done
*/
if(!_viewModel.WorkIsEdited || _viewModel.SaveInProgress) { //WorkIsEdited changes if they enter/change data or focus on certain elements such as a Picker
return;
}
if(!await Application.Current.MainPage.DisplayAlert("ALERT", "You have unsaved work! Would you like to save now?", "Yes", "No")) {
return;
}
if(await _viewModel.SaveClaimErrorsOrNotAsync()) { //The return value is whether validation succeeds or not, but it gets saved either way
App.SuccessToastConfig.Message = "Work saved successfully. Try saving it yourself next time!";
UserDialogs.Instance.Toast(App.SuccessToastConfig);
} else if(await Application.Current.MainPage.DisplayAlert("ERROR", "Work saved successfully but errors were detected. Tap the button to go back to your work.", "To Work Entry", "OK")) {
await Task.Delay(200); //BUG: On Android, the alert above could still be displayed when the page below is pushed, which prevents the page from displaying //BUG: On iOS 10+ currently the alerts are not fully removed from the view hierarchy when execution returns (a fix is in the works)
await Application.Current.MainPage.Navigation.PushAsync(new WorkPage(_viewModel.SavedWork));
}
#endregion
}
What you ask for is not possible. The back button tap cannot be canceled on iOS even in native apps. You can do some other tricks like having a custom 'back' button, but in general you shouldn't do that - you should instead have a modal dialog with the Done and Cancel buttons (or something similar).
If you use xamarin forms that code it is work.
CrossPlatform source
public class CoolContentPage : ContentPage
{
public Action CustomBackButtonAction { get; set; }
public static readonly BindableProperty EnableBackButtonOverrideProperty =
BindableProperty.Create(nameof(EnableBackButtonOverride), typeof(bool), typeof(CoolContentPage), false);
public bool EnableBackButtonOverride{
get { return (bool)GetValue(EnableBackButtonOverrideProperty); }
set { SetValue(EnableBackButtonOverrideProperty, value); }
}
}
}
Android source
public override bool OnOptionsItemSelected(IMenuItem item)
{
if (item.ItemId == 16908332)
{
var currentpage = (CoolContentPage)
Xamarin.Forms.Application.
Current.MainPage.Navigation.
NavigationStack.LastOrDefault();
if (currentpage?.CustomBackButtonAction != null)
{
currentpage?.CustomBackButtonAction.Invoke();
return false;
}
return base.OnOptionsItemSelected(item);
}
else
{
return base.OnOptionsItemSelected(item);
}
}
public override void OnBackPressed()
{
var currentpage = (CoolContentPage)
Xamarin.Forms.Application.
Current.MainPage.Navigation.
NavigationStack.LastOrDefault();
if (currentpage?.CustomBackButtonAction != null)
{
currentpage?.CustomBackButtonAction.Invoke();
}
else
{
base.OnBackPressed();
}
}
iOS source
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
if (((CoolContentPage)Element).EnableBackButtonOverride)
{
SetCustomBackButton();
}
}
private void SetCustomBackButton()
{
var backBtnImage = UIImage.FromBundle("iosbackarrow.png");
backBtnImage = backBtnImage.ImageWithRenderingMode
(UIImageRenderingMode.AlwaysTemplate);
var backBtn = new UIButton(UIButtonType.Custom)
{
HorizontalAlignment =
UIControlContentHorizontalAlignment.Left,
TitleEdgeInsets =
new UIEdgeInsets(11.5f, 15f, 10f, 0f),
ImageEdgeInsets =
new UIEdgeInsets(1f, 8f, 0f, 0f)
};
backBtn.SetTitle("Back", UIControlState.Normal);
backBtn.SetTitleColor(UIColor.White, UIControlState.Normal);
backBtn.SetTitleColor(UIColor.LightGray, UIControlState.Highlighted);
backBtn.Font = UIFont.FromName("HelveticaNeue", (nfloat)17);
backBtn.SetImage(backBtnImage, UIControlState.Normal);
backBtn.SizeToFit();
backBtn.TouchDown += (sender, e) =>
{
// Whatever your custom back button click handling
if(((CoolContentPage)Element)?.
CustomBackButtonAction != null)
{
((CoolContentPage)Element)?.
CustomBackButtonAction.Invoke();
}
};
backBtn.Frame = new CGRect(
0,
0,
UIScreen.MainScreen.Bounds.Width / 4,
NavigationController.NavigationBar.Frame.Height);
var btnContainer = new UIView(
new CGRect(0, 0,
backBtn.Frame.Width, backBtn.Frame.Height));
btnContainer.AddSubview(backBtn);
var fixedSpace =
new UIBarButtonItem(UIBarButtonSystemItem.FixedSpace)
{
Width = -16f
};
var backButtonItem = new UIBarButtonItem("",
UIBarButtonItemStyle.Plain, null)
{
CustomView = backBtn
};
NavigationController.TopViewController.NavigationItem.LeftBarButtonItems = new[] { fixedSpace, backButtonItem };
}
using in xamarin forms
public Page2()
{
InitializeComponent();
if (EnableBackButtonOverride)
{
this.CustomBackButtonAction = async () =>
{
var result = await this.DisplayAlert(null, "Go back?" Yes go back", "Nope");
if (result)
{
await Navigation.PopAsync(true);
}
};
}
}

How to enable long press gesture on table cell in xamarin.ios?

I am working on Xamarin.iOS. I need that when I long press on a UITableCell of a UITableView a specific menu pop up in the form of UIActionSheet.
I have tried using the sources at Xamarin official website but I failed.
Have anyone done this before?
In this sample I managed to add a long press gesture by altering this method in GrowRowTableCell
public GrowRowTableCell (IntPtr handle) : base (handle)
{
var longPressGesture = new UILongPressGestureRecognizer (LongPressMethod);
AddGestureRecognizer (longPressGesture);
}
void LongPressMethod (UILongPressGestureRecognizer gestureRecognizer)
{
if(gestureRecognizer.State == UIGestureRecognizerState.Began)
{
Console.Write("LongPress");
var selectCategory = new UIActionSheet ("ActionSheet", null, "Cancel", "test");
selectCategory.ShowInView (this);
}
}
looks like this:

Resources