danielsaidi / SystemNotification

SystemNotification is a Swift SDK that helps you mimic the native iOS system notification in SwiftUI.
MIT License
442 stars 15 forks source link

SystemNotification pops NavigationView if the user has navigated to a child view before the animation finishes #7

Closed devraj closed 2 years ago

devraj commented 2 years ago

Environment:

It's most likely that I am doing something wrong here, but I am at a dead end, hence posing the question here. If it turns out to be something I am doing then it will be something good to make a note of and make it available as part of the documentation.

My view somewhat looks like this

ScrollView {
    ... deleted for simplicity
}
.navigationTitle("Title")
.toolbar {
    /**
        Settings for the Controller
        */
    Button(action: {
        self.sheetContext.present(ControllerSettingsView())
    }) {
        Image(systemName: "gear")
    }
}
.onAppear {
    if (self.isFirstRun) {
        // Show a notification with the status
        self.showZoneStatusNotification()
        // Invalidate first run
        self.isFirstRun = false
    }
}
.onDisappear {
    // Stop the notification if the user flicks back
    // or forth from the view, if this isn't done you see
    // the notification even if the view is no longer active
    if(self.notificationContext.isActive) {
        self.notificationContext.dismiss()
    }
}

and is displayed in a NavigationView, the function that calls SystemNotification looks like

private func showZoneStatusNotification() {
    if let status = self.sprinklerController.status {
        let statusNotification = SystemNotificationMessage(
            icon: Image(systemName: (status.online ? "checkmark.circle.fill":"bell.slash.fill")),
            title: "Title_ControllerHealth",
            text: status.summary!,
            configuration: .init(iconColor: (status.online ? .green:.red))
        )
        self.notificationContext.present(content: statusNotification)
    }
}

The notificationContext is bound to the NavigationView

NavigationView {
    ControllerPickerView(
        sheetContext: self.sheetContext,
        notificationContext: self.notificationContext)
}
.navigationViewStyle(.automatic)
.systemNotification(self.notificationContext)
.sheet(context: self.sheetContext)

and it's reference passed down to the children as a @StateObject. Note that I do use SwiftUIKit and the modifier follows the .systemNotification modifier (which i wouldn't think would be causing the issue).

Video demo, I can make available the source and the app via TestFlight if it's of any use:

danielsaidi commented 2 years ago

Hmmmm, do you navigate from a page that presents the notification to another one that has the same behavior? It seems like the screen dismisses the notification when it disappears, and that the next presented view also presents it?

Would it be possible to move the present logic to the navigation view file instead? You don't need to explicitly dismiss it, since it will dismiss itself after a few seconds.

Also, the context should be defined as a @StateObject in the navigation view file, but passed down as an @EnvironmentObject.

devraj commented 2 years ago

My bad! I had it as @StateObject in the children. That fixed it, thank you so much.

Out of interest does SheetContext in SwiftUIKit have the same pattern?

danielsaidi commented 2 years ago

Ah, thatโ€™s great! ๐Ÿ˜€

Yeah, the sheet, alert and full screen modal contexts in SwiftUIKit behaves similar.

danielsaidi commented 2 years ago

The app looks ๐Ÿ’ฏ btw ๐Ÿ‘

devraj commented 2 years ago

Look out for the links in the credits section ๐Ÿ˜‰

danielsaidi commented 2 years ago

Haha nice!