// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import UIKit import Combine import SwiftUI import FirebaseCore import FirebaseMessaging import FirebaseInstallations struct ContentView: View { @EnvironmentObject var identity: Identity @EnvironmentObject var settings: UserSettings @State private var log: String = "" var body: some View { NavigationView { // Outer stack containing the list and the buttons. VStack { List { VStack(alignment: .leading) { Text("InstallationsID") .font(.subheadline) .fontWeight(.semibold) Text(identity.installationsID ?? "None").foregroundColor(.green) } VStack(alignment: .leading) { Text("Token") .font(.subheadline) .fontWeight(.semibold) Text(identity.token ?? "None") .foregroundColor(.green) // Increase the layout priority to allow more than one line to be shown. Without this, // the // simulator renders a single truncated line even though the Preview renders it // appropriately. Potentially a bug in the simulator? .layoutPriority(1) .lineLimit(7) } NavigationLink(destination: SettingsView()) { Text("Settings") .fontWeight(.semibold) } NavigationLink(destination: TopicView()) { Text("Topic") .fontWeight(.semibold) } // MARK: Action buttons VStack(alignment: .leading) { Text("getToken") .fontWeight(.semibold) HStack { Button(action: getIDAndToken) { HStack { Image(systemName: "arrow.clockwise.circle.fill") Text("FID & Token") .fontWeight(.semibold) } } Button(action: getFCMToken) { HStack { Image(systemName: "arrow.clockwise.circle.fill").font(.body) Text("getToken") .fontWeight(.semibold) } } } }.font(.system(size: 14)) VStack(alignment: .leading) { Text("deleteToken") .fontWeight(.semibold) HStack { Button(action: deleteFCMToken) { HStack { Image(systemName: "trash.fill") Text("deleteToken") .fontWeight(.semibold) } } } }.font(.system(size: 14)) VStack(alignment: .leading) { Text("delete") .fontWeight(.semibold) HStack { Button(action: deleteFCM) { HStack { Image(systemName: "trash.fill") Text("FM.delete") .fontWeight(.semibold) } } Button(action: deleteFID) { HStack { Image(systemName: "trash.fill") Text("FIS.delete") .fontWeight(.semibold) } } } }.font(.system(size: 14)) Text("\(log)") .lineLimit(10) .multilineTextAlignment(.leading) } .navigationBarTitle("Firebase Messaging") }.buttonStyle(IdentityButtonStyle()) } } func getIDAndToken() { Messaging.messaging().token { token, error in guard let token = token, error == nil else { self.log = "Failed getting iid and token: \(String(describing: error))" return } self.identity.token = token self.log = "Successfully got token." print("Token: ", self.identity.token ?? "") Installations.installations().installationID { fid, error in self.identity.installationsID = fid self.log = "Successfully got iid and token." } } } func getFCMToken() { Messaging.messaging().token { token, error in guard let token = token, error == nil else { self.log = "Failed getting iid and token: \(String(describing: error))" return } self.identity.token = token self.log = "Successfully got token." print("Token: ", self.identity.token ?? "") } } func deleteFCMToken() { Messaging.messaging().deleteToken { error in if let error = error as NSError? { self.log = "Failed deleting token: \(error)" return } self.log = "Successfully deleted token." } } func deleteFCM() { Messaging.messaging().deleteData { error in if let error = error as NSError? { self.log = "Failed deleting Messaging: \(error)" return } self.log = "Successfully deleted Messaging data." } } func deleteFID() { Installations.installations().delete { error in if let error = error as NSError? { self.log = "Failed deleting FID: \(error)" return } self.log = "Successfully deleted FID." } } } struct ActivityViewController: UIViewControllerRepresentable { var activityItems: [Any] var applicationActivities: [UIActivity]? = nil func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIActivityViewController { let controller = UIActivityViewController( activityItems: activityItems, applicationActivities: applicationActivities ) return controller } func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext< ActivityViewController >) {} } struct SettingsView: View { @EnvironmentObject var settings: UserSettings @State var shouldUseDelegate = true @State private var isSharePresented: Bool = false var body: some View { VStack { List { Toggle(isOn: $settings.isAutoInitEnabled) { Text("isAutoInitEnabled") .fontWeight(.semibold) } Toggle(isOn: $settings.shouldUseDelegateThanNotification) { Text("shouldUseDelegate") .fontWeight(.semibold) } Button(action: shareToken) { HStack { Image(systemName: "square.and.arrow.up").font(.body) Text("Share Token") .fontWeight(.semibold) } } .sheet(isPresented: $isSharePresented, onDismiss: { print("Dismiss") }, content: { let items = [Messaging.messaging().fcmToken] ActivityViewController(activityItems: items as [Any]) }) } .font(.subheadline) .foregroundColor(.blue) } } func shareToken() { isSharePresented = true } } struct ContentView_Previews: PreviewProvider { // A fake filled identity for testing rendering of a filled cell. static let filledIdentity: Identity = { var identity = Identity() identity.installationsID = UUID().uuidString // The token is a long string, generate a very long repeating string of characters to see how // the view // will react. let longString = UUID().uuidString.replacingOccurrences(of: "-", with: "") identity.token = Array(repeating: longString, count: 8).reduce("", +) return identity }() static let filledSettings: UserSettings = { var settings = UserSettings() settings.shouldUseDelegateThanNotification = true settings.isAutoInitEnabled = true return settings }() static var previews: some View { Group { ContentView().environmentObject(filledIdentity).environmentObject(filledSettings) } } } struct IdentityButtonStyle: ButtonStyle { func makeBody(configuration: Self.Configuration) -> some View { configuration.label .frame(minWidth: 0, maxWidth: 120) .padding() .foregroundColor(.white) .background(Color.yellow) .cornerRadius(20) // Push the button down a bit when it's pressed. .scaleEffect(configuration.isPressed ? 0.9 : 1) .font(.footnote) } }