ContentView.swift 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. // Copyright 2020 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import Combine
  15. import FirebaseCore
  16. import FirebaseInstallations
  17. import FirebaseMessaging
  18. import SwiftUI
  19. import UIKit
  20. struct ContentView: View {
  21. @EnvironmentObject var identity: Identity
  22. @EnvironmentObject var settings: UserSettings
  23. @State private var log: String = ""
  24. var body: some View {
  25. NavigationView {
  26. // Outer stack containing the list and the buttons.
  27. VStack {
  28. List {
  29. VStack(alignment: .leading) {
  30. Text("InstallationsID")
  31. .font(.subheadline)
  32. .fontWeight(.semibold)
  33. Text(identity.installationsID ?? "None").foregroundColor(.green)
  34. }
  35. VStack(alignment: .leading) {
  36. Text("Token")
  37. .font(.subheadline)
  38. .fontWeight(.semibold)
  39. Text(identity.token ?? "None")
  40. .foregroundColor(.green)
  41. // Increase the layout priority to allow more than one line to be shown. Without this,
  42. // the
  43. // simulator renders a single truncated line even though the Preview renders it
  44. // appropriately. Potentially a bug in the simulator?
  45. .layoutPriority(1)
  46. .lineLimit(7)
  47. }
  48. NavigationLink(destination: SettingsView()) {
  49. Text("Settings")
  50. .fontWeight(.semibold)
  51. }
  52. NavigationLink(destination: TopicView()) {
  53. Text("Topic")
  54. .fontWeight(.semibold)
  55. }
  56. #if LIVE_ACTIVITY_ENABLED
  57. NavigationLink(destination: LiveActivityView()) {
  58. Text("Live Activity")
  59. .fontWeight(.semibold)
  60. }
  61. #endif
  62. // MARK: Action buttons
  63. VStack(alignment: .leading) {
  64. Text("getToken")
  65. .fontWeight(.semibold)
  66. HStack {
  67. Button(action: getIDAndToken) {
  68. HStack {
  69. Image(systemName: "arrow.clockwise.circle.fill")
  70. Text("FID & Token")
  71. .fontWeight(.semibold)
  72. }
  73. }
  74. Button(action: getFCMToken) {
  75. HStack {
  76. Image(systemName: "arrow.clockwise.circle.fill").font(.body)
  77. Text("getToken")
  78. .fontWeight(.semibold)
  79. }
  80. }
  81. }
  82. }.font(.system(size: 14))
  83. VStack(alignment: .leading) {
  84. Text("deleteToken")
  85. .fontWeight(.semibold)
  86. HStack {
  87. Button(action: deleteFCMToken) {
  88. HStack {
  89. Image(systemName: "trash.fill")
  90. Text("deleteToken")
  91. .fontWeight(.semibold)
  92. }
  93. }
  94. }
  95. }.font(.system(size: 14))
  96. VStack(alignment: .leading) {
  97. Text("delete")
  98. .fontWeight(.semibold)
  99. HStack {
  100. Button(action: deleteFCM) {
  101. HStack {
  102. Image(systemName: "trash.fill")
  103. Text("FM.delete")
  104. .fontWeight(.semibold)
  105. }
  106. }
  107. Button(action: deleteFID) {
  108. HStack {
  109. Image(systemName: "trash.fill")
  110. Text("FIS.delete")
  111. .fontWeight(.semibold)
  112. }
  113. }
  114. }
  115. }.font(.system(size: 14))
  116. Text("\(log)")
  117. .lineLimit(10)
  118. .multilineTextAlignment(.leading)
  119. }
  120. .navigationBarTitle("Firebase Messaging")
  121. }.buttonStyle(IdentityButtonStyle())
  122. }
  123. }
  124. func getIDAndToken() {
  125. Messaging.messaging().token { token, error in
  126. guard let token = token, error == nil else {
  127. self.log = "Failed getting iid and token: \(String(describing: error))"
  128. return
  129. }
  130. self.identity.token = token
  131. self.log = "Successfully got token."
  132. print("Token: ", self.identity.token ?? "")
  133. Installations.installations().installationID { fid, error in
  134. self.identity.installationsID = fid
  135. self.log = "Successfully got iid and token."
  136. }
  137. }
  138. }
  139. func getFCMToken() {
  140. Messaging.messaging().token { token, error in
  141. guard let token = token, error == nil else {
  142. self.log = "Failed getting iid and token: \(String(describing: error))"
  143. return
  144. }
  145. self.identity.token = token
  146. self.log = "Successfully got token."
  147. print("Token: ", self.identity.token ?? "")
  148. }
  149. }
  150. func deleteFCMToken() {
  151. Messaging.messaging().deleteToken { error in
  152. if let error = error as NSError? {
  153. self.log = "Failed deleting token: \(error)"
  154. return
  155. }
  156. self.log = "Successfully deleted token."
  157. }
  158. }
  159. func deleteFCM() {
  160. Messaging.messaging().deleteData { error in
  161. if let error = error as NSError? {
  162. self.log = "Failed deleting Messaging: \(error)"
  163. return
  164. }
  165. self.log = "Successfully deleted Messaging data."
  166. }
  167. }
  168. func deleteFID() {
  169. Installations.installations().delete { error in
  170. if let error = error as NSError? {
  171. self.log = "Failed deleting FID: \(error)"
  172. return
  173. }
  174. self.log = "Successfully deleted FID."
  175. }
  176. }
  177. }
  178. struct ActivityViewController: UIViewControllerRepresentable {
  179. var activityItems: [Any]
  180. var applicationActivities: [UIActivity]? = nil
  181. func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityViewController>)
  182. -> UIActivityViewController {
  183. let controller = UIActivityViewController(
  184. activityItems: activityItems,
  185. applicationActivities: applicationActivities
  186. )
  187. return controller
  188. }
  189. func updateUIViewController(_ uiViewController: UIActivityViewController,
  190. context: UIViewControllerRepresentableContext<
  191. ActivityViewController
  192. >) {}
  193. }
  194. struct SettingsView: View {
  195. @EnvironmentObject var settings: UserSettings
  196. @State var shouldUseDelegate = true
  197. @State private var isSharePresented: Bool = false
  198. var body: some View {
  199. VStack {
  200. List {
  201. Toggle(isOn: $settings.isAutoInitEnabled) {
  202. Text("isAutoInitEnabled")
  203. .fontWeight(.semibold)
  204. }
  205. Toggle(isOn: $settings.shouldUseDelegateThanNotification) {
  206. Text("shouldUseDelegate")
  207. .fontWeight(.semibold)
  208. }
  209. Button(action: shareToken) {
  210. HStack {
  211. Image(systemName: "square.and.arrow.up").font(.body)
  212. Text("Share Token")
  213. .fontWeight(.semibold)
  214. }
  215. }
  216. .sheet(isPresented: $isSharePresented, onDismiss: {
  217. print("Dismiss")
  218. }, content: {
  219. let items = [Messaging.messaging().fcmToken]
  220. ActivityViewController(activityItems: items as [Any])
  221. })
  222. }
  223. .font(.subheadline)
  224. .foregroundColor(.blue)
  225. }
  226. }
  227. func shareToken() {
  228. isSharePresented = true
  229. }
  230. }
  231. struct ContentView_Previews: PreviewProvider {
  232. // A fake filled identity for testing rendering of a filled cell.
  233. static let filledIdentity: Identity = {
  234. var identity = Identity()
  235. identity.installationsID = UUID().uuidString
  236. // The token is a long string, generate a very long repeating string of characters to see how
  237. // the view
  238. // will react.
  239. let longString = UUID().uuidString.replacingOccurrences(of: "-", with: "")
  240. identity.token = Array(repeating: longString, count: 8).reduce("", +)
  241. return identity
  242. }()
  243. static let filledSettings: UserSettings = {
  244. var settings = UserSettings()
  245. settings.shouldUseDelegateThanNotification = true
  246. settings.isAutoInitEnabled = true
  247. return settings
  248. }()
  249. static var previews: some View {
  250. Group {
  251. ContentView().environmentObject(filledIdentity).environmentObject(filledSettings)
  252. }
  253. }
  254. }
  255. struct IdentityButtonStyle: ButtonStyle {
  256. func makeBody(configuration: Self.Configuration) -> some View {
  257. configuration.label
  258. .frame(minWidth: 0, maxWidth: 120)
  259. .padding()
  260. .foregroundColor(.white)
  261. .background(Color.yellow)
  262. .cornerRadius(20)
  263. // Push the button down a bit when it's pressed.
  264. .scaleEffect(configuration.isPressed ? 0.9 : 1)
  265. .font(.footnote)
  266. }
  267. }