Solved Create custom Apple Maps user location button - mkusertrackingmode

I was working on this I didn't find any documentation and so I thought I would create some. After I solved it I was like oh that was easier than I thought.
Anyway, I wanted to create the 3 button states I saw on apple maps. I tried a few setRegion things. After some work realized how apple intended its use. So I thought I would document it here.

func locationButtonWasPressed() {
switch self.coreMapView.userTrackingMode {
case .none:
self.coreMapView.userTrackingMode = .follow
case .follow:
self.coreMapView.userTrackingMode = .followWithHeading
case .followWithHeading:
self.coreMapView.userTrackingMode = .none
#unknown default:
print("userTrackingMode undefined")
}
}
func mapView(_ mapView: MKMapView, didChange mode: MKUserTrackingMode, animated: Bool) {
switch mode {
case .none:
let tintedImage = #imageLiteral(resourceName: "nearby").withRenderingMode(.alwaysTemplate)
locationButton.image = tintedImage
case .follow:
let tintedImage = #imageLiteral(resourceName: "nearby-selected").withRenderingMode(.alwaysTemplate)
locationButton.image = tintedImage
case .followWithHeading:
let tintedImage = #imageLiteral(resourceName: "scout").withRenderingMode(.alwaysTemplate)
locationButton.image = tintedImage
#unknown default:
print("userTrackingMode undefined")
}
}

Related

algolia filter works in console but is not working in actual search results

So my goal is to be able to filter out the Algolia hits not only in the console, but in the actual displayed results as well. So I've been stuck with this issue for a month or so now. I am using the AlgoliaSearchClient API with Swift and the InstantSearch library as well. I've recently figured out how to filter the hits but they only reflect in the console.
Here is the function I use to do that:
extension SchoolTableViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
let settings = Settings()
.set(\.searchableAttributes, to: [.default("eventName")])
.set(\.attributesForFaceting, to: [.filterOnly("schoolID")])
.set(\.attributesToRetrieve, to: ["*"])
searchResultsIndex.setSettings(settings) { (result) in
if case .success( _) = result {
self.getTheSchoolsID { (schoolID) in
if let id = schoolID {
let query = Query().set(\.filters, to: "schoolID:\(id)")
searchResultsIndex.search(query: query) { (result) in
if case .success(let response) = result {
print("\(response.hits)")
}
}
}
}
}
}
}
}
This works perfectly in the console, I can only see events from the current users schoolID. Now when I search, in the actual search bar, I can see events from every user. I was told by an Algolia team member to use this line of code below to have the filter applied in the actual search as well.
getTheSchoolsID { (id) in
if let id = id {
self.searcher.indexQueryState.query.filters = "schoolID:\(id)"
self.searcher.search()
}
}
I've double checked the id value by printing it, it is the exact same value as the one in the function above. I can't figure out why the searchBar doesn't filter out the hits on the screen, but it does it in the console. The Algolia team member said I didn't have to set settings again because it was already set in the other function.
Here is the whole function I use to configure the Algolia search :
func configureAlgoliaSearch() {
getTheSchoolsID { (id) in
if let id = id {
self.searcher.indexQueryState.query.filters = "schoolID:\(id)"
self.searcher.search()
}
}
searchConnector.connect()
navigationController?.navigationBar.prefersLargeTitles = false
navigationItem.setHidesBackButton(true, animated: true)
algoliaSearchController.searchResultsUpdater = self
algoliaSearchController.searchBar.searchTextField.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
algoliaSearchController.obscuresBackgroundDuringPresentation = false
algoliaSearchController.searchBar.placeholder = "Event Name"
navigationItem.searchController = algoliaSearchController
definesPresentationContext = true
}
Any suggestions?
Finally after a month of struggling, I came up with a solution that I should've came up with a long time ago. I decided to create an index for each user. This basically allows me to ditch the need to filter out the records.
All I needed to do was declare a couple variables in the viewController where the SearchController is.
public let client = SearchClient(appID: ApplicationID(rawValue: Keys.algoliaAppID), apiKey: APIKey(rawValue: Keys.algoliaApiKey))
lazy var algoliaSearchController: UISearchController = .init(searchResultsController: hitsViewController)
lazy var searchConnector: SingleIndexSearchConnector<NameOfEvent> = .init(searcher: searcher,searchController: algoliaSearchController, hitsController: hitsViewController)
let hitsViewController: SchoolInstantiatedHitsTableViewController = .init()
let searcher: SingleIndexSearcher = SingleIndexSearcher(appID: ApplicationID(rawValue: Keys.algoliaAppID), apiKey: APIKey(rawValue: Keys.searcherApiKey), indexName: IndexName(rawValue: Auth.auth().currentUser!.uid) )
Along with this function:
extension SchoolTableViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
let searchBar = searchController.searchBar.searchTextField.text
let index2 = client.index(withName: IndexName(rawValue: Auth.auth().currentUser!.uid))
let settings = Settings()
.set(\.searchableAttributes, to: [.default("eventName")])
.set(\.attributesToRetrieve, to: ["*"])
index2.setSettings(settings) { (result) in
if case .success(_) = result {
let query = Query(searchBar)
index2.search(query: query) { (result) in
if case .success(_ ) = result {
print("Success")
}
}
}
}
}
}
And of course configuring the actual searchBar itself:
func configureAlgoliaSearch() {
searchConnector.connect()
searcher.search()
algoliaSearchController.delegate = self
algoliaSearchController.searchResultsUpdater = self
algoliaSearchController.searchBar.searchTextField.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
algoliaSearchController.obscuresBackgroundDuringPresentation = false
algoliaSearchController.searchBar.placeholder = "Event Name"
navigationItem.searchController = algoliaSearchController
definesPresentationContext = true
}
Now with these functions, when I add, delete, or update, records, they all work uniquely to the index of the current user. Algolia's documentation was very confusing at first and asking questions on the forum is kinda like talking to a rock. Anyways, I hope this can help somebody out in the future.

