ソースを参照

Notifications received and shown.

Iñigo Valentin 9 年 前
コミット
359327a507
4 ファイル変更240 行追加0 行削除
  1. 4 0
      app.xcodeproj/project.pbxproj
  2. 12 0
      app/AppDelegate.swift
  3. 223 0
      app/Notifications.swift
  4. 1 0
      app/ViewController.swift

+ 4 - 0
app.xcodeproj/project.pbxproj

@@ -68,6 +68,7 @@
 		93BAD2F61E586310009DF853 /* RowHomeSocial.xib in Resources */ = {isa = PBXBuildFile; fileRef = 93BAD2F51E586310009DF853 /* RowHomeSocial.xib */; };
 		93BAD2F81E586741009DF853 /* RowHomeSocial.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93BAD2F71E586741009DF853 /* RowHomeSocial.swift */; };
 		93BEB6D21E7E878300C68DE5 /* PostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93BEB6D11E7E878300C68DE5 /* PostViewController.swift */; };
+		93D8B0941EF1A64C008BD946 /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93D8B0931EF1A64C008BD946 /* Notifications.swift */; };
 		93D9EA601DE271E700089002 /* Section.xib in Resources */ = {isa = PBXBuildFile; fileRef = 93D9EA5F1DE271E700089002 /* Section.xib */; };
 		93D9EA641DE273FD00089002 /* Section.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93D9EA631DE273FD00089002 /* Section.swift */; };
 		93D9EA681DE342AC00089002 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93D9EA671DE342AC00089002 /* UIView.swift */; };
