Restoring macOS window after close – SwiftUI WindowsGroup

Typical behavior for macOS apps is that the apps will preserve their size and position when closed (Command + W) or quit (Command + Q) by the user. 

11sgE

 

When using SwiftUI & WindowsGroup that’s not the case though: although it works as designed when quitting, it forgets position and size when closing the window (Command + W).

I’m hoping this gets addressed in the future, but until then I’m using AppDelegate to intercept the close command and instead hiding the window. 

@main

struct MarsManagedApp: App {

    

    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    

}

 

class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {

 

    func applicationDidFinishLaunching(_ notification: Notification) {

        let mainWindow = NSApp.windows[0]

        mainWindow.delegate = self

    }

    func windowShouldClose(_ sender: NSWindow) -> Bool {

        NSApp.hide(nil)

        return false

    }

}

Works like a charm, thanks to Mark G for the tip. 

Feedback / suggestions? Reach me at mastodon.social/@MarcMasVi or @MarcMasVi

Marc

Writing these lines from San Diego!

Some personal news to share, my wife and I have relocated to San Diego! 

We’re still in temporary housing, but I do expect to be fully settled starting January. Until then, I’ll be posting less as there’s a lot of things we’re handling ATM. 

So far, loving it here – here’s a pic from yesterday, just a few minutes from my temporary house. 

IMG 6291

And, yes, AvoToast scene is very much here. Approved!

IMG 7033

If you’re based in SD do hit me @MarcMasVi

Marc

Have an M1/M2 Mac? Use Diffusion Bee locally

If you’d like to try Stable Diffusion, the latest AI image generator, and have a Mac with an M1/M2 chip you can download it and run it locally (no technical expertise required)

Screen Shot 2022 09 12 at 10 25 05 AM

Features include:

  • Full data privacy – nothing is sent to the cloud
  • Clean and easy to use UI
  • One click installer
  • No dependencies needed
  • Multiple image sizes
  • Optimized for M1/M2 Chips
  • Runs locally on your computer

Kudos to @divamgupta for making it available, 

Marc

MarsManaged onboarding – Unleashing a new golden age for humanity!

‘Creating a future for Mars!’ ‘Unleashing a new golden age for humanity!’

This weekend I’ve been working on onboarding CARDs for MarsManaged. What’s that I hear you ask? Let me explain…

When the user first opens the app these onboarding CARDs show how to use it in a subtle way, allowing users to become familiar quickly & learn best practices.

To add personality, all CARDs simulate situations a Mars Product Leader could be dealing with. 

Screen Shot 2022 09 04 at 3 15 20 PMYou may know what this Portal to Earth pitch will end up leading to:

I’ve completed 5 out of the 7 onboarding examples so far. Aiming to get 90% there this weekend so i can fully focus on final app polish & launch website.

Feedback / suggestions? Reach me at @MarcMasVi 

Marc

Enabling undo CoreData + SwiftUI

I did a post a while back about how to enable undo functionality when using CoreData. It continues to work great for AppKit or UIKit apps, but what about if you’ve adopted SwiftUI as Apple is suggesting we do?

BestWaySwiftUI

Well… unfortunately the previous approach won’t work quite as well.

After a few hours working this, it turns out it’s quite simple… You have two options:

1. Using the @Environment property:

