// // Create Party.swift // Pickt // // Created by Morris Richman on 9/11/21. // import SwiftUI import Moya import Firebase import FirebaseFirestore import CoreLocation import Foundation import Introspect import ResponderChain import CDYelpFusionKit import TMDb struct createParty: View { @State private var location = "" @State private var code = "" @State private var creatingParty = false @State private var startPicker = false @State private var devTools = false @State var devToolsText = "" { didSet { print("devToolsText = \(devToolsText)") devTools = true } } @State private var creating = false @State private var textAlertMessage = "" @State private var textAlertFieldPlaceholder = "" @State private var blank = "" @State private var enterLoc = false @State private var codeExists = false @State private var disabledAlert = false @State private var nameError = false @State private var name = "" @State private var updateApp = false let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String let build = Bundle.main.infoDictionary?["CFBundleVersion"] as! String let db = Firestore.firestore() @State private var filter = "Dine in and Takeout"//filterOpt.all @State private var cuisine = "All" @State private var price = "$$" @State private var mediaType = "TV Shows" @State var filterOpt = Array<String>() @State var picktType = Utilities.picktTypeOpt.restaurants @State var howTo = false let cuisineOpt = ["All", "American", "Breakfast", "Chinese", "Comfort", "Italian", "Indian", "Japanese", "Sushi", "Thai", "Vietnamese", "Vegetarian"] let desertOpt = ["Bakery", "Ice Cream"] let nonCuisineOpt = ["Fast Food", "Lunch", "Dinner"] let priceOpt = ["$", "$$", "$$$", "$$$$"] let mediaOpt = ["TV Shows", "Movies"] let locIf = ["Current Location", "current location", "Current", "current", "CURRENT", "CURRENT LOCATION", "Current location"] let helpIf = ["Help", "help", "Support", "support", "Contact", "contact"] let devToolsIf = ["DevTools", "Devtools", "devTools", "devtools", "Dev Tools", "Dev tools", "dev Tools", "dev tools"] let shareIf = ["Share", "share"] @State private var longitude:Double = 0 @State private var latitude:Double = 0 @EnvironmentObject var chain: ResponderChain let nilPlace = Restaurants(name: "nil", imageUrl: URL(string: Utilities.noImage)!, id: "abcdef", rating: 0, url: "https://google.com", location: "nil", category: ["nil"], tag: [], isClosed: true, price: "Unknown", reviewCount: 0) @State private var locManager = CLLocationManager() { didSet { if locManager.authorizationStatus == .authorizedWhenInUse || locManager.authorizationStatus == .authorizedAlways { location = "Current Location" }else { allowLocation = true } } } @State private var allowLocation = false @Environment(\.presentationMode) var presentationMode @Environment(\.horizontalSizeClass) var horizantalSizeClass @State private var restMock: [Restaurants] = [] { didSet { //print("mock = \(mock)") // startPicker = true presentationMode.wrappedValue.dismiss() } } @State private var mediaMock: [Media] = [] { didSet { print("mock = \(mediaMock)") // startPicker = true presentationMode.wrappedValue.dismiss() } } func searchYelp(loc: String) { print("searching") print("Searchloc = \(loc)") Utilities.location = loc Utilities.restFilter = filter Utilities.cuisine = cuisine let service = MoyaProvider<YelpService.BuisnessesProvider>() let jsonDecoder = JSONDecoder() if loc == "friends" || loc == "family" || loc == "Family" || loc == "Friends" { restMock = Restaurants.viewModels }else { var finalCuisine = String() if cuisine == "All" { finalCuisine = "" }else { finalCuisine = "\(cuisine) food " } func handleResponse(businesses: [CDYelpBusiness]) { var businessList: [Restaurants] = [] for buis in businesses { let finalAddress = buis.location!.displayAddress!.joined(separator: " ") print("Cats = \(buis.categories)") CDYelpFusionKitManager.checkType(of: buis.categories!) { cat in print("cat = \(cat)") print("\(Restaurants(name: buis.name!, imageUrl: buis.imageUrl ?? URL(string: Utilities.noImage)!, id: buis.id!, rating: buis.rating!, url: "\(buis.url!)", location: finalAddress, category: cat, tag: [], isClosed: buis.isClosed!, price: buis.price ?? "Unknown", reviewCount: buis.reviewCount!))") businessList.append(Restaurants(name: buis.name!, imageUrl: buis.imageUrl ?? URL(string: Utilities.noImage)!, id: buis.id!, rating: buis.rating!, url: "\(buis.url!)", location: finalAddress, category: cat, tag: [], isClosed: buis.isClosed!, price: buis.price ?? "Unknown", reviewCount: buis.reviewCount!)) if businessList.count == businesses.count { print("coninue") Utilities.restMock = businessList restMock = businessList } } } // print(businesses) } if Utilities.latLong { CDYelpFusionKitManager.shared.apiClient.searchBusinesses(byTerm: "\(finalCuisine)\(filter) Restaurants", location: nil, latitude: latitude, longitude: longitude, radius: nil, categories: nil, locale: .english_unitedStates, limit: 20, offset: 0, sortBy: CDYelpFusionKitManager.sortby, priceTiers: nil, openNow: nil, openAt: nil, attributes: nil) { response in if let response = response, let businesses = response.businesses, businesses.count > 0 { handleResponse(businesses: businesses) } } }else { CDYelpFusionKitManager.shared.apiClient.searchBusinesses(byTerm: "\(finalCuisine)\(filter) Restaurants", location: location, latitude: nil, longitude: nil, radius: nil, categories: nil, locale: .english_unitedStates, limit: 20, offset: 0, sortBy: CDYelpFusionKitManager.sortby, priceTiers: nil, openNow: nil, openAt: nil, attributes: nil) { response in if let response = response, let businesses = response.businesses, businesses.count > 0 { handleResponse(businesses: businesses) } } } } } func create() { UIApplication.shared.endEditing() print("picktType = \(picktType)") print("loc = \(location.lowercased())") if location.lowercased() == "dev tools" || location.lowercased() == "devtools" {//devToolsIf.contains(location.lowercased()) { devToolsText = "Version = \(version)\nBuild = \(build)\nConnection Status = \(NetworkMonitor.shared.isConnected)\nConnection Type = \(NetworkMonitor.shared.connectionType!)" }else if helpIf.contains(location.lowercased()) { guard let url = URL(string: "mailto:\(Utilities.remoteConfig["supportEmail"].stringValue!)") else { return } UIApplication.shared.open(url) }else if shareIf.contains(location.lowercased()) { let text = "I found this great app called Pickt. It helps groups of people find a place to eat. You should download it here: https://apps.apple.com/us/app/pickt/id1584491007" let activityVC = UIActivityViewController(activityItems: [text], applicationActivities: nil) UIApplication.shared.windows.first?.rootViewController?.present(activityVC, animated: true, completion: nil) }else if location.lowercased() == "type.switch = enabled" && Utilities.appType != .AppStore { print("enable switch") Utilities.switchEnabled = true presentationMode.wrappedValue.dismiss() }else if location.lowercased() == "type.switch = disabled" { print("disable switch") Utilities.switchEnabled = false presentationMode.wrappedValue.dismiss() }else { if NetworkMonitor.shared.isConnected { func finish(latLong: Bool) { // print("pass") if name != "" { creating = true UserDefaults.standard.setValue(name, forKey: "deviceName") Utilities.name = name if location != "" || picktType == .media { let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" code = "" Utilities.code = "" for _ in 0..<6 { code.append(letters.randomElement()!) } // name = "" // Utilities.name = "" // for _ in 0..<10 { // name.append(letters.randomElement()!) // } print("name = \(name)") print("code = \(code)") let date = Date() let calendar = Calendar.current let day = calendar.component(.day, from: date) let month = calendar.component(.month, from: date) let year = calendar.component(.year, from: date) let dateCompiled = "\(month)/\(day)/\(year)" // print("dateCompiled = \(dateCompiled)") func setup() { if picktType == .media { print("pass") codeExists = false Utilities.name = name Utilities.code = code print("utilities.code = \(Utilities.code)") db.collection("parties").document(code).setData(["filter" : "\(mediaType)", "devices" : ["\(name)"], "devicesDone" : [], "date" : dateCompiled, "type" : picktType.rawValue], merge: false) Utilities.picktType = .media print("mediaType = \(mediaType)") if mediaType == "TV Shows" { Utilities.mediaType = .TVShows if #available(iOS 15.0.0, *) { entertainment.searchTVShows { list in Utilities.mediaMock = list mediaMock = list } } else { // Fallback on earlier versions } }else if mediaType == "Movies" { Utilities.mediaType = .Movies if #available(iOS 15.0.0, *) { entertainment.searchMovies { list in Utilities.mediaMock = list mediaMock = list } } else { // Fallback on earlier versions } } }else { print("pass") codeExists = false Utilities.name = name Utilities.code = code print("utilities.code = \(Utilities.code)") db.collection("parties").document(code).setData(["latLong" : latLong, "lat" : latitude, "loc" : "\(location)", "long" : longitude, "filter" : "\(filter)", "cuisine" : "\(cuisine)", "devices" : ["\(name)"], "devicesDone" : [], "date" : dateCompiled, "price" : price, "type" : picktType.rawValue], merge: false) Utilities.restFilter = filter Utilities.cuisine = cuisine print("loc = \(location)") searchYelp(loc: location) } } db.collection("parties").document(code).getDocument(completion: { document, error in if error == nil { if document != nil && document!.exists{ print("doc exists already") if let date = document!.get("date") as? String { print("date = \(date), currentDate = \(dateCompiled)") create() } }else { setup() } }else { print("error = \(error)") } }) }else { textAlertFieldPlaceholder = "Enter Location" enterLoc = true } }else { print("No name found") textAlertFieldPlaceholder = "Enter Your Name" nameError = true } } if picktType == .media { print("Pickt Type = media") finish(latLong: false) }else { print("loc = \(location), locIf = \(locIf), latLong = \(Utilities.latLong)") if (locIf.contains(location) || Utilities.latLong == true) && Utilities.currentLocationEnabled { Utilities.latLong = true locManager.requestWhenInUseAuthorization() if locManager.authorizationStatus == .authorizedWhenInUse || locManager.authorizationStatus == .authorizedAlways { print("Loc = \(locManager.location), lat = \(locManager.location?.coordinate.latitude ?? nil), long = \(locManager.location?.coordinate.longitude ?? nil)") if Utilities.appType == .Debug { if locManager.location?.coordinate.latitude == nil { latitude = 47.68114 }else { latitude = locManager.location!.coordinate.latitude } if locManager.location?.coordinate.longitude == nil { longitude = -122.39898 }else { longitude = locManager.location!.coordinate.longitude } }else { latitude = locManager.location!.coordinate.latitude longitude = locManager.location!.coordinate.longitude } Utilities.latLong = true var center : CLLocationCoordinate2D = CLLocationCoordinate2D() let ceo: CLGeocoder = CLGeocoder() center.latitude = latitude center.longitude = longitude let loc: CLLocation = CLLocation(latitude:center.latitude, longitude: center.longitude) ceo.reverseGeocodeLocation(loc, completionHandler: {(placemarks, error) in if (error != nil) { print("reverse geodcode fail: \(error!.localizedDescription)") } let pm = placemarks! as [CLPlacemark] if pm.count > 0 { let pm = placemarks![0] print(pm.country) print(pm.locality) print(pm.subLocality) print(pm.thoroughfare) print(pm.postalCode) print(pm.subThoroughfare) var addressString : String = "" if pm.subLocality != nil { addressString = addressString + pm.subLocality! + ", " } if pm.thoroughfare != nil { addressString = addressString + pm.thoroughfare! + ", " } if pm.locality != nil { addressString = addressString + pm.locality! + ", " } if pm.country != nil { addressString = addressString + pm.country! + ", " } if pm.postalCode != nil { addressString = addressString + pm.postalCode! + " " } location = addressString print(addressString) finish(latLong: true) } }) }else { Utilities.latLong = false locManager.requestWhenInUseAuthorization() allowLocation = true } }else { Utilities.latLong = false latitude = 0 longitude = 0 finish(latLong: false) } } }else { print("not connected") disabledAlert = true } } } var body: some View { NavigationView { VStack { Text("Create Party") .font(.largeTitle) .padding(.bottom) if Utilities.picktType == .media { Text("Please Note: This search has no filter and will show a range of content.") .font(.footnote) .padding(.horizontal) }else { Text("Please Note: Restaurants are shown in order of distance among other things, filters may work in certain places better than others.") .font(.footnote) .padding(.horizontal) } VStack { HStack { Group { Image(systemName: "book.closed") TextField("Enter Your Name", text: $name, onCommit: { Utilities.name = name UserDefaults.standard.setValue(name, forKey: "deviceName") }) .frame(minHeight: 35) if !name.isEmpty { Button(action: { self.name = "" }) { Image(systemName: "xmark.circle") .foregroundColor(Color.gray) } .padding(.trailing) } } .padding([.top, .leading, .bottom], 5.0) } .background(Color.gray.opacity(0.3)) .clipShape(RoundedRectangle(cornerRadius: 15)) .padding([.top, .horizontal]) if picktType == .media { HStack { if #available(iOS 15, *) { Text("Media Type: ") .lineLimit(2) // .padding(.trailing) Picker("", selection: $mediaType) { ForEach(mediaOpt, id: \.self) { Text($0) } } }else { Picker("Media Type: ", selection: $mediaType) { ForEach(mediaOpt, id: \.self) { Text($0) } } } } .padding(.horizontal) .pickerStyle(.menu) }else { HStack { Group { Image(systemName: "magnifyingglass") TextField("Enter Location", text: $location, onCommit: { print("locIf = \(locIf), loc = \(location)") if locIf.contains(location.lowercased()) { Utilities.latLong = true }else { Utilities.latLong = false } }) .frame(minHeight: 35) .minimumScaleFactor(0.6) if !location.isEmpty { Button(action: { self.location = "" }) { Image(systemName: "xmark.circle") .foregroundColor(Color.gray) } } if devToolsIf.contains(location) { Button { location = "" } label: { Image(systemName: "server.rack") } } if shareIf.contains(location.lowercased()) { Button { location = "" } label: { Image(systemName: "square.and.arrow.up.fill") } } if helpIf.contains(location) { Button { location = "" } label: { Image(systemName: "questionmark.circle.fill") } } if Utilities.currentLocationEnabled { Button(action: { if location == "Current Location" { location = "" Utilities.latLong = false }else { locManager.requestWhenInUseAuthorization() print("locManager authStatus = \(locManager.authorizationStatus)") if locManager.authorizationStatus == .denied { allowLocation = true } // if locManager.authorizationStatus == .authorizedWhenInUse || locManager.authorizationStatus == .authorizedAlways { location = "Current Location" Utilities.latLong = true // }else { // allowLocation = true // } } }, label: { if locIf.contains(location) { Image(systemName: "location.fill") }else { Image(systemName: "location") } }) .padding(.trailing) } } .padding([.top, .leading, .bottom], 5.0) } .background(Color.gray.opacity(0.3)) .clipShape(RoundedRectangle(cornerRadius: 15)) .padding([.bottom, .horizontal]) Group { if horizantalSizeClass == .regular { HStack { if #available(iOS 15, *) { Text("Restaurant Filter: ") .lineLimit(2) // .padding(.trailing) Picker("", selection: $filter) { ForEach(filterOpt, id: \.self) { Text($0) } } Spacer() .frame(width: 30) Text("Cuisine: ") // .padding(.trailing) Picker("", selection: $cuisine) { Section { ForEach(nonCuisineOpt, id: \.self) { Text($0) } } Section { ForEach(desertOpt.sorted(), id: \.self) { Text($0) } } Section { ForEach(cuisineOpt.sorted(), id: \.self) { Text($0) } } } // Spacer() // .frame(width: 30) // HStack { // Text("Price: ") // // .padding(.trailing) // Picker("", selection: $price) { // ForEach(priceOpt.sorted(), id: \.self) { // Text($0) // } // } // } }else { Picker("Restaurant Filter", selection: $filter) { ForEach(filterOpt, id: \.self) { Text($0) } } Spacer() .frame(width: 30) Picker("Cuisine", selection: $cuisine) { Section { ForEach(nonCuisineOpt, id: \.self) { Text($0) } } Section { ForEach(desertOpt.sorted().reversed(), id: \.self) { Text($0) } } Section { ForEach(cuisineOpt.sorted(), id: \.self) { Text($0) } } } // Spacer() // .frame(width: 30) // Picker("Price", selection: $price) { // ForEach(priceOpt.sorted(), id: \.self) { // Text($0) // } // } } } }else { VStack { if #available(iOS 15, *) { HStack { Text("Restaurant Filter: ") .lineLimit(2) // .padding(.trailing) Picker("", selection: $filter) { ForEach(filterOpt, id: \.self) { Text($0) } } } HStack { Text("Cuisine: ") // .padding(.trailing) Picker("", selection: $cuisine) { Section { ForEach(cuisineOpt.sorted().reversed(), id: \.self) { Text($0) } } Section { ForEach(desertOpt.sorted().reversed(), id: \.self) { Text($0) } } Section { ForEach(nonCuisineOpt.reversed(), id: \.self) { Text($0) } } } } // HStack { // Text("Price: ") // // .padding(.trailing) // Picker("", selection: $price) { // ForEach(priceOpt.sorted(), id: \.self) { // Text($0) // } // } // } }else { Picker("Restaurant Filter", selection: $filter) { ForEach(filterOpt, id: \.self) { Text($0) } } Picker("Cuisine", selection: $cuisine) { Section { ForEach(cuisineOpt.sorted().reversed(), id: \.self) { Text($0) } } Section { ForEach(desertOpt.sorted().reversed(), id: \.self) { Text($0) } } Section { ForEach(nonCuisineOpt.reversed(), id: \.self) { Text($0) } } } // Picker("Price", selection: $price) { // ForEach(priceOpt.sorted(), id: \.self) { // Text($0) // } // } } } } } .padding(.horizontal) .pickerStyle(.menu) } HStack { Button("Done") { if locIf.contains(location) { Utilities.latLong = true }else { Utilities.latLong = false } print("done") Utilities.checkForUpdate { update in print("update = \(update)") if update && !Utilities.ignoreUpdate { updateApp = true }else { create() } } } Spacer() .frame(width: 40) Button("Cancel") { print("Cancel") presentationMode.wrappedValue.dismiss() } } .padding() } if creating { Text("Creating Party...") .padding(.top) } AlertControlView(textString: $blank, showAlert: $enterLoc, textPlaceholder: $textAlertFieldPlaceholder, title: "Error", message: "Please enter location to continue.", onDone: { loc in location = loc create() }, onCancel: { enterLoc = false creating = false }) } .fullScreenCover(isPresented: $startPicker, content: { ContentView(join: false, create: false, showPicker: true, setMock: $restMock) }) .sheet(isPresented: $howTo, content: { Guide(sender: .create) }) .toolbar { Group { if horizantalSizeClass == .compact { Button(action: {howTo = true}, label: { Image(systemName: "book.closed") Text("How To") }) }else { NavigationLink( destination: Guide(sender: .create), label: { Image(systemName: "book.closed") Text("How To") }) } } } .alert(isPresented: $disabledAlert, content: { Alert(title: Text("Network Error"), message: Text("You aren't connected to the internet, please connect to use Pickt."), dismissButton: .default(Text("Ok"), action: { disabledAlert = false presentationMode.wrappedValue.dismiss() })) }) .alert(isPresented: $devTools, content: { Alert(title: Text("DevTools"), message: Text(devToolsText), dismissButton: .default(Text("Done"), action: { devTools = false })) }) .alert(isPresented: $allowLocation, content: { Alert(title: Text("Uh Oh"), message: Text("We're not able to find your location, please open settings to enable it."), primaryButton: .destructive(Text("Cancel"), action: { creating = false allowLocation = false }), secondaryButton: .default(Text("Open Settings"), action: { creating = false allowLocation = false if let appSettings = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(appSettings) } })) }) .alert(isPresented: $codeExists, content: { Alert(title: Text("Error"), message: Text("Please try again"), dismissButton: .default(Text("Ok"), action: { codeExists = false creating = false })) }) .alert(isPresented: $updateApp, content: { Alert(title: Text("Warning!"), message: Text("Pickt is not up to date, some things may not work if you are on different versions of Pickt."), primaryButton: .default(Text("Update"), action: { print("update, type = \(Utilities.appType)") if Utilities.appType == .TestFlight { print("opening testflight") if let url = URL(string: "itms-beta://") { UIApplication.shared.open(url) } }else { print("opening app store") if let url = URL(string: "https://apps.apple.com/us/app/pickt/id1584491007") { UIApplication.shared.open(url) } } updateApp = false }), secondaryButton: .destructive(Text("Ignore"), action: { Utilities.ignoreUpdate = true updateApp = false create() })) }) } .padding(.bottom) .onAppear { if Utilities.picktType == .media { picktType = .media }else { picktType = .restaurants } if let dineIn = Utilities.remoteConfig["dineIn"].stringValue { if let takeout = Utilities.remoteConfig["takeout"].stringValue { if let foodTrucks = Utilities.remoteConfig["foodTrucks"].stringValue { print("dineIn = \(dineIn), takeout = \(takeout), foodTrucks = \(foodTrucks)") filterOpt = [dineIn, takeout, foodTrucks] filter = dineIn } } } name = UserDefaults.standard.string(forKey: "deviceName") ?? "" if NetworkMonitor.shared.isConnected { disabledAlert = false }else { disabledAlert = true } if Utilities.latLong { location = "Current Location" }else { location = Utilities.location } } .navigationViewStyle(StackNavigationViewStyle()) } } struct createParty_Previews: PreviewProvider { static var previews: some View { createParty() } }