@@ -155,6 +156,7 @@
 		93BAD2F51E586310009DF853 /* RowHomeSocial.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RowHomeSocial.xib; sourceTree = "<group>"; };
 		93BAD2F71E586741009DF853 /* RowHomeSocial.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowHomeSocial.swift; sourceTree = "<group>"; };
 		93BEB6D11E7E878300C68DE5 /* PostViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostViewController.swift; sourceTree = "<group>"; };
+		93D8B0931EF1A64C008BD946 /* Notifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Notifications.swift; sourceTree = "<group>"; };
 		93D9EA5F1DE271E700089002 /* Section.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = Section.xib; path = ../Section.xib; sourceTree = "<group>"; };
 		93D9EA631DE273FD00089002 /* Section.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Section.swift; sourceTree = "<group>"; };
 		93D9EA671DE342AC00089002 /* UIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = "<group>"; };
@@ -225,6 +227,7 @@
 		93B84B981D9C31AB006C0F67 /* app */ = {
 			isa = PBXGroup;
 			children = (
+				93D8B0931EF1A64C008BD946 /* Notifications.swift */,
 				93B84BA81D9C31AB006C0F67 /* Info.plist */,
 				93B84BA31D9C31AB006C0F67 /* Assets.xcassets */,
 				93B84BA01D9C31AB006C0F67 /* app.xcdatamodeld */,
@@ -439,6 +442,7 @@
 				93E0C5EA1EBDFFB400905811 /* RowPastActivity.swift in Sources */,
 				93BAD2F41E585EE6009DF853 /* RowHomeFutureActivities.swift in Sources */,
 				93E5058F1EEB0DCC00560B4A /* PhotoViewController.swift in Sources */,
+				93D8B0941EF1A64C008BD946 /* Notifications.swift in Sources */,
 				931AA5891E1AFF8C003A2290 /* String.swift in Sources */,
 				935AE18A1EC6138D0055E71F /* SyncController.swift in Sources */,
 				93B84B9C1D9C31AB006C0F67 /* ViewController.swift in Sources */,

+ 12 - 0
app/AppDelegate.swift

@@ -21,6 +21,7 @@
 import UIKit
 import CoreData
 import GoogleMaps
+import UserNotifications
 
 @UIApplicationMain
 class AppDelegate: UIResponder, UIApplicationDelegate {
@@ -39,12 +40,23 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
 		// Background mode.
 		UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
 		
+		if #available(iOS 10.0, *) {
+			let center = UNUserNotificationCenter.current()
+			center.requestAuthorization(options: [.alert, .sound]) { (granted, error) in
+				// Enable or disable features based on authorization.
+			}
+		} else {
+			// Fallback on earlier versions
+		}
+		
+		
 		return true
 	}
 	
 
 	func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
 		NSLog(":BACKGROUND:LOG: Start bg sync...")
+		Notifications()
 		Sync()
 		
 		let when = DispatchTime.now() + 120 // 2 minutes to perform the sync.

+ 223 - 0
app/Notifications.swift

@@ -0,0 +1,223 @@
+// Copyright (C) 2016 Inigo Valentin
+//
+// This file is part of the Gasteizko Margolariak IOS app.
+//
+// The Gasteizko Margolariak IOS app is free software: you can
+// redistribute it and/or modify it under the terms of the
+// GNU General Public License as published by the Free Software
+// Foundation, either version 3 of the License, or (at your
+// option) any later version.
+//
+// The Gasteizko Margolariak IOS app is distributed in the
+// hope that it will be useful, but WITHOUT ANY WARRANTY;
+// without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+// Public License for more details.
+//
+// You should have received a copy of the GNU General Public
+// License along with the Gasteizko Margolariak IOS app.
+// If not, see <http://www.gnu.org/licenses/>.
+
+import Foundation
+import CoreData
+import UIKit
+import UserNotifications
+
+/**
+Class to handle server sync.
+*/
+class Notifications{
+	
+	/**
+	Starts the sync process.
+	Always asynchronously.
+	*/
+	init(){
+		let url = buildUrl();
+		notification(url: url)
+	}
+	
+	
+	/**
+	Builds the URL to perform the sync against.
+	:returns: The URL.
+	*/
+	func buildUrl() -> URL{
+		
+		let url = URL(string: "https://margolariak.com/API/v1/notifications.php")
+		
+		return url!
+	}
+	
+	
+	/**
+	Performs an asynchronous sync.
+	It fetches the info from the server and stores as Core Data
+	:param: url The url to sync.
+	*/
+	func notification(url: URL){
+		
+		NSLog(":NOTIFICATION:LOG: Notification fetch started.")
+		
+		//Synchronously get data
+		let task = URLSession.shared.dataTask(with: url) { data, response, error in
+			guard error == nil else {
+				NSLog(":NOTIFICATION:ERROR: Unknown error.")
+				return
+			}
+			guard let data = data else {
+				NSLog(":NOTIFICATION:ERROR: Data is empty.")
+				return
+			}
+			
+			let strData: String = String(data:data, encoding: String.Encoding.utf8)!
+			NSLog(":NOTIFICATION:LOG: Data received: \(strData)")
+			if strData.length > 0{
+				let dataNotification: [String] = self.getData(data: strData)
+				self.saveNotifications(entries: dataNotification)
+			}
+			
+		}
+		
+		task.resume()
+	}
+	
+	
+	/**
+	Extracts notifications from the raw data received.
+	:param: param Received data in JSON format.
+	:return: Array of strings containing the notifications.
+	*/
+	func getData(data: String) -> [String]{
+		
+		//Separate the entries
+		var entries : [String] = data.components(separatedBy: "},{")
+		
+		//Modify the first and the last one to remove bracers
+		entries[0] = entries[0].subStr(start: 1, end: entries[0].length - 1)
+		entries[entries.count - 1] = entries[entries.count - 1].subStr(start: 0, end: entries[entries.count - 1].length - 2)
+		
+		
+		//Return the array
+		return entries
+	}
+	
+	
+	/**
+	Saves the data in the table.
+	:param: entries Array of strings containing the rows of the table, in JSON format.
+	*/
+	func saveNotifications(entries : [String]){
+		
+		let dateFormatter = DateFormatter()
+		dateFormatter.timeZone = TimeZone.ReferenceType.local
+		
+		//Set up context
+		let appDelegate = UIApplication.shared.delegate as! AppDelegate
+		let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
+		context.persistentStoreCoordinator = appDelegate.persistentStoreCoordinator
+		
+		let entity =  NSEntityDescription.entity(forEntityName: "Notification", in: context)
+		
+		var row: NSManagedObject
+		
+		//Loop new entries
+		for entry in entries{
+			
+			//Get id
+			var str = entry
+			let id: Int = Int(str.subStr(start : str.indexOf(target : "\"id\":")! + 6, end : str.indexOf(target : ",\"")! - 2))!
+			
+			//Get title_es
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			let title_es: String = str.subStr(start : str.indexOf(target : "\"title_es\":")! + 12, end : str.indexOf(target : ",\"")! - 2)
+			
+			//Get title_en
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			let title_en: String = str.subStr(start : str.indexOf(target : "\"title_en\":")! + 12, end : str.indexOf(target : ",\"")! - 2)
+			
+			//Get title_eu
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			let title_eu: String = str.subStr(start : str.indexOf(target : "\"title_eu\":")! + 12, end : str.indexOf(target : ",\"")! - 2)
+			
+			//Get text_es
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			let text_es: String = str.subStr(start : str.indexOf(target : "\"text_es\":")! + 11, end : str.indexOf(target : ",\"")! - 2)
+			
+			//Get text_en
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			let text_en: String = str.subStr(start : str.indexOf(target : "\"text_en\":")! + 11, end : str.indexOf(target : ",\"")! - 2)
+			
+			//Get text_eu
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			let text_eu: String = str.subStr(start : str.indexOf(target : "\"text_eu\":")! + 11, end: str.indexOf(target : ",\"")! - 2)
+			
+			//Get dtime
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
+			let dtime = dateFormatter.date(from : str.subStr(start : str.indexOf(target : "\"dtime\":")! + 9, end : str.indexOf(target : ",\"")! - 2))!
+			
+			//Get GM
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			let gm: Int = Int(str.subStr(start : str.indexOf(target : "\"gm\":")! + 6, end : str.indexOf(target : ",\"")! - 2))!
+			
+			// Not getting seen
+			
+			// Save & show
+			let fetchRequest: NSFetchRequest<Notification> = Notification.fetchRequest()
+			fetchRequest.predicate = NSPredicate(format: "id == %i", id)
+			fetchRequest.fetchLimit = 1
+			do{
+				let searchResults = try context.fetch(fetchRequest)
+				if (searchResults.count == 0){
+					row = NSManagedObject(entity: entity!, insertInto: context)
+					row.setValue(id, forKey: "id")
+					row.setValue(title_es, forKey: "title_es")
+					row.setValue(title_en, forKey: "title_en")
+					row.setValue(title_eu, forKey: "title_eu")
+					row.setValue(text_es, forKey: "text_es")
+					row.setValue(text_en, forKey: "text_en")
+					row.setValue(text_eu, forKey: "text_eu")
+					row.setValue(dtime, forKey: "dtime")
+					row.setValue(gm, forKey: "gm")
+					do {
+						try context.save()
+						
+						if #available(iOS 10.0, *) {
+							let content = UNMutableNotificationContent()
+							
+							// TODO Select language.
+							content.title = title_es
+							content.body = text_es
+							content.sound = UNNotificationSound.default()
+							let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 1, repeats: false)
+							let request = UNNotificationRequest.init(identifier: "Not", content: content, trigger: trigger)
+							
+							// Schedule the notification.
+							let center = UNUserNotificationCenter.current()
+							center.add(request) {
+								(error) in
+								NSLog(":NOTIFICATION:ERROR: Error showing notification \(String(describing: error))")
+							}
+						} else {
+							// Fallback on earlier versions
+						}
+						// TODO Get language
+						
+					}
+					catch let error as NSError  {
+						NSLog(":NOTIFICATION:ERROR: Could not save notification with id \(id): \(error), \(error.userInfo).")
+					}
+					catch {
+						NSLog(":NOTIFICATION:ERROR: Could not save notification with id \(id).")
+					}
+				}
+			}
+			catch {
+				NSLog(":NOTIFICATION:ERROR: Error getting notifications: \(error)")
+			}
+		}
+	}
+	
+	
+}

+ 1 - 0
app/ViewController.swift

@@ -229,6 +229,7 @@ class ViewController: UIViewController, UICollectionViewDataSource, UICollection
 				
 		NSLog(":CONTROLLER:DEBUG: Don't skyp sync")
 		//NSLog(":CONTROLLER:DEBUG: Skyp sync")
+		Notifications()
 		Sync()