validate clipboard when applicationWillEnterForeground happens (swift) - ios

I am building an app that will allow to copy images to an image view from a safari search and the when I reopen the app and if I am in a specific view (the picture below) I need to validate if the clipboard is not empty I want to enable a paste button.
I would like to know how can I do this in swift.
Thanks again in advance.

You can check for images on the clipboard like this:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if UIPasteboard.generalPasteboard().image != nil {
pasteButton.enabled = true
}
else {
pasteButton.enabled = false
}
}
If you want to use the event, you can do something like this:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self,
selector: Selector("updatePasteButton"),
name: UIApplicationWillEnterForegroundNotification,
object: nil)
}
func updatePasteButton() {
if UIPasteboard.generalPasteboard().image != nil {
pasteButton.enabled = true
}
else {
pasteButton.enabled = false
}
}
updatePasteButton() will get called every time the event happens.

Related

Create new event in CalendarKit

In my app, I'm trying to add ability to create a new event with CalendarKit when I press an empty space, but I can't find how to do that.
I know it's possible because you can do it in the demo app:
I've tried adding this to my app's code:
override func create(event: EventDescriptor, animated: Bool = false) {
self.events.append(event) // self.events is my events data source
}
But it didn't worked, in fact, it doesn't even get called when I long press an empty space.
I also tried to look in the source code, but I found nothing. How can I do that? thanks in advance
override func dayView(dayView: DayView, didLongPressTimelineAt date: Date) {
let newEvent = Event()
newEvent.startDate = date
newEvent.endDate = date.addingTimeInterval(3600)
// Customize your event...
newEvent.text = randomName() // A function that generates a new random name that haven't been used before.
self.create(event: newEvent)
}
override func create(event: EventDescriptor, animated: Bool = false) {
super.create(event: event, animated: animated)
self.events.append(event)
}
override func dayView(dayView: DayView, didUpdate event: EventDescriptor) {
for (index, eventFromList) in events.enumerated() {
if eventFromList.text == event.text {
events[index] = event
}
}
self.endEventEditing()
self.reloadData()
}
Please make sure that every Event have it's own unique name, otherwise it won't work

How can I create an Instance of NSManagedObject in a NotesApp without a Button - Apple's NoteApp Style?