NSUserActivity deleteAllSavedUserActivities not working

My case is utterly simple: I use the next function
private func launchActivity(_ id: String, title: String, invocPhrase: String) {
userActivity = NSUserActivity(activityType: "Open_bank")
userActivity?.title = title
userActivity?.userInfo = ["id": id]
if #available(iOS 12.0, *) {
userActivity?.suggestedInvocationPhrase = invocPhrase
userActivity?.isEligibleForPrediction = true
userActivity?.persistentIdentifier = id
} else {
//Can't actually invoke this block
}
}
to create a certain userActivity, and then add it to Siri, so that it can be invoked by by invocPhrase. Here is the function which does this.
func presentAddOpenBankToSiriVC() {
guard let userActivity = self.userActivity else { return }
if #available(iOS 12.0, *) {
let shortcut = INShortcut(userActivity: userActivity)
let viewController = INUIAddVoiceShortcutViewController(shortcut: shortcut)
viewController.modalPresentationStyle = .formSheet
viewController.delegate = self
present(viewController, animated: true, completion: nil)
} else {
//Can't actually invoke this block
}
}
Later I try to delete it (as well as all other user activities)
NSUserActivity.deleteAllSavedUserActivities {}
And it just does not delete any user activity, contrary to what's written in Apple Documentation
https://developer.apple.com/documentation/sirikit/deleting_donated_shortcuts
Actually, at first, I've tried a method
deleteSavedUserActivities(withPersistentIdentifiers:completionHandler:)
with userActivity's persistentIdentifier, but, obviously, also to no avail.
I've no idea why it refuses to budge but would be grateful to any help or hint

NSTouchBar integration not calling