First, be sure you pass the right managedObjectContext to your top level view as part of the @main App:

    var body: some Scene {

        WindowGroup {

            someTopLevelView

                .environment(\.managedObjectContext,container.viewContext)

        }

Then, in the SwiftUI file where you want to add undo functionality you’ll add the  following @Environment properties

//CoreData convinience

    @Environment(\.managedObjectContext) private var viewContext

    @Environment(\.undoManager) private var undoManager

And then you’ll connect them, ensuring the SwiftUI undoManager is connected to the one you’ve created:

    someView

    .onAppear{

        viewContext.undoManager = undoManager

     }

Voila!

2. Alternatively you can implement your own Undo/Redo Commands in SwiftUI:

    .commands {

        CommandGroup(replacing: .undoRedo) {

            Button(“Undo”) {

                //Trigger  your own undo with your created undoManager

                undoManager?.undo()

            }

            .keyboardShortcut(KeyEquivalent(“z”), modifiers: [.command])

            .disabled(undoManager?.canUndo == false)

            Button(“Redo”) {

                //Trigger  your own undo with your created undoManager

                undoManager?.redo()

            }

            .keyboardShortcut(KeyEquivalent(“z”), modifiers: [.command, .shift])

            .disabled(undoManager?.canRedo == false)

        }

    }

 

And that’s it, now you have full undo functionality for Core Data in SwiftUI. 

Questions / comments? I’m at @MarcMasVi 

Marc

SideBar: The Silent Super-Feature

If done right you will almost never notice it.. It is however one of the most used parts of any app: the sidebar. 

With MarsManaged we’ve gone through quite a few iterations. Here’s a retrospective on the improvements made, and the thinking behind them. 

Sidebars

First Iteration (A): Although it was purely a SwiftUI non-functional prototype, the sidebar already contained all the key elements that would define the app -> notes, tasks and tags. 

Second Iteration (B): To show notes are much more than just text and to indicate intent, Notes are renamed to Action Cards. For the first time we’re also including the concept of Categories, essentially non-deletable Tags.  Finally Tasks is renamed to To-Dos as it reads better.

Third Iteration (C): Minor tweaks here, Action Cards is simplified to Cards and Categories is moved below To-Dos. The reasoning being Tags and Categories should appear at the bottom as they group above elements. Another addition is the button to add a Tag from the sidebar, allowing users to quickly create new ones.

Fourth Iteration (D): A visually minor but significant change, categories no longer exist as their own element. They have now become regular Tags. Pinned ones to be precise. Pinned tags is a new feature where any tag can be pinned to appear above non-pinned ones, separated by a thin line. 

Fifth Iteration (E): As To-Dos are linked to Cards, and Cards are linked to Tags, the order in which they appear on the sidebar is changed to reflect this functional reality (1. ToDo < 2. Card < 3. Tag). Two other changes you’ll notice is that, based on user-testing feedback, Tags is now called Groups and To-Dos has been renamed to Actions, better matching the app theme and showing intent.

Sixth Iteration (F): The New Card and New Action buttons are moved to the Toolbar, freeing the SideBar to only focus on the user content and giving MarsManaged a cleaner look.  

Which takes us to today’s (and probably final) iteration-> Seventh Iteration 

NewImage

6th iteration on the left, 7th on the right

First, the cosmetic changes:  In Focus has become simply Focus and This Week has become Recents.

Second, the Today section is no longer available: although initially I thought it would be convenient for users, the reality is that I was wrong. Today would always be empty at the beginning of the day so users would end up always skipping Today and going to Recents instead, even when they wanted to see Cards they edited today. 

So, here you have it, the evolution of the SideBar over almost a year, one of the most important parts of MarsManaged. What are your thoughts, anything I have missed? Let me know @MarcMasVi

Happy coding,

Marc

MarsManaged July Update: New Palette, Icon, UX Improvements…

Back in Sunny California!

Portugal was great: the food, the weather, the people… In between hikes, museums and reading breaks I’ve done quite a bit of progress on MarsManaged: it’s looking better and better. Every day a bit more polished and user feedback is helping raise the bar big time.

Here’s how the main screen looks like now:

Screen Shot 2022 07 26 at 4 26 03 PM

And here’s how it looks when a Card is selected:

Screen Shot 2022 07 26 at 4 26 11 PM

Finally, as you may recall previous attempts were not satisfactory (to say the least) here’s the latest iteration of the icon: 

Icon

If you want to be part of TestFlight and help shape the future of the app, drop me a line at contact@mmvsolucions.com

Thoughts, suggestions? Reach me @MarcMasVi

Marc

Bom Dia

I’m writing these lines from a wonderful terrace overseeing Guimaraes, a small medieval town in Portugal. 

The day is sunny, there’s a refreshing breeze and -behind me- a fountain provides background noise perfect for focusing. 

IMG 2856

As you may have guessed, I’m on vacation. My wife and I have taken two weeks to visit Portugal, enjoy its cuisine and -of course- read and code. 

The book I’m reading at the moment is Build, by Tony Fadell. It’s an excellent book, a wealth of product experience condensed to its essence. He does not beat around the bush, delivers at every page. 

Nyt the book forward slant

Coding-wise, I’m continuing to work on polish and bug-fixing while keeping impulses to add more features to MarsManaged at bay. I won’t lie, this final phase is not as rewarding/stimulating, it is however necessary to ship a reliable product so powering through it. 

Also, the app icon… I’m playing with different concepts, I’m not entirely happy with any yet. Here’s one option:

Screen Shot 2022 07 11 at 11 07 47 AM

I like the fact that its easily recognizable and scales well to multiple sizes. I do not like that it does not reflect the functionality of the app in any way. 

Here’s another:

Screen Shot 2022 07 11 at 11 08 27 AM

On this one I like that it shows the functionality of the app. However I do not like that it does so poorly and that it does not scale well to multiple sizes. It’s too crowded too. OK, I agree, this one is horrible. 

More to come as I keep iterating.  

Thoughts, suggestions? Reach me @MarcMasVi

Marc

– – –

P.S. After so many holidays at home due to COVID its so refreshing to travel again, I missed this so much.