I started learning programming and I decided to try out my first Note Taking App.
My Goal is to create an App similar to the iPhone's NoteApp. Therefore, I wanted the note's title be set when the User writes in the TextView as the first line. Therefore, I created a NoteViewController, which contains a TextView and a NoteIndexViewController, which is a TableViewController, both embedded in a NavigationController.
I'm also using Core Data to store the data.
The problem is that I don't know how I can commit those changes to the DataBase without using a button. I know how to create an instance of the NSManagedObject - in NoteIndexViewController to create new notes in the TableView using a Button:
#IBAction func addNotePressed(_ sender: UIBarButtonItem) {
let newNoteIndex = NoteIndex(context: self.context)
newNoteIndex.name = "Temporal Name"
notesArray.append(newNoteIndex)
saveNoteIndex()
performSegue(withIdentifier: K.segueToNote, sender: self)
}
But I'm completely lost if I want to commit the changes without a "Save Button" to create the instance and also committing changes. This is the code I got so far. Notice that I did not set any Note() object.
class NoteViewController: UIViewController {
var noteArray = [Note]()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var selectedNote: NoteIndex? {
didSet {
loadData()
}
}
var firstLine: String?
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
loadData()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
if !textView.text.isEmpty {
if let newLine = textView.text.firstIndex(of: "\n") {
let firstLetter = textView.text.startIndex
let lineBrake = textView.text.index(before: newLine)
let lettersTillPosition = textView.text.distance(from: firstLetter, to: lineBrake)
firstLine = (textView.text as NSString).substring(to: lettersTillPosition)
} else {
if textView.text.count >= 30{
firstLine = (textView.text as NSString).substring(to: 30)
} else {
firstLine = (textView.text as NSString).substring(to: textView.text.count)
}
}
selectedNote!.name = firstLine
saveCurrentNote()
}
}
//MARK: - Data Manipulation Methods
func saveCurrentNote() {
do {
try context.save()
} catch {
print("Error saving cateogry \(error)")
}
}
func loadData(with request: NSFetchRequest<Note> = Note.fetchRequest()) {
// goToIndex is the relationship between the IndexNote entity and Note. And when Back button is pressed the code tend also to break in this part.
request.predicate = NSPredicate(format: "goToIndex.name MATCHES %#", selectedNote!.name!)
do {
noteArray = try context.fetch(request)
} catch {
print("This is a load error: \(error)")
}
}
}
extension NoteViewController: UITextViewDelegate {
func textViewDidChange(_ textView: UITextView) {
saveCurrentNote()
}
}
Here is a possible solution for your question. You can use Notification Center to monitor if the user is interrupted and if so you can do a quick save.
Place these in the scene delegate
func sceneWillResignActive(_ scene: UIScene) {
let notificationName = NSNotification.Name(ReuseIdentifier.pause)
NotificationCenter.default.post(name: notificationName , object: nil)
}
func sceneDidDisconnect(_ scene: UIScene) {
let notificationName = NSNotification.Name(ReuseIdentifier.quit)
NotificationCenter.default.post(name: notificationName, object: nil)
}
Place something like this where the user data is being saved.
/// Monitors application state for major changes.
/// - Pause Observer: Adds observer that notifies application if application is no longer active (enters foreground).
/// - Quit Observer: Adds observer that notifies application if terminated.
private func checkForPauseOrQuit(){
NotificationCenter.default.addObserver(self,
selector: #selector(autoSave),
name: NSNotification.Name(ReuseIdentifier.pause),
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(autoSave),
name: NSNotification.Name(ReuseIdentifier.quit),
object: nil)
}
And then for your selector method you create your NSManagedObject and capture whatever values the user may have started typing.
On startup you do the reverse, and make sure to erase the values. This should function only as a temporary holding container not your main entity. Check out my note application for reference:
https://github.com/victis23/AwesomeNote/tree/WorkingBranch/AwesomeNote

Switch Save user preference

I am trying to send a tag with OneSignal when the switch is turned on, and send request to delete the tag when it is turned off again.
#IBAction func tagGeneral(_ sender: UISwitch) {
if (sender.isOn == true) {
OneSignal.sendTag("General", value: "value")
print("sendtag")
}
else {
OneSignal.deleteTag("General")
print("deletetag")
}
}
This is the code i use for it. Seems to be working but when the user goes to another page the switch is automatically turned off...
How can i fix this?
Regarding #Ryan's comment, Here's an answer:
First. there are many ways to save the user preference, i'll be doing it with UserDefaults() | Edit your button action code:
#IBAction func tagGeneral(_ sender: UISwitch) {
let userdef = UserDefaults.standard
if (sender.isOn == true) {
OneSignal.sendTag("General", value: "value")
print("sendtag")
// user made the choice
userdef.set(true, forKey: "sw_set")
} else {
OneSignal.deleteTag("General")
print("deletetag")
// reset
userdef.set(false, forKey: "sw_set")
}
}
Normally this wouldn't work without this little function, make sure you call this function in your viewDidAppear():
private func init_switch() {
// Thanks #Vadian for the tip
let userdef = UserDefaults.standard
self.yourSwitch.isOn = userdef.bool(forKey: "sw_set")
}
Call it in viewDidAppear():
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
self.init_switch()
}
And let me know if it helped.

Why canPerformAction get called again when action of menuItem is called?