I am integrating TouchBar support to my App. I used the how to from Rey Wenderlich and implemented everything as follows:
If self.touchBarArraygot filled the makeTouchBar() Method returns the NSTouchBar object. If I print out some tests the identifiers object is filled and works.
What not work is that the makeItemForIdentifier method not get triggered. So the items do not get created and the TouchBar is still empty.
Strange behavior: If I add print(touchBar) and a Breakpoint before returning the NSTouchBar object it works and the TouchBar get presented as it should (also the makeItemForIdentifier function gets triggered). Even if it disappears after some seconds... also strange.
#available(OSX 10.12.2, *)
extension ViewController: NSTouchBarDelegate {
override func makeTouchBar() -> NSTouchBar? {
if(self.touchBarArray.count != 0) {
let touchBar = NSTouchBar()
touchBar.delegate = self
touchBar.customizationIdentifier = NSTouchBarCustomizationIdentifier("com.TaskControl.ViewController.WorkspaceBar")
var identifiers: [NSTouchBarItemIdentifier] = []
for (workspaceId, _) in self.touchBarArray {
identifiers.append(NSTouchBarItemIdentifier("com.TaskControl.ViewController.WorkspaceBar.\(workspaceId)"))
}
touchBar.defaultItemIdentifiers = identifiers
touchBar.customizationAllowedItemIdentifiers = identifiers
return touchBar
}
return nil
}
func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItemIdentifier) -> NSTouchBarItem? {
if(self.touchBarArray.count != 0) {
for (workspaceId, data) in self.touchBarArray {
if(identifier == NSTouchBarItemIdentifier("com.TaskControl.ViewController.WorkspaceBar.\(workspaceId)")) {
let saveItem = NSCustomTouchBarItem(identifier: identifier)
let button = NSButton(title: data["name"] as! String, target: self, action: #selector(self.touchBarPressed))
button.bezelColor = NSColor(red:0.35, green:0.61, blue:0.35, alpha:1.00)
saveItem.view = button
return saveItem
}
}
}
return nil
}
}
self.view.window?.makeFirstResponder(self) in viewDidLoad() did solve the problem.

protocols & viewControllers, passing info using protocols on the same action Func Swift 3 & 4

I have this code to pass info between viewControllers using protocols, I have my models and with the first protocol work perfectly but the second one I have some issues, the data pass nil, or do nothing, already use tabBarController & UINavigationBar... the protocols... I create one in my ViewController(RecordViewController) and have the button & action and one protocol, this is:
protocol RecordViewProtocol {
func newTrackInstrument(item: SampleCarouselsRecord)
func newInstrumentTrackCell(item: SampleTrackCellRecord)
}
extension RecordViewController: RecordViewProtocol {
func newTrackInstrument(item: SampleCarouselsRecord) {
self.sampleCarouselItemsRecord.append(item)
let indexOnPath = NSIndexPath(row: self.sampleCarouselItemsRecord.count - 1, section: 0)
self.instrumentCarousel.insertItems(at: [indexOnPath as IndexPath])
}
func newInstrumentTrackCell(item: SampleTrackCellRecord) {
self.sampleTrackRecord.append(item)
let indexOnPath = NSIndexPath(row: self.sampleTrackRecord.count - 1, section: 0)
self.trackInstrument.insertItems(at: [indexOnPath as IndexPath])
}
}
the other protocol, on another ViewController(MixerViewController):...
protocol MixerViewProtocol {
func newCarouselItem(item: SampleCarouselMixer)
}
extension MixerViewController: MixerViewProtocol {
func newCarouselItem(item: SampleCarouselMixer) {
self.sampleCarouselMixer.append(item)
let indexOnPath = NSIndexPath(row: self.sampleCarouselMixer.count - 1, section: 0)
self.mixerCarouselInstrument.insertItems(at: [indexOnPath as IndexPath])
}
}
so, when wanna go the view and put the info to my models.. I put this code in the action Button to go into the view where is the function to put the info models:
#objc func goToAddView() {
let addTrackViewController = AddNewTrackView()
let addTrackView = UINavigationController(rootViewController: addTrackViewController)
addTrackViewController.recordViewControllerProtocol = self as RecordViewProtocol
present(addTrackView, animated: true, completion: nil)
}
and work good with the first protocol.. but with to the other protocol nothing.. I don't know why or I don't know wath I have to do... look, I have the delegate protocols inside on the AddNweTrackView:
var recordViewControllerProtocol: RecordViewProtocol?
var delegateMixerView: MixerViewProtocol? <- this is I think, put into the action button like the firstone:
here on the same action where the first protocol already is
#objc func goToAddView() {
let addTrackViewController = AddNewTrackView()
let addTrackView = UINavigationController(rootViewController: addTrackViewController)
addTrackViewController.recordViewControllerProtocol = self as RecordViewProtocol
addTrackViewController.delegateMixerView = MixerViewController.self as? MixerViewProtocol
present(addTrackView, animated: true, completion: nil)
}
but return nil... and I try with diferents forms.. I try put this:
let mixerViewController = MixerViewController()
addTrackViewController.delegateMixerView = mixerViewController as? MixerViewProtocol
and try with this but the error Is obvious:
addTrackViewController.delegateMixerView = self as MixerProtocol
and the same... I think, here at this point, it's where Im failing .. someone can help?

How to pass the func () value of the view element to another Controller

First I'll start with what I did, and in the end I will describe the problem, so it will be clearer. In general, after Android Studio, working with view elements in Xcode is still a task. I understand that a good programmer will not write the same code twice, so that each time in different Controller does not describe each time the view elements - so I wrote this function in the main Controller
class func designForButton (button: UIButton){
button.layer.masksToBounds = true
button.layer.cornerRadius = 8
}
Then you can access it in different Controller
class RegisterViewController: UIViewController {
#IBOutlet weak var buttonBack: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
ViewController.designForButton(button: buttonBack)
}
Now, what is not clear. I loaded the framework to work with Toast. And I described its values in the main Controller
func designForToast(message: String){
let style = CSToastStyle.init(defaultStyle: {
}())
_ = style?.backgroundColor = UIColor.gray
_ = style?.titleColor = UIColor.cyan
_ = style?.messageColor = UIColor.darkGray
self.view.makeToast(message, duration: 2, position: self.bottomLayoutGuide, title: "title", image: UIImage (named: "logo.jpg"), style: style ) { (success: Bool) in
}
}
But the matter is that in this case I can address to it exclusively in the same Controller
_=self.designForToast(message: "Its a Toast")
As soon as I want to make func () - like class func () to work in another Controller, Xcode starts to highlight that it's impossible, and due to my small experience, I can not fix it myself.
I suggest that you add a viewController parameter in the method so that it looks like this:
static func showToast(message: String, on viewController: UIViewController){ // I also renamed the method as well
let style = CSToastStyle.init(defaultStyle: {
}())
_ = style?.backgroundColor = UIColor.gray
_ = style?.titleColor = UIColor.cyan
_ = style?.messageColor = UIColor.darkGray
viewController.view.makeToast(message, duration: 2, position: viewController.bottomLayoutGuide, title: "title", image: UIImage (named: "logo.jpg"), style: style ) { (success: Bool) in
}
}
I also suggest that you put these "helper functions" in a designated class, like StyleHelper or something like that.
Then you can use it like this in a View Controller:
StyleHelper.showToast(message: "Hello", on: self)
Or better yet, make this an extension method!
extension UIViewController {
func showMyToast(message: String){
let style = CSToastStyle.init(defaultStyle: {
}())
_ = style?.backgroundColor = UIColor.gray
_ = style?.titleColor = UIColor.cyan
_ = style?.messageColor = UIColor.darkGray
self.view.makeToast(message, duration: 2, position: self.bottomLayoutGuide, title: "title", image: UIImage (named: "logo.jpg"), style: style ) { (success: Bool) in
}
}
}
You can then use it like this in a View Controller:
self.showMyToast(message: "Hello")
Side Note:
For views that conform to UIAppearance protocol, you can access the appearance() property to change its style globally. For example, you can do this in didFinishLaunchingWithOptions:
UIButton.appearance().tintColor = .red
And every UIButton you create will be red.
I think you need to define a protocol , and an extension to UIViewController to provide a default implementation for your method.....if this was the question...:P
protocol ToastProtocol: class {
func showToast(message:String)
}
extension ToastProtocol where Self: UIViewController {
func showToast(message:String){
///yourcode
}
}
After that you can youse your showToast method in any UIViewController