Skip to content

Repository files navigation

SwiftUIAlert

A comprehensive Swift Package solution for SwiftUI alerts management in iOS projects

Installation

📦 Swift Package Manager

Add SwiftUIAlert as a Swift Package in Xcode 11.0 or later, select File > Swift Packages > Add Package Dependency... and add the repository URL:

https://github.com/xxZap/SwiftUIAlert.git

📋 Requirements

  • iOS 15+
  • Swift 5

✅ Feature

Here's the list of the awesome features SwiftUIAlert has:

  • clean way to show single or multiple Alerts in SwiftUI
  • you don't have to add Alerts as view modifiers any more
  • blends in perfectly with all other SwiftUI functioanlity and principles
  • Combine friendly: just listen for changes and communicate them to the AlertController
  • MVVM friendly: handle alerts business logic directly from your viewModels and keep your views agnostic
  • haptic feedbacks
  • sound feedbacks
  • pool of alerts support, to add/dequeue all the needed alerts once at a time
  • solve SwiftUI limitation around lack of completion show/hide alert that forces us a programmatic delay for consecutive alerts

🚨 The Problem

In SwiftUI alerts are added as view modifiers with a bit of help from @State:

structMyView:View{@StateprivatevarisSwiftUIAlert1Presented=false@StateprivatevarisSwiftUIAlert2Presented=falsevarbody:someView{Button("SwiftUI Alert"){
isSwiftUIAlert1Presented =true}.alert(isPresented: $isSwiftUIAlert1Presented){Alert(title:Text("SwiftUI Alert 1"))}.alert(isPresented: $isSwiftUIAlert2Presented){Alert(title:Text("SwiftUI Alert 2"))}...}}

This will get ugly really quickly if you're trying to add multiple Alerts on a view. Lots of @States with Alerts scattered all around your view 💩

It is also really hard to uncouple business logic from the views since alert management is mainly inside the view, violating all the design patterns and the single responsibility principle.

✏️ How SwiftUIAlert works

Simply register an AlertController instance on the root of a navigation. This will ensure an @Environment accessibility to all of the subviews all along the same navigation.

import SwiftUI
import SwiftUIAlert
structExampleRootView:View{@StateObjectprivatevaralertController=AlertController()varbody:someView{NavigationStack{ExampleView()}.registerAlertController(alertController) // <--- Important: register an AlertController instance on the root
// to make it accassible to all the subviews through a dedicated Environment variable
}}

Once an AlertController instance is being register on the root view, you can just access to it in all of the subviews through a dedicated @Environment variable:

