diff --git a/MijickPopups.podspec b/MijickPopups.podspec index 82f2d4904..88d92b05c 100644 --- a/MijickPopups.podspec +++ b/MijickPopups.podspec @@ -5,7 +5,7 @@ Pod::Spec.new do |s| MijickPopups solves two seemingly contradictory problems - to allow developers to create fully customizable popup, and to make the process as simple as possible. DESC - s.version = '4.0.0' + s.version = '4.0.1' s.ios.deployment_target = '14.0' s.osx.deployment_target = '12.0' s.tvos.deployment_target = '15.0' diff --git a/README.md b/README.md index a3b26aaa0..e0b4785c0 100644 --- a/README.md +++ b/README.md @@ -63,26 +63,83 @@

- Join us on Discord + Join us on Discord - Follow us on LinkedIn + Follow us on LinkedIn - See our other frameworks + See our other frameworks - Read us on Medium + Read us on Medium - Buy us a coffee + Buy us a coffee

+ +# ✨ Features + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
📱Three positions for the popups: Top, Center or Bottom
🎁Stackable popups
đŸĢThree height modes: Automatic, Large or Fullscreen
⛹ī¸Resizable popups
🍃Automatic dismissal
🖖Super easy to use from any place in the code
🚧Fully customizable
đŸ•ēBeautiful animations
🤏đŸŧGestures support
🍏Works with SwiftUI sheets
đŸ–Ĩī¸Supports iOS, macOS, tvOS, watchOS and visionOS
⚡ī¸Supports Swift 6
🚀... and others
+ # ☀ī¸ Why MijickPopups? MijickPopups library solves two seemingly contradictory problems - to allow developers to create fully customizable popup views, and to make the process as simple as possible. Here is why we think we have successfully met these objectives: @@ -145,7 +202,7 @@ Join the welcoming community of developers on [Discord](https://link.mijick.com/ # đŸŒŧ Contribute To contribute a feature or idea to **MijickPopups**, create an [issue](https://github.com/Mijick/Popups/issues/new?assignees=FulcrumOne&labels=state%3A+inactive%2C+type%3A+feature&projects=&template=🚀-feature-request.md&title=%5BFREQ%5D) explaining your idea or bring it up on [Discord](https://discord.com/invite/dT5V7nm5SC).
If you find a bug, please create an [issue](https://github.com/Mijick/Popups/issues/new?assignees=FulcrumOne%2C+jay-jay-lama&labels=state%3A+inactive%2C+type%3A+bug&projects=&template=đŸĻŸ-bug-report.md&title=%5BBUG%5D).
-If you would like to contribute, please refer to the [Contribution Guidelines](https://link.mijick.com/contribution-guidelines). +If you would like to contribute, please refer to the [Contribution Guidelines](https://github.com/Mijick/Popups/blob/main/.github/CONTRIBUTING.md). # 💜 Sponsor our work diff --git a/Sources/Internal/Containers/PopupStack.swift b/Sources/Internal/Containers/PopupStack.swift index 382385665..7d87ecb3c 100644 --- a/Sources/Internal/Containers/PopupStack.swift +++ b/Sources/Internal/Containers/PopupStack.swift @@ -27,7 +27,6 @@ extension PopupStack { } - // MARK: - STACK OPERATIONS @@ -96,7 +95,6 @@ private extension PopupStack { } - // MARK: - STACK CONTAINER OPERATIONS diff --git a/Sources/Internal/Models/AnyPopup.swift b/Sources/Internal/Models/AnyPopup.swift index e21246854..941754399 100644 --- a/Sources/Internal/Models/AnyPopup.swift +++ b/Sources/Internal/Models/AnyPopup.swift @@ -24,7 +24,6 @@ struct AnyPopup: Popup { } - // MARK: - INITIALIZE & UPDATE @@ -70,7 +69,6 @@ private extension AnyPopup { } - // MARK: - PROTOCOLS CONFORMANCE diff --git a/Sources/Internal/Models/ID+Popup.swift b/Sources/Internal/Models/ID+Popup.swift index 866463dbf..99d4d7ee7 100644 --- a/Sources/Internal/Models/ID+Popup.swift +++ b/Sources/Internal/Models/ID+Popup.swift @@ -37,7 +37,6 @@ extension PopupID { } - // MARK: - HELPERS diff --git a/Sources/Internal/UI/PopupCenterStackView.swift b/Sources/Internal/UI/PopupCenterStackView.swift index 0b6af71a2..e3d5526cb 100644 --- a/Sources/Internal/UI/PopupCenterStackView.swift +++ b/Sources/Internal/UI/PopupCenterStackView.swift @@ -15,12 +15,12 @@ struct PopupCenterStackView: View { @ObservedObject var viewModel: VM.CenterStack - var body: some View { + var body: some View { if viewModel.screen.height > 0 { ZStack(content: createPopupStack) .id(viewModel.popups.isEmpty) .transition(transition) .frame(maxWidth: .infinity, maxHeight: viewModel.screen.height) - } + }} } private extension PopupCenterStackView { func createPopupStack() -> some View { diff --git a/Sources/Internal/UI/PopupVerticalStackView.swift b/Sources/Internal/UI/PopupVerticalStackView.swift index cbeaa0685..67a0400e9 100644 --- a/Sources/Internal/UI/PopupVerticalStackView.swift +++ b/Sources/Internal/UI/PopupVerticalStackView.swift @@ -15,11 +15,11 @@ struct PopupVerticalStackView: View { @ObservedObject var viewModel: VM.VerticalStack - var body: some View { + var body: some View { if viewModel.screen.height > 0 { ZStack(alignment: (!viewModel.alignment).toAlignment(), content: createPopupStack) .frame(height: viewModel.screen.height, alignment: viewModel.alignment.toAlignment()) .onDragGesture(onChanged: viewModel.onPopupDragGestureChanged, onEnded: viewModel.onPopupDragGestureEnded, isEnabled: viewModel.dragGestureEnabled) - } + }} } private extension PopupVerticalStackView { func createPopupStack() -> some View { diff --git a/Sources/Internal/UI/PopupView.swift b/Sources/Internal/UI/PopupView.swift index b59e99cff..c80dd5294 100644 --- a/Sources/Internal/UI/PopupView.swift +++ b/Sources/Internal/UI/PopupView.swift @@ -22,6 +22,14 @@ struct PopupView: View { private let bottomStackViewModel: VM.VerticalStack = .init(BottomPopupConfig.self) + init(rootView: any View, popupStack: PopupStack) { + #if os(tvOS) + self.rootView = rootView + #endif + self.stack = popupStack + + Task { [self] in await updateViewModels { await $0.updatePopups(stack.popups) } } + } var body: some View { #if os(tvOS) AnyView(rootView) diff --git a/Sources/Internal/View Models/ViewModel+CentreStack.swift b/Sources/Internal/View Models/ViewModel+CentreStack.swift index db6847549..257388fb1 100644 --- a/Sources/Internal/View Models/ViewModel+CentreStack.swift +++ b/Sources/Internal/View Models/ViewModel+CentreStack.swift @@ -16,12 +16,11 @@ extension VM { class CenterStack: ViewModel { required init() {} var popups: [AnyPopup] = [] var activePopupProperties: ActivePopupProperties = .init() var screen: Screen = .init() - var updatePopupAction: ((AnyPopup) async -> ())! - var closePopupAction: ((AnyPopup) async -> ())! + var updatePopupAction: ((AnyPopup) async -> ())? + var closePopupAction: ((AnyPopup) async -> ())? }} - // MARK: - METHODS / VIEW MODEL / ACTIVE POPUP @@ -84,7 +83,6 @@ extension VM.CenterStack { } - // MARK: - METHODS / VIEW MODEL / SELECTED POPUP @@ -104,7 +102,6 @@ private extension VM.CenterStack { } - // MARK: - METHODS / VIEW diff --git a/Sources/Internal/View Models/ViewModel+VerticalStack.swift b/Sources/Internal/View Models/ViewModel+VerticalStack.swift index a29ca2e87..97f98cacc 100644 --- a/Sources/Internal/View Models/ViewModel+VerticalStack.swift +++ b/Sources/Internal/View Models/ViewModel+VerticalStack.swift @@ -16,12 +16,11 @@ extension VM { class VerticalStack: ViewModel { required init() {} var popups: [AnyPopup] = [] var activePopupProperties: ActivePopupProperties = .init() var screen: Screen = .init() - var updatePopupAction: ((AnyPopup) async -> ())! - var closePopupAction: ((AnyPopup) async -> ())! + var updatePopupAction: ((AnyPopup) async -> ())? + var closePopupAction: ((AnyPopup) async -> ())? }} - // MARK: - METHODS / VIEW MODEL / ACTIVE POPUP @@ -171,7 +170,6 @@ extension VM.VerticalStack { } - // MARK: - METHODS / VIEW MODEL / SELECTED POPUP @@ -214,7 +212,6 @@ private extension VM.VerticalStack { } - // MARK: - METHODS / VIEW @@ -307,7 +304,6 @@ extension VM.VerticalStack { } - // MARK: - GESTURES @@ -371,7 +367,7 @@ extension VM.VerticalStack { } private extension VM.VerticalStack { func dismissLastPopupIfNeeded(_ popup: AnyPopup) async { switch activePopupProperties.translationProgress >= dragThreshold { - case true: await closePopupAction(popup) + case true: await closePopupAction?(popup) case false: return }} func calculateTargetDragHeight(_ activePopup: AnyPopup) async -> CGFloat { diff --git a/Sources/Internal/View Models/ViewModel.swift b/Sources/Internal/View Models/ViewModel.swift index 4f852add0..9340bdb03 100644 --- a/Sources/Internal/View Models/ViewModel.swift +++ b/Sources/Internal/View Models/ViewModel.swift @@ -21,8 +21,8 @@ enum VM {} var screen: Screen { get set } // MARK: Actions - var updatePopupAction: ((AnyPopup) async -> ())! { get set } - var closePopupAction: ((AnyPopup) async -> ())! { get set } + var updatePopupAction: ((AnyPopup) async -> ())? { get set } + var closePopupAction: ((AnyPopup) async -> ())? { get set } // MARK: Methods func calculateActivePopupHeight() async -> CGFloat? @@ -35,7 +35,6 @@ enum VM {} } - // MARK: - INITIALIZE & SETUP @@ -54,7 +53,6 @@ extension ViewModel { } - // MARK: UPDATE @@ -95,7 +93,7 @@ extension ViewModel { let newHeight = await calculatePopupHeight(heightCandidate, popup) if newHeight != popup.height { - await updatePopupAction(popup.updatedHeight(newHeight)) + await updatePopupAction?(popup.updatedHeight(newHeight)) } } } @@ -103,7 +101,7 @@ extension ViewModel { // MARK: Popup Drag Height extension ViewModel { func updatePopupDragHeight(_ targetDragHeight: CGFloat, _ popup: AnyPopup) async { - await updatePopupAction(popup.updatedDragHeight(targetDragHeight)) + await updatePopupAction?(popup.updatedDragHeight(targetDragHeight)) } } diff --git a/Sources/Public/Setup/Public+Setup+SceneDelegate.swift b/Sources/Public/Setup/Public+Setup+SceneDelegate.swift index 3e391b15f..e7adacfe9 100644 --- a/Sources/Public/Setup/Public+Setup+SceneDelegate.swift +++ b/Sources/Public/Setup/Public+Setup+SceneDelegate.swift @@ -73,7 +73,6 @@ extension PopupSceneDelegate { } - // MARK: - WINDOW diff --git a/Sources/Public/Setup/Public+Setup+View.swift b/Sources/Public/Setup/Public+Setup+View.swift index 676d277a4..239e53c19 100644 --- a/Sources/Public/Setup/Public+Setup+View.swift +++ b/Sources/Public/Setup/Public+Setup+View.swift @@ -44,11 +44,11 @@ public extension View { */ func registerPopups(id: PopupStackID = .shared, configBuilder: @escaping (GlobalConfigContainer) -> GlobalConfigContainer = { $0 }) -> some View { #if os(tvOS) - PopupView(rootView: self, stack: .registerStack(id: id)).onAppear { _ = configBuilder(.init()) } + PopupView(rootView: self, popupStack: .registerStack(id: id)).onAppear { _ = configBuilder(.init()) } #else self .frame(maxWidth: .infinity, maxHeight: .infinity) - .overlay(PopupView(stack: .registerStack(id: id)), alignment: .top) + .overlay(PopupView(rootView: self, popupStack: .registerStack(id: id)), alignment: .top) .onAppear { _ = configBuilder(.init()) } #endif } diff --git a/Tests/Tests+PopupID.swift b/Tests/Tests+PopupID.swift index c30460e79..a972982f1 100644 --- a/Tests/Tests+PopupID.swift +++ b/Tests/Tests+PopupID.swift @@ -16,7 +16,6 @@ import SwiftUI @MainActor final class PopupIDTests: XCTestCase {} - // MARK: - TEST CASES @@ -119,7 +118,6 @@ extension PopupIDTests { } - // MARK: - HELPERS diff --git a/Tests/Tests+PopupStack.swift b/Tests/Tests+PopupStack.swift index 148bae864..59cbb272b 100644 --- a/Tests/Tests+PopupStack.swift +++ b/Tests/Tests+PopupStack.swift @@ -20,7 +20,6 @@ import SwiftUI } - // MARK: - TEST CASES @@ -241,7 +240,6 @@ extension PopupStackTests { } - // MARK: - HELPERS diff --git a/Tests/Tests+ViewModel+PopupCenterStack.swift b/Tests/Tests+ViewModel+PopupCenterStack.swift index 47887c6aa..715d29109 100644 --- a/Tests/Tests+ViewModel+PopupCenterStack.swift +++ b/Tests/Tests+ViewModel+PopupCenterStack.swift @@ -37,7 +37,6 @@ private extension PopupCenterStackViewModelTests { } - // MARK: - TEST CASES @@ -223,7 +222,6 @@ private extension PopupCenterStackViewModelTests { } - // MARK: - HELPERS diff --git a/Tests/Tests+ViewModel+PopupVerticalStack.swift b/Tests/Tests+ViewModel+PopupVerticalStack.swift index 2ca6c8267..b995cccc3 100644 --- a/Tests/Tests+ViewModel+PopupVerticalStack.swift +++ b/Tests/Tests+ViewModel+PopupVerticalStack.swift @@ -44,7 +44,6 @@ private extension PopupVerticalStackViewModelTests { } - // MARK: - TEST CASES @@ -133,7 +132,7 @@ extension PopupVerticalStackViewModelTests { private extension PopupVerticalStackViewModelTests { func appendPopupsAndCheckPopups(viewModel: ViewModel, popups: [AnyPopup], updatedPopup: AnyPopup, expectedValue: (height: CGFloat?, dragHeight: CGFloat)) async { await viewModel.updatePopups(popups) - await viewModel.updatePopupAction(updatedPopup) + await viewModel.updatePopupAction?(updatedPopup) if let index = viewModel.popups.firstIndex(of: updatedPopup) { XCTAssertEqual(viewModel.popups[index].height, expectedValue.height) @@ -1475,7 +1474,6 @@ private extension PopupVerticalStackViewModelTests { } - // MARK: - HELPERS