Below is my code, I found when click menu "pasteAndGo", two log strings are printed: 1. paste and go show 2.paste and go clicked. My requirement is when the menu is shown, log "paste and go show" is shown. When it is clicked, log "paste and go clicked" is shown.
class MyTextField: UITextField {
private func Init() {
let menuController: UIMenuController = UIMenuController.shared
menuController.isMenuVisible = true
let pasteAndGoMenuItem: UIMenuItem = UIMenuItem(title: "pasteAndGo", action: #selector(pasteAndGo(sender:)))
let myMenuItems: NSArray = [pasteAndGoMenuItem]
menuController.menuItems = myMenuItems as? [UIMenuItem]
}
#objc private func pasteAndGo(sender: UIMenuItem) {
Print("paste and go clicked")
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
let pasteboard = UIPasteboard.general
if action == #selector(pasteAndGo) {
if pasteboard.url != nil {
Print("paste and go show")
return true
} else {
return false
}
}
return super.canPerformAction(action, withSender: sender)
}
}
Your code works as implemented:
In the instant you press your pasteAndGo menu item, the UIKit framework calls canPerformAction to ask whether it is allowed to execute the action or not. Here, you print "paste and go show"
Since you return true, your action pasteAndGo(sender:) is executed and prints "paste and go clicked"
To react on the menu item being shown, you'll have to register to the notification center with the UIMenuController.willShowMenuNotification, like this:
// create a property
var token: NSObjectProtocol?
// then add observer
self.token = NotificationCenter.default.addObserver(forName: UIMenuController.willShowMenuNotification, object: nil, queue: .main)
{ _ in
print ("paste and go show")
}
and don't forget to unsubscribe (NotificationCenter.default.removeObserver) once your viewcontroller gets dismissed.
if let t = self.token {
NotificationCenter.default.removeObserver(t)
}
Update
You could also do so (without properties) in Init
// in Init
var token = NotificationCenter.default.addObserver(forName: UIMenuController.willShowMenuNotification, object: nil, queue: .main)
{ _ in
print ("paste and go show")
NotificationCenter.default.removeObserver(token)
}

viewWillAppear is not being called after clicking the home button

i have this view controller
class ViewController: UIViewController {
override func viewWillAppear(animated: Bool) {
let user = NSUserDefaults()
let mobileNumber = user.valueForKey("mobileNumber") as? String
if let mobileNumber = mobileNumber {
print("mobile number = \(mobileNumber)")
}else {
print("no mobile number")
}
}
#IBAction func makePhoneCall(sender: UIButton) {
if let phoneCall = phoneCall {
let user = NSUserDefaults()
user.setValue(phoneCall, forKey: "mobileNumber")
when the user clicks on a button, i save the mobileNumber in nsuserdefault.
then i click the button, then i open the app again, but problem is that when i open the app agian, i don't bet any message from the viewWillAppear even though i am printing in the if and in the else part.
tylersimko is correct that viewWillAppear(_:) is not called when the application enters the foreground and that event is instead captured by "application will enter background".
That said, you don't need to observe this from the app delegate but could instead use the UIApplicationWillEnterForegroundNotification notification:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "applicationDidEnterForeground", name: UIApplicationWillEnterForegroundNotification, object: nil)
}
func applicationDidEnterForeground() {
// Update variable here.
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
The above code:
When your view loads, your view controller registers to have the function applicationDidEnterForeground() called whenever the application enters the foreground.
The function applicationDidEnterForeground() does whatever needs to be done.
The view controller unregisters from all notifications when it deallocates to avoid a zombie reference in iOS versions before 9.0.
Given that you are working with NSUserDefaults, you could instead consider observing NSUserDefaultsDidChangeNotification.
In AppDelegate.swift, make your change in applicationWillEnterForeground:
func applicationWillEnterForeground(application: UIApplication) {
// do something
}
Alternatively, if you want to keep your changes in the ViewController, you could set up a function and call it like this:
func applicationWillEnterForeground(application: UIApplication) {
ViewController.refreshView()
}

Resources