structExampleView:View{...@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
...

Now you can just create your ExampleView without caring about the alert creation/handling logic because all the business logic is moved inside the viewmodel, as it should be. You can let your ExampleViewModel to expose a @Published BaseAlert? and connect it to the living alertController instance.

structExampleView:View{@StateObjectprivatevarviewModel=ExampleViewModel()@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
varbody:someView{VStack{Button{
viewModel.onButtonTap()} label:{Text("Show alert")}}.onChange(of: viewModel.alert){ alert in // <--- When the view model emits a new alert value
alertController.alert = alert // just pass it to the alertController to handle its visibility
}}}

Finally, all the logic can be writte in your ViewModel. A small example can be:

import Combine
classExampleViewModel:ObservableObject{@Publishedvaralert:BaseAlert?privatevaralertPublisher:CurrentValueSubject<BaseAlert?,Never>=.init(nil)privatevarcancellables=Set<AnyCancellable>()init(){self.alertPublisher
.receive(on:RunLoop.main).sink{[weak self] alert inself?.alert = alert
}.store(in:&cancellables)}func onOkButtonTap(){
alertPublisher.send(SwiftUIAlert(title:"Title", message:"This is classic cancel/ok alert", alertButtons:[AlertButton("Cancel", role:.cancel){
// Whatever the viewmodel wants to do here...
},AlertButton("Ok", role:.default){
// Whatever the viewmodel wants to do here...
}]))}}

Using this library, you won't see anymore your views horribly scaling when you have to handle multiple alerts and, most of all, your views will not know anything about the logic. You can handle multiple alerts directly on your ViewModel.

🎉 As an extra, this library exposes an alert with an integrated TextField!

🧰 Demo Project

Please, to clarify all your doubts you can see the dedicated Example Project SwiftUIAlertDemo

License

Apache License 2.0. See Apache Software Foundation's licensing FAQ

About

An open source solution for iOS alerts in SwiftUI

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - xxZap/SwiftUIAlert: An open source solution for iOS alerts in SwiftUI · GitHub
Skip to content

Repository files navigation

SwiftUIAlert

A comprehensive Swift Package solution for SwiftUI alerts management in iOS projects

Installation

📦 Swift Package Manager

Add SwiftUIAlert as a Swift Package in Xcode 11.0 or later, select File > Swift Packages > Add Package Dependency... and add the repository URL:

https://github.com/xxZap/SwiftUIAlert.git

📋 Requirements

  • iOS 15+
  • Swift 5

✅ Feature

Here's the list of the awesome features SwiftUIAlert has:

  • clean way to show single or multiple Alerts in SwiftUI
  • you don't have to add Alerts as view modifiers any more
  • blends in perfectly with all other SwiftUI functioanlity and principles
  • Combine friendly: just listen for changes and communicate them to the AlertController
  • MVVM friendly: handle alerts business logic directly from your viewModels and keep your views agnostic
  • haptic feedbacks
  • sound feedbacks
  • pool of alerts support, to add/dequeue all the needed alerts once at a time
  • solve SwiftUI limitation around lack of completion show/hide alert that forces us a programmatic delay for consecutive alerts

🚨 The Problem

In SwiftUI alerts are added as view modifiers with a bit of help from @State:

structMyView:View{@StateprivatevarisSwiftUIAlert1Presented=false@StateprivatevarisSwiftUIAlert2Presented=falsevarbody:someView{Button("SwiftUI Alert"){
isSwiftUIAlert1Presented =true}.alert(isPresented: $isSwiftUIAlert1Presented){Alert(title:Text("SwiftUI Alert 1"))}.alert(isPresented: $isSwiftUIAlert2Presented){Alert(title:Text("SwiftUI Alert 2"))}...}}

This will get ugly really quickly if you're trying to add multiple Alerts on a view. Lots of @States with Alerts scattered all around your view 💩

It is also really hard to uncouple business logic from the views since alert management is mainly inside the view, violating all the design patterns and the single responsibility principle.

✏️ How SwiftUIAlert works

Simply register an AlertController instance on the root of a navigation. This will ensure an @Environment accessibility to all of the subviews all along the same navigation.

import SwiftUI
import SwiftUIAlert
structExampleRootView:View{@StateObjectprivatevaralertController=AlertController()varbody:someView{NavigationStack{ExampleView()}.registerAlertController(alertController) // <--- Important: register an AlertController instance on the root
// to make it accassible to all the subviews through a dedicated Environment variable
}}

Once an AlertController instance is being register on the root view, you can just access to it in all of the subviews through a dedicated @Environment variable:

structExampleView:View{...@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
...

Now you can just create your ExampleView without caring about the alert creation/handling logic because all the business logic is moved inside the viewmodel, as it should be. You can let your ExampleViewModel to expose a @Published BaseAlert? and connect it to the living alertController instance.

structExampleView:View{@StateObjectprivatevarviewModel=ExampleViewModel()@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
varbody:someView{VStack{Button{
viewModel.onButtonTap()} label:{Text("Show alert")}}.onChange(of: viewModel.alert){ alert in // <--- When the view model emits a new alert value
alertController.alert = alert // just pass it to the alertController to handle its visibility
}}}

Finally, all the logic can be writte in your ViewModel. A small example can be:

import Combine
classExampleViewModel:ObservableObject{@Publishedvaralert:BaseAlert?privatevaralertPublisher:CurrentValueSubject<BaseAlert?,Never>=.init(nil)privatevarcancellables=Set<AnyCancellable>()init(){self.alertPublisher
.receive(on:RunLoop.main).sink{[weak self] alert inself?.alert = alert
}.store(in:&cancellables)}func onOkButtonTap(){
alertPublisher.send(SwiftUIAlert(title:"Title", message:"This is classic cancel/ok alert", alertButtons:[AlertButton("Cancel", role:.cancel){
// Whatever the viewmodel wants to do here...
},AlertButton("Ok", role:.default){
// Whatever the viewmodel wants to do here...
}]))}}

Using this library, you won't see anymore your views horribly scaling when you have to handle multiple alerts and, most of all, your views will not know anything about the logic. You can handle multiple alerts directly on your ViewModel.

🎉 As an extra, this library exposes an alert with an integrated TextField!

🧰 Demo Project

Please, to clarify all your doubts you can see the dedicated Example Project SwiftUIAlertDemo

License

Apache License 2.0. See Apache Software Foundation's licensing FAQ

About

An open source solution for iOS alerts in SwiftUI

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - xxZap/SwiftUIAlert: An open source solution for iOS alerts in SwiftUI · GitHub
Skip to content

Repository files navigation

SwiftUIAlert

A comprehensive Swift Package solution for SwiftUI alerts management in iOS projects

Installation

📦 Swift Package Manager

Add SwiftUIAlert as a Swift Package in Xcode 11.0 or later, select File > Swift Packages > Add Package Dependency... and add the repository URL:

https://github.com/xxZap/SwiftUIAlert.git

📋 Requirements

  • iOS 15+
  • Swift 5

✅ Feature

Here's the list of the awesome features SwiftUIAlert has:

  • clean way to show single or multiple Alerts in SwiftUI
  • you don't have to add Alerts as view modifiers any more
  • blends in perfectly with all other SwiftUI functioanlity and principles
  • Combine friendly: just listen for changes and communicate them to the AlertController
  • MVVM friendly: handle alerts business logic directly from your viewModels and keep your views agnostic
  • haptic feedbacks
  • sound feedbacks
  • pool of alerts support, to add/dequeue all the needed alerts once at a time
  • solve SwiftUI limitation around lack of completion show/hide alert that forces us a programmatic delay for consecutive alerts

🚨 The Problem

In SwiftUI alerts are added as view modifiers with a bit of help from @State:

structMyView:View{@StateprivatevarisSwiftUIAlert1Presented=false@StateprivatevarisSwiftUIAlert2Presented=falsevarbody:someView{Button("SwiftUI Alert"){
isSwiftUIAlert1Presented =true}.alert(isPresented: $isSwiftUIAlert1Presented){Alert(title:Text("SwiftUI Alert 1"))}.alert(isPresented: $isSwiftUIAlert2Presented){Alert(title:Text("SwiftUI Alert 2"))}...}}

This will get ugly really quickly if you're trying to add multiple Alerts on a view. Lots of @States with Alerts scattered all around your view 💩

It is also really hard to uncouple business logic from the views since alert management is mainly inside the view, violating all the design patterns and the single responsibility principle.

✏️ How SwiftUIAlert works

Simply register an AlertController instance on the root of a navigation. This will ensure an @Environment accessibility to all of the subviews all along the same navigation.

import SwiftUI
import SwiftUIAlert
structExampleRootView:View{@StateObjectprivatevaralertController=AlertController()varbody:someView{NavigationStack{ExampleView()}.registerAlertController(alertController) // <--- Important: register an AlertController instance on the root
// to make it accassible to all the subviews through a dedicated Environment variable
}}

Once an AlertController instance is being register on the root view, you can just access to it in all of the subviews through a dedicated @Environment variable:

structExampleView:View{...@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
...

Now you can just create your ExampleView without caring about the alert creation/handling logic because all the business logic is moved inside the viewmodel, as it should be. You can let your ExampleViewModel to expose a @Published BaseAlert? and connect it to the living alertController instance.

structExampleView:View{@StateObjectprivatevarviewModel=ExampleViewModel()@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
varbody:someView{VStack{Button{
viewModel.onButtonTap()} label:{Text("Show alert")}}.onChange(of: viewModel.alert){ alert in // <--- When the view model emits a new alert value
alertController.alert = alert // just pass it to the alertController to handle its visibility
}}}

Finally, all the logic can be writte in your ViewModel. A small example can be:

import Combine
classExampleViewModel:ObservableObject{@Publishedvaralert:BaseAlert?privatevaralertPublisher:CurrentValueSubject<BaseAlert?,Never>=.init(nil)privatevarcancellables=Set<AnyCancellable>()init(){self.alertPublisher
.receive(on:RunLoop.main).sink{[weak self] alert inself?.alert = alert
}.store(in:&cancellables)}func onOkButtonTap(){
alertPublisher.send(SwiftUIAlert(title:"Title", message:"This is classic cancel/ok alert", alertButtons:[AlertButton("Cancel", role:.cancel){
// Whatever the viewmodel wants to do here...
},AlertButton("Ok", role:.default){
// Whatever the viewmodel wants to do here...
}]))}}

Using this library, you won't see anymore your views horribly scaling when you have to handle multiple alerts and, most of all, your views will not know anything about the logic. You can handle multiple alerts directly on your ViewModel.

🎉 As an extra, this library exposes an alert with an integrated TextField!

🧰 Demo Project

Please, to clarify all your doubts you can see the dedicated Example Project SwiftUIAlertDemo

License

Apache License 2.0. See Apache Software Foundation's licensing FAQ

About

An open source solution for iOS alerts in SwiftUI

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - xxZap/SwiftUIAlert: An open source solution for iOS alerts in SwiftUI · GitHub
Skip to content

Repository files navigation

SwiftUIAlert

A comprehensive Swift Package solution for SwiftUI alerts management in iOS projects

Installation

📦 Swift Package Manager

Add SwiftUIAlert as a Swift Package in Xcode 11.0 or later, select File > Swift Packages > Add Package Dependency... and add the repository URL:

https://github.com/xxZap/SwiftUIAlert.git

📋 Requirements

  • iOS 15+
  • Swift 5

✅ Feature

Here's the list of the awesome features SwiftUIAlert has:

  • clean way to show single or multiple Alerts in SwiftUI
  • you don't have to add Alerts as view modifiers any more
  • blends in perfectly with all other SwiftUI functioanlity and principles
  • Combine friendly: just listen for changes and communicate them to the AlertController
  • MVVM friendly: handle alerts business logic directly from your viewModels and keep your views agnostic
  • haptic feedbacks
  • sound feedbacks
  • pool of alerts support, to add/dequeue all the needed alerts once at a time
  • solve SwiftUI limitation around lack of completion show/hide alert that forces us a programmatic delay for consecutive alerts

🚨 The Problem

In SwiftUI alerts are added as view modifiers with a bit of help from @State:

structMyView:View{@StateprivatevarisSwiftUIAlert1Presented=false@StateprivatevarisSwiftUIAlert2Presented=falsevarbody:someView{Button("SwiftUI Alert"){
isSwiftUIAlert1Presented =true}.alert(isPresented: $isSwiftUIAlert1Presented){Alert(title:Text("SwiftUI Alert 1"))}.alert(isPresented: $isSwiftUIAlert2Presented){Alert(title:Text("SwiftUI Alert 2"))}...}}

This will get ugly really quickly if you're trying to add multiple Alerts on a view. Lots of @States with Alerts scattered all around your view 💩

It is also really hard to uncouple business logic from the views since alert management is mainly inside the view, violating all the design patterns and the single responsibility principle.

✏️ How SwiftUIAlert works

Simply register an AlertController instance on the root of a navigation. This will ensure an @Environment accessibility to all of the subviews all along the same navigation.

import SwiftUI
import SwiftUIAlert
structExampleRootView:View{@StateObjectprivatevaralertController=AlertController()varbody:someView{NavigationStack{ExampleView()}.registerAlertController(alertController) // <--- Important: register an AlertController instance on the root
// to make it accassible to all the subviews through a dedicated Environment variable
}}

Once an AlertController instance is being register on the root view, you can just access to it in all of the subviews through a dedicated @Environment variable:

structExampleView:View{...@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
...

Now you can just create your ExampleView without caring about the alert creation/handling logic because all the business logic is moved inside the viewmodel, as it should be. You can let your ExampleViewModel to expose a @Published BaseAlert? and connect it to the living alertController instance.

structExampleView:View{@StateObjectprivatevarviewModel=ExampleViewModel()@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
varbody:someView{VStack{Button{
viewModel.onButtonTap()} label:{Text("Show alert")}}.onChange(of: viewModel.alert){ alert in // <--- When the view model emits a new alert value
alertController.alert = alert // just pass it to the alertController to handle its visibility
}}}

Finally, all the logic can be writte in your ViewModel. A small example can be:

import Combine
classExampleViewModel:ObservableObject{@Publishedvaralert:BaseAlert?privatevaralertPublisher:CurrentValueSubject<BaseAlert?,Never>=.init(nil)privatevarcancellables=Set<AnyCancellable>()init(){self.alertPublisher
.receive(on:RunLoop.main).sink{[weak self] alert inself?.alert = alert
}.store(in:&cancellables)}func onOkButtonTap(){
alertPublisher.send(SwiftUIAlert(title:"Title", message:"This is classic cancel/ok alert", alertButtons:[AlertButton("Cancel", role:.cancel){
// Whatever the viewmodel wants to do here...
},AlertButton("Ok", role:.default){
// Whatever the viewmodel wants to do here...
}]))}}

Using this library, you won't see anymore your views horribly scaling when you have to handle multiple alerts and, most of all, your views will not know anything about the logic. You can handle multiple alerts directly on your ViewModel.

🎉 As an extra, this library exposes an alert with an integrated TextField!

🧰 Demo Project

Please, to clarify all your doubts you can see the dedicated Example Project SwiftUIAlertDemo

License

Apache License 2.0. See Apache Software Foundation's licensing FAQ

About

An open source solution for iOS alerts in SwiftUI

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - xxZap/SwiftUIAlert: An open source solution for iOS alerts in SwiftUI · GitHub
Skip to content

Repository files navigation

SwiftUIAlert

A comprehensive Swift Package solution for SwiftUI alerts management in iOS projects

Installation

📦 Swift Package Manager

Add SwiftUIAlert as a Swift Package in Xcode 11.0 or later, select File > Swift Packages > Add Package Dependency... and add the repository URL:

https://github.com/xxZap/SwiftUIAlert.git

📋 Requirements

  • iOS 15+
  • Swift 5

✅ Feature

Here's the list of the awesome features SwiftUIAlert has:

  • clean way to show single or multiple Alerts in SwiftUI
  • you don't have to add Alerts as view modifiers any more
  • blends in perfectly with all other SwiftUI functioanlity and principles
  • Combine friendly: just listen for changes and communicate them to the AlertController
  • MVVM friendly: handle alerts business logic directly from your viewModels and keep your views agnostic
  • haptic feedbacks
  • sound feedbacks
  • pool of alerts support, to add/dequeue all the needed alerts once at a time
  • solve SwiftUI limitation around lack of completion show/hide alert that forces us a programmatic delay for consecutive alerts

🚨 The Problem

In SwiftUI alerts are added as view modifiers with a bit of help from @State:

structMyView:View{@StateprivatevarisSwiftUIAlert1Presented=false@StateprivatevarisSwiftUIAlert2Presented=falsevarbody:someView{Button("SwiftUI Alert"){
isSwiftUIAlert1Presented =true}.alert(isPresented: $isSwiftUIAlert1Presented){Alert(title:Text("SwiftUI Alert 1"))}.alert(isPresented: $isSwiftUIAlert2Presented){Alert(title:Text("SwiftUI Alert 2"))}...}}

This will get ugly really quickly if you're trying to add multiple Alerts on a view. Lots of @States with Alerts scattered all around your view 💩

It is also really hard to uncouple business logic from the views since alert management is mainly inside the view, violating all the design patterns and the single responsibility principle.

✏️ How SwiftUIAlert works

Simply register an AlertController instance on the root of a navigation. This will ensure an @Environment accessibility to all of the subviews all along the same navigation.

import SwiftUI
import SwiftUIAlert
structExampleRootView:View{@StateObjectprivatevaralertController=AlertController()varbody:someView{NavigationStack{ExampleView()}.registerAlertController(alertController) // <--- Important: register an AlertController instance on the root
// to make it accassible to all the subviews through a dedicated Environment variable
}}

Once an AlertController instance is being register on the root view, you can just access to it in all of the subviews through a dedicated @Environment variable:

structExampleView:View{...@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
...

Now you can just create your ExampleView without caring about the alert creation/handling logic because all the business logic is moved inside the viewmodel, as it should be. You can let your ExampleViewModel to expose a @Published BaseAlert? and connect it to the living alertController instance.

structExampleView:View{@StateObjectprivatevarviewModel=ExampleViewModel()@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
varbody:someView{VStack{Button{
viewModel.onButtonTap()} label:{Text("Show alert")}}.onChange(of: viewModel.alert){ alert in // <--- When the view model emits a new alert value
alertController.alert = alert // just pass it to the alertController to handle its visibility
}}}

Finally, all the logic can be writte in your ViewModel. A small example can be:

import Combine
classExampleViewModel:ObservableObject{@Publishedvaralert:BaseAlert?privatevaralertPublisher:CurrentValueSubject<BaseAlert?,Never>=.init(nil)privatevarcancellables=Set<AnyCancellable>()init(){self.alertPublisher
.receive(on:RunLoop.main).sink{[weak self] alert inself?.alert = alert
}.store(in:&cancellables)}func onOkButtonTap(){
alertPublisher.send(SwiftUIAlert(title:"Title", message:"This is classic cancel/ok alert", alertButtons:[AlertButton("Cancel", role:.cancel){
// Whatever the viewmodel wants to do here...
},AlertButton("Ok", role:.default){
// Whatever the viewmodel wants to do here...
}]))}}

Using this library, you won't see anymore your views horribly scaling when you have to handle multiple alerts and, most of all, your views will not know anything about the logic. You can handle multiple alerts directly on your ViewModel.

🎉 As an extra, this library exposes an alert with an integrated TextField!

🧰 Demo Project

Please, to clarify all your doubts you can see the dedicated Example Project SwiftUIAlertDemo

License

Apache License 2.0. See Apache Software Foundation's licensing FAQ

About

An open source solution for iOS alerts in SwiftUI

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - xxZap/SwiftUIAlert: An open source solution for iOS alerts in SwiftUI · GitHub
Skip to content

Repository files navigation

SwiftUIAlert

A comprehensive Swift Package solution for SwiftUI alerts management in iOS projects

Installation

📦 Swift Package Manager

Add SwiftUIAlert as a Swift Package in Xcode 11.0 or later, select File > Swift Packages > Add Package Dependency... and add the repository URL:

https://github.com/xxZap/SwiftUIAlert.git

📋 Requirements

  • iOS 15+
  • Swift 5

✅ Feature

Here's the list of the awesome features SwiftUIAlert has:

  • clean way to show single or multiple Alerts in SwiftUI
  • you don't have to add Alerts as view modifiers any more
  • blends in perfectly with all other SwiftUI functioanlity and principles
  • Combine friendly: just listen for changes and communicate them to the AlertController
  • MVVM friendly: handle alerts business logic directly from your viewModels and keep your views agnostic
  • haptic feedbacks
  • sound feedbacks
  • pool of alerts support, to add/dequeue all the needed alerts once at a time
  • solve SwiftUI limitation around lack of completion show/hide alert that forces us a programmatic delay for consecutive alerts

🚨 The Problem

In SwiftUI alerts are added as view modifiers with a bit of help from @State:

structMyView:View{@StateprivatevarisSwiftUIAlert1Presented=false@StateprivatevarisSwiftUIAlert2Presented=falsevarbody:someView{Button("SwiftUI Alert"){
isSwiftUIAlert1Presented =true}.alert(isPresented: $isSwiftUIAlert1Presented){Alert(title:Text("SwiftUI Alert 1"))}.alert(isPresented: $isSwiftUIAlert2Presented){Alert(title:Text("SwiftUI Alert 2"))}...}}

This will get ugly really quickly if you're trying to add multiple Alerts on a view. Lots of @States with Alerts scattered all around your view 💩

It is also really hard to uncouple business logic from the views since alert management is mainly inside the view, violating all the design patterns and the single responsibility principle.

✏️ How SwiftUIAlert works

Simply register an AlertController instance on the root of a navigation. This will ensure an @Environment accessibility to all of the subviews all along the same navigation.

import SwiftUI
import SwiftUIAlert
structExampleRootView:View{@StateObjectprivatevaralertController=AlertController()varbody:someView{NavigationStack{ExampleView()}.registerAlertController(alertController) // <--- Important: register an AlertController instance on the root
// to make it accassible to all the subviews through a dedicated Environment variable
}}

Once an AlertController instance is being register on the root view, you can just access to it in all of the subviews through a dedicated @Environment variable:

structExampleView:View{...@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
...

Now you can just create your ExampleView without caring about the alert creation/handling logic because all the business logic is moved inside the viewmodel, as it should be. You can let your ExampleViewModel to expose a @Published BaseAlert? and connect it to the living alertController instance.

structExampleView:View{@StateObjectprivatevarviewModel=ExampleViewModel()@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
varbody:someView{VStack{Button{
viewModel.onButtonTap()} label:{Text("Show alert")}}.onChange(of: viewModel.alert){ alert in // <--- When the view model emits a new alert value
alertController.alert = alert // just pass it to the alertController to handle its visibility
}}}

Finally, all the logic can be writte in your ViewModel. A small example can be:

import Combine
classExampleViewModel:ObservableObject{@Publishedvaralert:BaseAlert?privatevaralertPublisher:CurrentValueSubject<BaseAlert?,Never>=.init(nil)privatevarcancellables=Set<AnyCancellable>()init(){self.alertPublisher
.receive(on:RunLoop.main).sink{[weak self] alert inself?.alert = alert
}.store(in:&cancellables)}func onOkButtonTap(){
alertPublisher.send(SwiftUIAlert(title:"Title", message:"This is classic cancel/ok alert", alertButtons:[AlertButton("Cancel", role:.cancel){
// Whatever the viewmodel wants to do here...
},AlertButton("Ok", role:.default){
// Whatever the viewmodel wants to do here...
}]))}}

Using this library, you won't see anymore your views horribly scaling when you have to handle multiple alerts and, most of all, your views will not know anything about the logic. You can handle multiple alerts directly on your ViewModel.

🎉 As an extra, this library exposes an alert with an integrated TextField!

🧰 Demo Project

Please, to clarify all your doubts you can see the dedicated Example Project SwiftUIAlertDemo

License

Apache License 2.0. See Apache Software Foundation's licensing FAQ

About

An open source solution for iOS alerts in SwiftUI

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - xxZap/SwiftUIAlert: An open source solution for iOS alerts in SwiftUI · GitHub
Skip to content

Repository files navigation

SwiftUIAlert

A comprehensive Swift Package solution for SwiftUI alerts management in iOS projects

Installation

📦 Swift Package Manager

Add SwiftUIAlert as a Swift Package in Xcode 11.0 or later, select File > Swift Packages > Add Package Dependency... and add the repository URL:

https://github.com/xxZap/SwiftUIAlert.git

📋 Requirements

  • iOS 15+
  • Swift 5

✅ Feature

Here's the list of the awesome features SwiftUIAlert has:

  • clean way to show single or multiple Alerts in SwiftUI
  • you don't have to add Alerts as view modifiers any more
  • blends in perfectly with all other SwiftUI functioanlity and principles
  • Combine friendly: just listen for changes and communicate them to the AlertController
  • MVVM friendly: handle alerts business logic directly from your viewModels and keep your views agnostic
  • haptic feedbacks
  • sound feedbacks
  • pool of alerts support, to add/dequeue all the needed alerts once at a time
  • solve SwiftUI limitation around lack of completion show/hide alert that forces us a programmatic delay for consecutive alerts

🚨 The Problem

In SwiftUI alerts are added as view modifiers with a bit of help from @State:

structMyView:View{@StateprivatevarisSwiftUIAlert1Presented=false@StateprivatevarisSwiftUIAlert2Presented=falsevarbody:someView{Button("SwiftUI Alert"){
isSwiftUIAlert1Presented =true}.alert(isPresented: $isSwiftUIAlert1Presented){Alert(title:Text("SwiftUI Alert 1"))}.alert(isPresented: $isSwiftUIAlert2Presented){Alert(title:Text("SwiftUI Alert 2"))}...}}

This will get ugly really quickly if you're trying to add multiple Alerts on a view. Lots of @States with Alerts scattered all around your view 💩

It is also really hard to uncouple business logic from the views since alert management is mainly inside the view, violating all the design patterns and the single responsibility principle.

✏️ How SwiftUIAlert works

Simply register an AlertController instance on the root of a navigation. This will ensure an @Environment accessibility to all of the subviews all along the same navigation.

import SwiftUI
import SwiftUIAlert
structExampleRootView:View{@StateObjectprivatevaralertController=AlertController()varbody:someView{NavigationStack{ExampleView()}.registerAlertController(alertController) // <--- Important: register an AlertController instance on the root
// to make it accassible to all the subviews through a dedicated Environment variable
}}

Once an AlertController instance is being register on the root view, you can just access to it in all of the subviews through a dedicated @Environment variable:

structExampleView:View{...@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
...

Now you can just create your ExampleView without caring about the alert creation/handling logic because all the business logic is moved inside the viewmodel, as it should be. You can let your ExampleViewModel to expose a @Published BaseAlert? and connect it to the living alertController instance.

structExampleView:View{@StateObjectprivatevarviewModel=ExampleViewModel()@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
varbody:someView{VStack{Button{
viewModel.onButtonTap()} label:{Text("Show alert")}}.onChange(of: viewModel.alert){ alert in // <--- When the view model emits a new alert value
alertController.alert = alert // just pass it to the alertController to handle its visibility
}}}

Finally, all the logic can be writte in your ViewModel. A small example can be:

import Combine
classExampleViewModel:ObservableObject{@Publishedvaralert:BaseAlert?privatevaralertPublisher:CurrentValueSubject<BaseAlert?,Never>=.init(nil)privatevarcancellables=Set<AnyCancellable>()init(){self.alertPublisher
.receive(on:RunLoop.main).sink{[weak self] alert inself?.alert = alert
}.store(in:&cancellables)}func onOkButtonTap(){
alertPublisher.send(SwiftUIAlert(title:"Title", message:"This is classic cancel/ok alert", alertButtons:[AlertButton("Cancel", role:.cancel){
// Whatever the viewmodel wants to do here...
},AlertButton("Ok", role:.default){
// Whatever the viewmodel wants to do here...
}]))}}

Using this library, you won't see anymore your views horribly scaling when you have to handle multiple alerts and, most of all, your views will not know anything about the logic. You can handle multiple alerts directly on your ViewModel.

🎉 As an extra, this library exposes an alert with an integrated TextField!

🧰 Demo Project

Please, to clarify all your doubts you can see the dedicated Example Project SwiftUIAlertDemo

License

Apache License 2.0. See Apache Software Foundation's licensing FAQ

About

An open source solution for iOS alerts in SwiftUI

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - xxZap/SwiftUIAlert: An open source solution for iOS alerts in SwiftUI · GitHub
Skip to content

Repository files navigation

SwiftUIAlert

A comprehensive Swift Package solution for SwiftUI alerts management in iOS projects

Installation

📦 Swift Package Manager

Add SwiftUIAlert as a Swift Package in Xcode 11.0 or later, select File > Swift Packages > Add Package Dependency... and add the repository URL:

https://github.com/xxZap/SwiftUIAlert.git

📋 Requirements

  • iOS 15+
  • Swift 5

✅ Feature

Here's the list of the awesome features SwiftUIAlert has:

  • clean way to show single or multiple Alerts in SwiftUI
  • you don't have to add Alerts as view modifiers any more
  • blends in perfectly with all other SwiftUI functioanlity and principles
  • Combine friendly: just listen for changes and communicate them to the AlertController
  • MVVM friendly: handle alerts business logic directly from your viewModels and keep your views agnostic
  • haptic feedbacks
  • sound feedbacks
  • pool of alerts support, to add/dequeue all the needed alerts once at a time
  • solve SwiftUI limitation around lack of completion show/hide alert that forces us a programmatic delay for consecutive alerts

🚨 The Problem

In SwiftUI alerts are added as view modifiers with a bit of help from @State:

structMyView:View{@StateprivatevarisSwiftUIAlert1Presented=false@StateprivatevarisSwiftUIAlert2Presented=falsevarbody:someView{Button("SwiftUI Alert"){
isSwiftUIAlert1Presented =true}.alert(isPresented: $isSwiftUIAlert1Presented){Alert(title:Text("SwiftUI Alert 1"))}.alert(isPresented: $isSwiftUIAlert2Presented){Alert(title:Text("SwiftUI Alert 2"))}...}}

This will get ugly really quickly if you're trying to add multiple Alerts on a view. Lots of @States with Alerts scattered all around your view 💩

It is also really hard to uncouple business logic from the views since alert management is mainly inside the view, violating all the design patterns and the single responsibility principle.

✏️ How SwiftUIAlert works

Simply register an AlertController instance on the root of a navigation. This will ensure an @Environment accessibility to all of the subviews all along the same navigation.

import SwiftUI
import SwiftUIAlert
structExampleRootView:View{@StateObjectprivatevaralertController=AlertController()varbody:someView{NavigationStack{ExampleView()}.registerAlertController(alertController) // <--- Important: register an AlertController instance on the root
// to make it accassible to all the subviews through a dedicated Environment variable
}}

Once an AlertController instance is being register on the root view, you can just access to it in all of the subviews through a dedicated @Environment variable:

structExampleView:View{...@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
...

Now you can just create your ExampleView without caring about the alert creation/handling logic because all the business logic is moved inside the viewmodel, as it should be. You can let your ExampleViewModel to expose a @Published BaseAlert? and connect it to the living alertController instance.

structExampleView:View{@StateObjectprivatevarviewModel=ExampleViewModel()@Environment(\.alertController)privatevaralertController // <--- You have alertController as Environment variable
// all along ExampleRootView navigation
varbody:someView{VStack{Button{
viewModel.onButtonTap()} label:{Text("Show alert")}}.onChange(of: viewModel.alert){ alert in // <--- When the view model emits a new alert value
alertController.alert = alert // just pass it to the alertController to handle its visibility
}}}

Finally, all the logic can be writte in your ViewModel. A small example can be:

import Combine
classExampleViewModel:ObservableObject{@Publishedvaralert:BaseAlert?privatevaralertPublisher:CurrentValueSubject<BaseAlert?,Never>=.init(nil)privatevarcancellables=Set<AnyCancellable>()init(){self.alertPublisher
.receive(on:RunLoop.main).sink{[weak self] alert inself?.alert = alert
}.store(in:&cancellables)}func onOkButtonTap(){
alertPublisher.send(SwiftUIAlert(title:"Title", message:"This is classic cancel/ok alert", alertButtons:[AlertButton("Cancel", role:.cancel){
// Whatever the viewmodel wants to do here...
},AlertButton("Ok", role:.default){
// Whatever the viewmodel wants to do here...
}]))}}

Using this library, you won't see anymore your views horribly scaling when you have to handle multiple alerts and, most of all, your views will not know anything about the logic. You can handle multiple alerts directly on your ViewModel.

🎉 As an extra, this library exposes an alert with an integrated TextField!

🧰 Demo Project

Please, to clarify all your doubts you can see the dedicated Example Project SwiftUIAlertDemo

License

Apache License 2.0. See Apache Software Foundation's licensing FAQ

About

An open source solution for iOS alerts in SwiftUI

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages