SubscriptionAddView.swift 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import SwiftUI
  2. struct SubscriptionAddView: View {
  3. private let tag = "SubscriptionAddView"
  4. @Binding var isShowing: Bool
  5. @EnvironmentObject private var store: Store
  6. @State private var topic: String = ""
  7. @State private var useAnother: Bool = false
  8. @State private var baseUrl: String = ""
  9. private var subscriptionManager: SubscriptionManager {
  10. return SubscriptionManager(store: store)
  11. }
  12. var body: some View {
  13. NavigationView {
  14. VStack {
  15. Form {
  16. Section(
  17. footer:
  18. Text("Topics are not password protected, so choose a name that's not easy to guess. Once subscribed, you can PUT/POST notifications")
  19. ) {
  20. TextField("Topic name, e.g. phil_alerts", text: $topic)
  21. .disableAutocapitalization()
  22. .disableAutocorrection(true)
  23. }
  24. Section(
  25. footer:
  26. (useAnother) ? Text("Support for self-hosted servers is currently limited. To ensure instant delivery, be sure to set upstream-base-url in your server's config, otherwise messages may arrive with significant delay. Auth is not yet supported.") : Text("")
  27. ) {
  28. Toggle("Use another server", isOn: $useAnother)
  29. if useAnother {
  30. TextField("Server URL, e.g. https://ntfy.example.com", text: $baseUrl)
  31. .disableAutocapitalization()
  32. .disableAutocorrection(true)
  33. }
  34. }
  35. }
  36. }
  37. .navigationTitle("Add subscription")
  38. .navigationBarTitleDisplayMode(.inline)
  39. .toolbar {
  40. ToolbarItem(placement: .navigationBarLeading) {
  41. Button(action: cancelAction) {
  42. Text("Cancel")
  43. }
  44. }
  45. ToolbarItem(placement: .navigationBarTrailing) {
  46. Button(action: subscribeAction) {
  47. Text("Subscribe")
  48. }
  49. .disabled(!isValid())
  50. }
  51. }
  52. }
  53. }
  54. private var sanitizedTopic: String {
  55. return topic.trimmingCharacters(in: .whitespaces)
  56. }
  57. private func isValid() -> Bool {
  58. if sanitizedTopic.isEmpty {
  59. return false
  60. } else if sanitizedTopic.range(of: "^[-_A-Za-z0-9]{1,64}$", options: .regularExpression, range: nil, locale: nil) == nil {
  61. return false
  62. } else if store.getSubscription(baseUrl: selectedBaseUrl, topic: topic) != nil {
  63. return false
  64. }
  65. return true
  66. }
  67. private func subscribeAction() {
  68. DispatchQueue.global(qos: .background).async {
  69. subscriptionManager.subscribe(baseUrl: selectedBaseUrl, topic: sanitizedTopic)
  70. }
  71. isShowing = false
  72. }
  73. private func cancelAction() {
  74. isShowing = false
  75. }
  76. private var selectedBaseUrl: String {
  77. return (useAnother) ? baseUrl : Config.appBaseUrl
  78. }
  79. }
  80. struct SubscriptionAddView_Previews: PreviewProvider {
  81. @State static var isShowing = true
  82. static var previews: some View {
  83. let store = Store.preview
  84. SubscriptionAddView(isShowing: $isShowing)
  85. .environmentObject(store)
  86. }
  87. }