Yeah sure....
import UIKit // Framework for UIKit Framework.
import MessageUI // Framework for E-Mail Sheet.
import LocalAuthentication // Framework for Touch ID.
import WatchConnectivity // Framework for WatchKitConnectivity.
import WatchKit // Framework for WatchKit.
import Foundation // Framework for Foundation.
import AVFoundation
import AVKit
class QNote: UIViewController, UITextViewDelegate, MFMailComposeViewControllerDelegate, WCSessionDelegate, AVSpeechSynthesizerDelegate, FileManagerDelegate
{
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
// Dummy
}
func sessionDidBecomeInactive(_ session: WCSession) {
// Dummy
}
func sessionDidDeactivate(_ session: WCSession) {
// Dummy
}
@IBOutlet var text:UITextView! // Main Variable for TextView.
@IBOutlet var dispCount: UILabel! // Show number of characters in Note.
@IBOutlet var statusBar: UILabel! // Main Variable for Bottom Status Bar.
@IBOutlet var sysVersion: UILabel! // Show app version.
// For Apple Watch:
let session = WCSession.default
// Get device type:
let systemVersion = UIDevice.current.model
// Get app version:
let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")
// Store device responses for easy etrieval later:
var welcomeTitle = "Welcome to QNote"
var appTitle = "QNote"
var emailSignature = "E-Mail sent from QNote for iOS"
var noteDeleted = "Note has been Deleted"
var noteSaved = "Note is now Saved"
var characterCount = 0
var fileMgr: FileManager = FileManager.default
var docsDir: String?
var dataFile: String?
var error: NSError? // Error Variable for Touch ID.
var wcSession : WCSession!
override func viewDidLoad() {
super.viewDidLoad()
self.statusBar.text = "Welcome to QNote."
wcSession = WCSession.default
wcSession.delegate = self
wcSession.activate()
// Apple Watch Notification Center:
NotificationCenter.default.addObserver(self, selector: #selector(messageReceived), name: NSNotification.Name(rawValue: "receiveWatchMessage"), object:nil)
let message = ["message":text.text] as [String: Any]
wcSession.sendMessage(message, replyHandler: nil, errorHandler: nil)
// Set delegate for UITextView:
text.delegate = self
text.isEditable = true
self.view.isAccessibilityElement = true
text.becomeFirstResponder()
text.keyboardType = .default
// Load notes for Apple Watch:
let sn = "group.com.connectingpeoplesoftware.qnote"
let key = "QNoteKey"
let userDefaults = UserDefaults(suiteName: sn)
userDefaults?.set(text.text, forKey: key)
userDefaults?.synchronize()
// Load main text (if it exists):
let fileName = "QNote.dat"
let fileMgr = FileManager.default
var dirPaths = fileMgr.urls(for: .documentDirectory, in: .userDomainMask)
dataFile = dirPaths[0].appendingPathComponent(fileName).path
if fileMgr.fileExists(atPath: dataFile!)
{
let dataBuffer = fileMgr.contents(atPath: dataFile!)
let datastring = NSString(data: dataBuffer!, encoding: String.Encoding.utf8.rawValue)
text.text = datastring! as String
}
}
@objc func messageReceived(info: Notification)
{
let message = info.userInfo!
// Process the below on a background thread:
DispatchQueue.global(qos: .background).async
{
self.text.text = message["msg"] as? String
}
// Go back to the main thread to update the UI:
DispatchQueue.main.async {
}
}
override func viewDidAppear(_ animated: Bool) {
// future code.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func textViewDidBeginEditing(_ textView: UITextView)
{
// For Apple Watch (send to watch):
if self.session.isPaired == true && self.session.isWatchAppInstalled
{
self.session.sendMessage(["msg":self.text.text], replyHandler: nil, errorHandler: { (error) -> Void in
})
}else {
}
}
func textViewDidChange(_ textView: UITextView)
{
// Update Apple Watch:
let message = ["message":text.text] as [String: Any]
wcSession.sendMessage(message, replyHandler: nil, errorHandler: nil)
}
func textViewDidChangeSelection(_ textView: UITextView)
{
// Update Apple Watch:
let message = ["message":text.text] as [String: Any]
wcSession.sendMessage(message, replyHandler: nil, errorHandler: nil)
}
func textViewDidEndEditing(_ textView: UITextView) {
// Resign Keyboard:
textView.resignFirstResponder()
// Save File:
let databuffer = (text.text)!.data(using: String.Encoding.utf8)
fileMgr.createFile(atPath: dataFile!, contents: databuffer, attributes: nil)
sendToAppleWatch()
// For Apple Watch:
if self.session.isPaired == true && self.session.isWatchAppInstalled
{
self.session.sendMessage(["msg":self.text.text!], replyHandler: nil, errorHandler: { (error) -> Void in
print("Watch Communications Error - User not in Watch App when saving Note. - Ignoring Save on Device.")
})
}
}
func sendToAppleWatch()
{
// For Apple Watch:
if self.session.isPaired == true && self.session.isWatchAppInstalled
{
self.session.sendMessage(["msg":self.text.text!], replyHandler: nil, errorHandler: { (error) -> Void in
print("Watch Communications Error - User not in Watch App when saving Note. - Ignoring Save on Device.")
})
}
}
override func viewWillDisappear(_ animated: Bool)
{
// Save File:
let databuffer = (text.text)!.data(using: String.Encoding.utf8)
fileMgr.createFile(atPath: dataFile!, contents: databuffer, attributes: nil)
sendToAppleWatch()
// For Apple Watch:
if self.session.isPaired == true && self.session.isWatchAppInstalled
{
self.session.sendMessage(["msg":self.text.text!], replyHandler: nil, errorHandler: { (error) -> Void in
NSLog("QNote did NOT send to watch when user quit Note.")
})
}else {
NSLog("Note DID send when user quit Note.")
}
}
override func viewWillAppear(_ animated: Bool)
{
// Load text (if it exists):
let fileMgr = FileManager.default
var dirPaths = fileMgr.urls(for: .documentDirectory, in: .userDomainMask)
dataFile = dirPaths[0].appendingPathComponent("QNote.dat").path
if fileMgr.fileExists(atPath: dataFile!)
{
let dataBuffer = fileMgr.contents(atPath: dataFile!)
let datastring = NSString(data: dataBuffer!, encoding: String.Encoding.utf8.rawValue)
text.text = datastring! as String
if (text.text == "")
{
}
}
}
// Save Button:
@IBAction func SaveButton(_ sender: UIBarButtonItem)
{
if text.text == ""
{
let title = "Cannot save a blank note.".localizedCapitalized
let button = "Close".localizedCapitalized
let alert = UIAlertController(title: title, message: nil, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: button, style: UIAlertAction.Style.cancel, handler: { (action:UIAlertAction!) in
}))
self.present(alert, animated: true, completion: nil)
}else {
// Resign Keyboard before saving:
text.resignFirstResponder()
// Save File:
let databuffer = (text.text)!.data(using: String.Encoding.utf8)
fileMgr.createFile(atPath: dataFile!, contents: databuffer, attributes: nil)
let message = ["message":text.text] as [String: Any]
wcSession.sendMessage(message, replyHandler: nil, errorHandler: nil)
statusBar.text = noteSaved
}
}
// Support:
@IBAction func supportButton(_ sender: UIBarButtonItem)
{
let title = "Customer Support".localizedCapitalized
let message = "For customer support, please send an email to:\n\ncpsoftware1@gmail.com\n\nPlease include the name of the below application.\n\nName: QNOTE\n\nVersion: \(appVersion ?? 1.0)".localizedCapitalized
let button = "Close".localizedCapitalized
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: button, style: UIAlertAction.Style.default, handler: { (action:UIAlertAction!) in
}))
self.present(alert, animated: true, completion: nil)
}
// Speak Text:
@IBAction func speakText(_ sender: UIBarButtonItem)
{
text.resignFirstResponder()
guard let voice = AVSpeechSynthesisVoice(identifier: AVSpeechSynthesisVoiceIdentifierAlex) else {
statusBar.text = "Text Reading is not available.".localizedCapitalized
print ("Text Reading is not available")
let title = "Text Reading isn't Available.".localizedCapitalized
let message = "In order for QNote to read the text, you must install a voice file called Alex by going to:\n\nSETTINGS > GENERAL > ACCESSIBILITY > VOICEOVER > SPEECH > VOICE\n\nand select ALEX.\n\nYou may need to download the voice file if it's not available on the device (about 10-20 mins. via WiFi.)"
let button = "Close".localizedCapitalized
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: button, style: UIAlertAction.Style.default, handler: { (action:UIAlertAction!) in
}))
self.present(alert, animated: true, completion: nil)
return
}
let toSay = AVSpeechUtterance(string: text.text)
toSay.voice = voice
let alex = AVSpeechSynthesizer()
// alex.delegate = self as? AVSpeechSynthesizerDelegate
alex.speak(toSay)
}
// Trash:
@IBAction func trashCan(_ sender: UIBarButtonItem)
{
let title = "Delete this Note.".localizedCapitalized
let msg = "Are you sure?\n(This can't be undone)".localizedCapitalized
let yesButton = "YES".localizedCapitalized
let noButton = "NO".localizedCapitalized
let alertController = UIAlertController(title: title, message: msg, preferredStyle: .alert)
let yes = UIAlertAction(title: yesButton, style: .default) { (action:UIAlertAction) in
// Animate page flip with delete:
let transisitionOptions: UIView.AnimationOptions = [.transitionCurlUp]
UIView.transition(with: self.view, duration: 1.0, options: transisitionOptions, animations: {
self.view.isHidden = false
})
// Delete UITextView:
self.text.text = nil // Delete entire UITextView.
// Save File:
let databuffer = (self.text.text)!.data(using: String.Encoding.utf8)
self.fileMgr.createFile(atPath: self.dataFile!, contents: databuffer, attributes: nil)
self.statusBar.text = "Note has been deleted.".localizedCapitalized
// Delete note on Apple Watch:
let message = ["message":self.text.text] as [String: Any]
self.wcSession.sendMessage(message, replyHandler: nil, errorHandler: nil)
}
let no = UIAlertAction(title: noButton, style: .default) { (action:UIAlertAction) in
}
alertController.addAction(yes)
alertController.addAction(no)
self.present(alertController, animated: true, completion: nil)
}
@IBAction func helpButton(_ sender: UIBarButtonItem)
{
let title = "Help".localizedCapitalized
let message = "SAVE: Save Note\nREAD: Read Note\nLOCK: Lock Note\n(?): This Window\nCOMPOSE: E-Mail Note\nTRASH: Delete Note\nSHARE: Share Note\n\nWhen pressing the Save button, the device will save your note(s) to the device AND your watch (if available)".localizedCapitalized
let button = "Close".localizedCapitalized
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: button, style: UIAlertAction.Style.default, handler: { (action:UIAlertAction!) in
}))
self.present(alert, animated: true, completion: nil)
}
@IBAction func emailMessage(_ sender: UIBarButtonItem)
{
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.present(mailComposeViewController, animated: true, completion: nil)
} else {
self.showSendMailErrorAlert()
}
}
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self
mailComposerVC.setToRecipients([""])
mailComposerVC.setSubject("")
mailComposerVC.setMessageBody(text.text, isHTML: false)
return mailComposerVC
}
func showSendMailErrorAlert()
{
// No Need for Code here.
}
// MARK: MFMailComposeViewControllerDelegate Method
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
controller.dismiss(animated: true, completion: nil)
statusBar.text = "E-Mail Sent from your " + systemVersion
}
@IBAction func sharingButton(_ sender: Any)
{
let activityViewController = UIActivityViewController(activityItems: [text.text], applicationActivities: nil)
if let popoverPresentationController = activityViewController.popoverPresentationController {
popoverPresentationController.barButtonItem = (sender as! UIBarButtonItem)
}
present(activityViewController, animated: true, completion: nil)
}
// Background Processes:
func applicationWillEnterBackground(_ application: UIApplication)
{
// Save File:
let databuffer = (text.text)!.data(using: String.Encoding.utf8)
fileMgr.createFile(atPath: dataFile!, contents: databuffer, attributes: nil)
// Update Apple Watch:
let message = ["message":text.text] as [String: Any]
wcSession.sendMessage(message, replyHandler: nil, errorHandler: nil)
}
func applicationDidEnterBackround(_ application: UIApplication)
{
// Save File:
let databuffer = (text.text)!.data(using: String.Encoding.utf8)
fileMgr.createFile(atPath: dataFile!, contents: databuffer, attributes: nil)
// Update Apple Watch:
let message = ["message":text.text] as [String: Any]
wcSession.sendMessage(message, replyHandler: nil, errorHandler: nil)
}
func applictionDidEnterForeground(_ application: UIApplication)
{
// Update Apple Watch:
let message = ["message":text.text] as [String: Any]
wcSession.sendMessage(message, replyHandler: nil, errorHandler: nil)
}
func applicationWillTerminate(_ application: UIApplication)
{
// Save File:
let databuffer = (text.text)!.data(using: String.Encoding.utf8)
fileMgr.createFile(atPath: dataFile!, contents: databuffer, attributes: nil)
// Update Apple Watch:
let message = ["message":text.text] as [String: Any]
wcSession.sendMessage(message, replyHandler: nil, errorHandler: nil)
}
func applicationDidTerminate(_ application: UIApplication)
{
text.text = nil
}
func applicationWillResignActive(_ application: UIApplication)
{
// Save File:
let databuffer = (text.text)!.data(using: String.Encoding.utf8)
fileMgr.createFile(atPath: dataFile!, contents: databuffer, attributes: nil)
// Update Apple Watch:
let message = ["message":text.text] as [String: Any]
wcSession.sendMessage(message, replyHandler: nil, errorHandler: nil)
}
func applicationDidResignActive(_ application: UIApplication)
{
// Update Apple Watch:
let message = ["message":text.text] as [String: Any]
wcSession.sendMessage(message, replyHandler: nil, errorHandler: nil)
}
}