ソースを参照

Merge branch 'Gallery' into BaseProject

Iñigo Valentin 9 年 前
コミット
89b6903483

+ 43 - 19
app.xcodeproj/project.pbxproj

@@ -18,8 +18,14 @@
 		93294FF81E336FA000FDAF50 /* Entry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93294FF71E336FA000FDAF50 /* Entry.swift */; };
 		93294FFA1E337D0D00FDAF50 /* RowHomePastActivities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93294FF91E337D0D00FDAF50 /* RowHomePastActivities.swift */; };
 		935892D01E493C2300E1CD5F /* UIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 935892CF1E493C2300E1CD5F /* UIImageView.swift */; };
+		935D6E2D1E8678B700CED3A1 /* GalleryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 935D6E2C1E8678B700CED3A1 /* GalleryView.xib */; };
+		935D6E2F1E86792000CED3A1 /* GalleryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 935D6E2E1E86792000CED3A1 /* GalleryView.swift */; };
+		935D6E311E867C5E00CED3A1 /* RowGallery.xib in Resources */ = {isa = PBXBuildFile; fileRef = 935D6E301E867C5E00CED3A1 /* RowGallery.xib */; };
+		935D6E331E867C7E00CED3A1 /* RowGallery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 935D6E321E867C7E00CED3A1 /* RowGallery.swift */; };
 		937EA02D1E5B8B5300D0893A /* UIApplcation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 937EA02C1E5B8B5300D0893A /* UIApplcation.swift */; };
 		93B408031D9ED44C000FBC99 /* MenuCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93B408021D9ED44C000FBC99 /* MenuCollectionViewCell.swift */; };
+		93B5C01A1E872B4B0069BFF8 /* RowHomeGallery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93B5C0191E872B4B0069BFF8 /* RowHomeGallery.swift */; };
+		93B5C01C1E872B600069BFF8 /* RowHomeGallery.xib in Resources */ = {isa = PBXBuildFile; fileRef = 93B5C01B1E872B600069BFF8 /* RowHomeGallery.xib */; };
 		93B84B9A1D9C31AB006C0F67 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93B84B991D9C31AB006C0F67 /* AppDelegate.swift */; };
 		93B84B9C1D9C31AB006C0F67 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93B84B9B1D9C31AB006C0F67 /* ViewController.swift */; };
 		93B84B9F1D9C31AB006C0F67 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 93B84B9D1D9C31AB006C0F67 /* Main.storyboard */; };
@@ -54,8 +60,14 @@
 		93294FF71E336FA000FDAF50 /* Entry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Entry.swift; sourceTree = "<group>"; };
 		93294FF91E337D0D00FDAF50 /* RowHomePastActivities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowHomePastActivities.swift; sourceTree = "<group>"; };
 		935892CF1E493C2300E1CD5F /* UIImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageView.swift; sourceTree = "<group>"; };
+		935D6E2C1E8678B700CED3A1 /* GalleryView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = GalleryView.xib; sourceTree = "<group>"; };
+		935D6E2E1E86792000CED3A1 /* GalleryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GalleryView.swift; sourceTree = "<group>"; };
+		935D6E301E867C5E00CED3A1 /* RowGallery.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RowGallery.xib; sourceTree = "<group>"; };
+		935D6E321E867C7E00CED3A1 /* RowGallery.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowGallery.swift; sourceTree = "<group>"; };
 		937EA02C1E5B8B5300D0893A /* UIApplcation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIApplcation.swift; sourceTree = "<group>"; };
 		93B408021D9ED44C000FBC99 /* MenuCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MenuCollectionViewCell.swift; path = ../MenuCollectionViewCell.swift; sourceTree = "<group>"; };
+		93B5C0191E872B4B0069BFF8 /* RowHomeGallery.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowHomeGallery.swift; sourceTree = "<group>"; };
+		93B5C01B1E872B600069BFF8 /* RowHomeGallery.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RowHomeGallery.xib; sourceTree = "<group>"; };
 		93B84B961D9C31AB006C0F67 /* app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = app.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		93B84B991D9C31AB006C0F67 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
 		93B84B9B1D9C31AB006C0F67 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
@@ -113,38 +125,44 @@
 		93B84B981D9C31AB006C0F67 /* app */ = {
 			isa = PBXGroup;
 			children = (
-				93B408021D9ED44C000FBC99 /* MenuCollectionViewCell.swift */,
-				93B84B9B1D9C31AB006C0F67 /* ViewController.swift */,
-				93B84B991D9C31AB006C0F67 /* AppDelegate.swift */,
-				93B84B9D1D9C31AB006C0F67 /* Main.storyboard */,
-				93B84BA31D9C31AB006C0F67 /* Assets.xcassets */,
-				93B84BA51D9C31AB006C0F67 /* LaunchScreen.storyboard */,
 				93B84BA81D9C31AB006C0F67 /* Info.plist */,
+				93B84BA31D9C31AB006C0F67 /* Assets.xcassets */,
 				93B84BA01D9C31AB006C0F67 /* app.xcdatamodeld */,
+				93B84BA51D9C31AB006C0F67 /* LaunchScreen.storyboard */,
+				93B84B991D9C31AB006C0F67 /* AppDelegate.swift */,
+				93B84B9D1D9C31AB006C0F67 /* Main.storyboard */,
+				93B84B9B1D9C31AB006C0F67 /* ViewController.swift */,
+				93B408021D9ED44C000FBC99 /* MenuCollectionViewCell.swift */,
+				93BEB6D11E7E878300C68DE5 /* PostViewController.swift */,
 				93D9EA5F1DE271E700089002 /* Section.xib */,
 				93D9EA631DE273FD00089002 /* Section.swift */,
 				931AA5AD1E218D0D003A2290 /* Entry.xib */,
 				93294FF71E336FA000FDAF50 /* Entry.swift */,
-				93D9EA691DE3491100089002 /* HomeView.swift */,
 				93D9EA6B1DE3498500089002 /* HomeView.xib */,
-				93D9EA751DE3ACBB00089002 /* Sync.swift */,
-				931AA5AF1E219006003A2290 /* RowHomePastActivities.xib */,
-				93294FF91E337D0D00FDAF50 /* RowHomePastActivities.swift */,
+				93D9EA691DE3491100089002 /* HomeView.swift */,
+				93BAD2F11E585E88009DF853 /* RowHomeFutureActivities.xib */,
+				93BAD2F31E585EE6009DF853 /* RowHomeFutureActivities.swift */,
 				93BAD2ED1E585578009DF853 /* RowHomeBlog.xib */,
 				93BAD2EF1E585662009DF853 /* RowHomeBlog.swift */,
-				931AA5881E1AFF8C003A2290 /* String.swift */,
-				93D9EA671DE342AC00089002 /* UIView.swift */,
-				935892CF1E493C2300E1CD5F /* UIImageView.swift */,
+				931AA5AF1E219006003A2290 /* RowHomePastActivities.xib */,
+				93294FF91E337D0D00FDAF50 /* RowHomePastActivities.swift */,
+				93BAD2F51E586310009DF853 /* RowHomeSocial.xib */,
+				93BAD2F71E586741009DF853 /* RowHomeSocial.swift */,
 				93075C691E59CAB000396389 /* BlogView.xib */,
 				93075C6B1E59CB6B00396389 /* BlogView.swift */,
-				93075C6F1E59D04A00396389 /* RowBlog.swift */,
 				93075C711E59D06900396389 /* RowBlog.xib */,
-				93BAD2F11E585E88009DF853 /* RowHomeFutureActivities.xib */,
-				93BAD2F31E585EE6009DF853 /* RowHomeFutureActivities.swift */,
-				93BAD2F51E586310009DF853 /* RowHomeSocial.xib */,
-				93BAD2F71E586741009DF853 /* RowHomeSocial.swift */,
-				93BEB6D11E7E878300C68DE5 /* PostViewController.swift */,
+				93075C6F1E59D04A00396389 /* RowBlog.swift */,
+				93D9EA751DE3ACBB00089002 /* Sync.swift */,
+				931AA5881E1AFF8C003A2290 /* String.swift */,
+				93D9EA671DE342AC00089002 /* UIView.swift */,
+				935892CF1E493C2300E1CD5F /* UIImageView.swift */,
 				937EA02C1E5B8B5300D0893A /* UIApplcation.swift */,
+				935D6E2C1E8678B700CED3A1 /* GalleryView.xib */,
+				935D6E2E1E86792000CED3A1 /* GalleryView.swift */,
+				935D6E301E867C5E00CED3A1 /* RowGallery.xib */,
+				935D6E321E867C7E00CED3A1 /* RowGallery.swift */,
+				93B5C0191E872B4B0069BFF8 /* RowHomeGallery.swift */,
+				93B5C01B1E872B600069BFF8 /* RowHomeGallery.xib */,
 			);
 			path = app;
 			sourceTree = "<group>";
@@ -227,9 +245,12 @@
 				93D9EA601DE271E700089002 /* Section.xib in Resources */,
 				93075C6A1E59CAB000396389 /* BlogView.xib in Resources */,
 				93B84BA41D9C31AB006C0F67 /* Assets.xcassets in Resources */,
+				935D6E2D1E8678B700CED3A1 /* GalleryView.xib in Resources */,
 				93BAD2EE1E585578009DF853 /* RowHomeBlog.xib in Resources */,
+				935D6E311E867C5E00CED3A1 /* RowGallery.xib in Resources */,
 				93B84B9F1D9C31AB006C0F67 /* Main.storyboard in Resources */,
 				93D9EA6C1DE3498500089002 /* HomeView.xib in Resources */,
+				93B5C01C1E872B600069BFF8 /* RowHomeGallery.xib in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -248,6 +269,7 @@
 				93BAD2F81E586741009DF853 /* RowHomeSocial.swift in Sources */,
 				93BAD2F01E585662009DF853 /* RowHomeBlog.swift in Sources */,
 				93294FFA1E337D0D00FDAF50 /* RowHomePastActivities.swift in Sources */,
+				93B5C01A1E872B4B0069BFF8 /* RowHomeGallery.swift in Sources */,
 				935892D01E493C2300E1CD5F /* UIImageView.swift in Sources */,
 				93D9EA761DE3ACBB00089002 /* Sync.swift in Sources */,
 				93BAD2F41E585EE6009DF853 /* RowHomeFutureActivities.swift in Sources */,
@@ -256,9 +278,11 @@
 				93075C6C1E59CB6B00396389 /* BlogView.swift in Sources */,
 				93B84B9A1D9C31AB006C0F67 /* AppDelegate.swift in Sources */,
 				93B84BA21D9C31AB006C0F67 /* app.xcdatamodeld in Sources */,
+				935D6E331E867C7E00CED3A1 /* RowGallery.swift in Sources */,
 				93D9EA681DE342AC00089002 /* UIView.swift in Sources */,
 				93075C701E59D04A00396389 /* RowBlog.swift in Sources */,
 				93B408031D9ED44C000FBC99 /* MenuCollectionViewCell.swift in Sources */,
+				935D6E2F1E86792000CED3A1 /* GalleryView.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 2 - 2
app/Base.lproj/Main.storyboard

@@ -290,10 +290,10 @@
                         <viewControllerLayoutGuide type="top" id="yvh-VS-RXe"/>
                         <viewControllerLayoutGuide type="bottom" id="tOB-l0-rCU"/>
                     </layoutGuides>
-                    <view key="view" contentMode="scaleToFill" id="pPe-Xd-teA">
+                    <view key="view" contentMode="scaleToFill" id="pPe-Xd-teA" customClass="GalleryView" customModule="app" customModuleProvider="target">
                         <rect key="frame" x="0.0" y="0.0" width="320" height="458"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        <color key="backgroundColor" red="0.70980392160000005" green="0.82745098039999998" blue="0.8980392157" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                     </view>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="2vc-bF-Qwf" userLabel="First Responder" sceneMemberID="firstResponder"/>

+ 181 - 0
app/GalleryView.swift

@@ -0,0 +1,181 @@
+// 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
+/**
+Class to handle the home view.
+*/
+class GalleryView: UIView {
+	
+	@IBOutlet var container: UIView!
+	@IBOutlet weak var scrollView: UIScrollView!
+	@IBOutlet weak var section: Section!
+	var delegate: AppDelegate? = nil
+	
+	override init(frame: CGRect){
+		super.init(frame: frame)
+	}
+	
+	/**
+	Run when the view is started.
+	*/
+	required init?(coder aDecoder: NSCoder) {
+		
+		super.init(coder: aDecoder)
+		
+		print("GALLERY:DEBUG: init.")
+		
+		//Load the contents of the HomeView.xib file.
+		Bundle.main.loadNibNamed("GalleryView", owner: self, options: nil)
+		self.addSubview(container)
+		container.frame = self.bounds
+		section.setTitle(text: "Gallery")
+		let parent = section.getContentStack()
+		
+		// Get viewController from StoryBoard
+		let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
+		let controller = storyboard.instantiateViewController(withIdentifier: "GMViewController") as! ViewController
+		
+		// Show albums
+		let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
+		let appDelegate = UIApplication.shared.delegate as! AppDelegate
+		self.delegate = appDelegate
+		let lang : String = getLanguage()
+		context.persistentStoreCoordinator = appDelegate.persistentStoreCoordinator
+		let fetchRequest: NSFetchRequest<Album> = Album.fetchRequest()
+		let sortDescriptor = NSSortDescriptor(key: "time", ascending: false)
+		let sortDescriptors = [sortDescriptor]
+		fetchRequest.sortDescriptors = sortDescriptors
+		
+		do {
+			//Get the results
+			let searchResults = try context.fetch(fetchRequest)
+
+			var row : RowGallery
+			var count = 0
+			var id: Int
+			var title: String
+			for r in searchResults as [NSManagedObject] {
+				count = count + 1
+				
+				//Create a new row
+				row = RowGallery.init(s: "rowGallery\(count)", i: count)
+				id = r.value(forKey: "id")! as! Int
+				
+				title = r.value(forKey: "title_\(lang)")! as! String
+				row.setTitle(text: title)
+				
+				// Get 4 random images from the album
+				let imgFetchRequest: NSFetchRequest<Photo_album> = Photo_album.fetchRequest()
+				// TODO Order random
+				//let imgSortDescriptor = NSSortDescriptor(key: "time", ascending: true)
+				//let imgSortDescriptors = [imgSortDescriptor]
+				//simgFetchRequest.sortDescriptors = imgSortDescriptors
+				imgFetchRequest.predicate = NSPredicate(format: "album == %i", id)
+				imgFetchRequest.fetchLimit = 4
+				do{
+					let imgSearchResults = try context.fetch(imgFetchRequest)
+					
+					// Loop images
+					var imageIdx = 0
+					for imgR in imgSearchResults as [NSManagedObject]{
+						
+						let imageId = imgR.value(forKey: "photo")! as! Int
+						
+						// For each image, I need a new query to fetch from photo entity.
+						let singleImgFetchRequest: NSFetchRequest<Photo> = Photo.fetchRequest()
+						singleImgFetchRequest.predicate = NSPredicate(format: "id == %i", imageId)
+						singleImgFetchRequest.fetchLimit = 4
+						do{
+							let singleImgSearchResults = try context.fetch(singleImgFetchRequest)
+							
+							// Loop image
+							for sImgR in singleImgSearchResults as [NSManagedObject]{
+						
+								let image = sImgR.value(forKey: "file")! as! String
+								row.setImage(idx: imageIdx, filename: image)
+							}
+							imageIdx = imageIdx + 1
+						}
+						catch {
+							print("GALLERY:ERROR: Error getting image from photo entity: \(error)")
+						}
+					}
+				} catch {
+					print("GALLERY:ERROR: Error getting image for post \(id): \(error)")
+				}
+				
+				parent.addArrangedSubview(row)
+				row.setNeedsLayout()
+				row.layoutIfNeeded()
+				
+				// TODO: Do this on the row didLoad method
+				// Set tap recognizer
+				//let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(openPost(_:)))
+				//row.isUserInteractionEnabled = true
+				//row.addGestureRecognizer(tapRecognizer)
+				
+				
+				
+			}
+		} catch {
+			print("GALLERY:ERROR: Error with request: \(error)")
+		}
+		
+		//Always at the end: update scrollview
+		var h: Int = 0
+		for view in scrollView.subviews {
+			//contentRect = contentRect.union(view.frame);
+			h = h + Int(view.frame.height) + 30 //Why 30?
+		}
+		// TODO: Calculate at the end
+		self.scrollView.contentSize.height = 2500//CGFloat(h);
+		
+		// The view controller
+		//var viewController: ViewController  = self.window?.rootViewController as! ViewController
+		
+		
+		//let viewController = UIApplication.topViewController() as! ViewController
+		
+		//viewController.showPost(id: 4)
+		
+		//print("BLOG:DEBUG: Show post on load.")
+		//self.delegate?.controller?.showPost(id: 4)
+		
+		//controller.showPost(id: 4)
+		
+		
+		
+		
+		print("GALLERY:DEBUG: Finished loading GalleryView")
+	}
+	
+	func getLanguage() -> String{
+		let pre = NSLocale.preferredLanguages[0].subStr(start: 0, end: 1)
+		if(pre == "es" || pre == "en" || pre == "eu"){
+			return pre
+		}
+		else{
+			return "es"
+		}
+	}
+}

+ 62 - 0
app/GalleryView.xib

@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="GalleryView" customModule="app" customModuleProvider="target">
+            <connections>
+                <outlet property="container" destination="iN0-l3-epB" id="75N-Q5-bZw"/>
+                <outlet property="scrollView" destination="aoy-Mh-gpR" id="6fj-Cm-cse"/>
+                <outlet property="section" destination="3TY-0K-6q1" id="bqj-sb-ZO2"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aoy-Mh-gpR">
+                    <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                    <subviews>
+                        <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="ULw-PH-L95">
+                            <rect key="frame" x="0.0" y="0.0" width="320" height="3000"/>
+                            <subviews>
+                                <view autoresizesSubviews="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3TY-0K-6q1" customClass="Section" customModule="app">
+                                    <rect key="frame" x="0.0" y="0.0" width="320" height="3000"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="3000" id="vPf-aG-EZ9"/>
+                                    </constraints>
+                                    <edgeInsets key="layoutMargins" top="8" left="8" bottom="8" right="8"/>
+                                </view>
+                            </subviews>
+                            <constraints>
+                                <constraint firstItem="3TY-0K-6q1" firstAttribute="top" secondItem="ULw-PH-L95" secondAttribute="top" id="0GM-gA-76X"/>
+                                <constraint firstItem="3TY-0K-6q1" firstAttribute="width" secondItem="ULw-PH-L95" secondAttribute="width" id="fZS-cn-vrg"/>
+                                <constraint firstAttribute="bottom" secondItem="3TY-0K-6q1" secondAttribute="bottom" id="n9J-oi-jRF"/>
+                            </constraints>
+                        </stackView>
+                    </subviews>
+                    <constraints>
+                        <constraint firstAttribute="trailing" secondItem="ULw-PH-L95" secondAttribute="trailing" id="FEV-qn-MAO"/>
+                        <constraint firstItem="ULw-PH-L95" firstAttribute="leading" secondItem="aoy-Mh-gpR" secondAttribute="leading" id="LOc-iu-RwK"/>
+                        <constraint firstItem="ULw-PH-L95" firstAttribute="top" secondItem="aoy-Mh-gpR" secondAttribute="top" id="tCz-sX-2pl"/>
+                        <constraint firstAttribute="bottom" secondItem="ULw-PH-L95" secondAttribute="bottom" id="wJq-aC-CNc"/>
+                    </constraints>
+                </scrollView>
+            </subviews>
+            <constraints>
+                <constraint firstItem="aoy-Mh-gpR" firstAttribute="width" secondItem="iN0-l3-epB" secondAttribute="width" id="1sn-WI-SeL"/>
+                <constraint firstItem="aoy-Mh-gpR" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="53f-dW-QfI"/>
+                <constraint firstItem="aoy-Mh-gpR" firstAttribute="height" secondItem="iN0-l3-epB" secondAttribute="height" id="JAc-a5-eSB"/>
+                <constraint firstItem="aoy-Mh-gpR" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="KbH-35-FjR"/>
+                <constraint firstItem="aoy-Mh-gpR" firstAttribute="width" secondItem="iN0-l3-epB" secondAttribute="width" id="ftc-db-cKU"/>
+            </constraints>
+        </view>
+    </objects>
+</document>

+ 43 - 0
app/HomeView.swift

@@ -80,6 +80,7 @@ class HomeView: UIView {
 		setUpBlog(context: moc, delegate: appDelegate, lang: lang, parent: blogSection.getContentStack())
 		setUpFutureActivities(context: moc, delegate: appDelegate, lang: lang, parent: futureActivitiesSection.getContentStack())
 		setUpSocial(parent: socialSection.getContentStack())
+		setUpGallery(context: moc, delegate: appDelegate, parent: gallerySection.getContentStack())
 		
 		
 		pastActivitiesSection.expandSection()
@@ -318,6 +319,48 @@ class HomeView: UIView {
 		}
 	}
 	
+	func setUpGallery(context : NSManagedObjectContext, delegate: AppDelegate,parent: UIStackView){
+		print("HOME:LOG: Setting up gallery.")
+		
+		// Create the row
+		var row: RowHomeGallery
+		row = RowHomeGallery.init(s: "rowHomeGallery", i: 0)
+		parent.addArrangedSubview(row)
+		
+		
+		// Set images
+		let fetchRequest: NSFetchRequest<Photo> = Photo.fetchRequest()
+		let sortDescriptor = NSSortDescriptor(key: "uploaded", ascending: false)
+		let sortDescriptors = [sortDescriptor]
+		fetchRequest.sortDescriptors = sortDescriptors
+		fetchRequest.fetchLimit = 4
+		
+		do {
+			//go get the results
+			let searchResults = try context.fetch(fetchRequest)
+	
+			var id: Int
+			var image: String
+			
+			// Loop images
+			var i = 0
+			for r in searchResults as [NSManagedObject] {
+				
+				image = r.value(forKey: "file")! as! String
+				row.setImage(idx: i, filename: image)
+				
+				//TODO Set click listener
+				
+				i = i + 1
+			}
+			
+		}
+		catch{
+			print("HOME:ERROR: Error setting gallery up: \(error)")
+		}
+		
+	}
+	
 	func setUpSocial(parent : UIStackView){
 		print("SETING UP SOCIAL")
 		//Create a new row

+ 1 - 1
app/HomeView.xib

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16B2657" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
     <device id="retina3_5" orientation="portrait">
         <adaptation id="fullscreen"/>
     </device>

+ 2 - 2
app/RowBlog.xib

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16B2657" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
     <device id="retina4_7" orientation="portrait">
         <adaptation id="fullscreen"/>
     </device>
@@ -77,7 +77,7 @@
                     </subviews>
                     <constraints>
                         <constraint firstItem="b17-mq-rbm" firstAttribute="leading" secondItem="fIu-6X-Tsy" secondAttribute="leading" constant="10" id="09K-4S-bco"/>
-                        <constraint firstItem="b17-mq-rbm" firstAttribute="top" secondItem="fIu-6X-Tsy" secondAttribute="top" constant="10" id="DRs-NG-UKY"/>
+                        <constraint firstAttribute="top" secondItem="b17-mq-rbm" secondAttribute="top" constant="-10" id="DRs-NG-UKY"/>
                         <constraint firstAttribute="trailing" secondItem="b17-mq-rbm" secondAttribute="trailing" constant="10" id="Qtu-G3-8IH"/>
                         <constraint firstAttribute="height" constant="120" id="W85-Qc-MWb"/>
                         <constraint firstItem="b17-mq-rbm" firstAttribute="bottom" secondItem="fIu-6X-Tsy" secondAttribute="bottom" constant="10" id="bcY-vf-soX"/>

+ 121 - 0
app/RowGallery.swift

@@ -0,0 +1,121 @@
+// 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 UIKit
+
+/**
+Extension of UIView to be formatted as sections.
+*/
+@IBDesignable class RowGallery: UIView {
+	
+	//This view
+	var v: UIView!
+	
+	@IBOutlet weak var container: UIView!
+	@IBOutlet weak var title: UILabel!
+	@IBOutlet weak var photo0: UIImageView!
+	@IBOutlet weak var photo1: UIImageView!
+	@IBOutlet weak var photo2: UIImageView!
+	@IBOutlet weak var photo3: UIImageView!
+	
+	//Array with the imageviews
+	var preview: [UIImageView] = []
+	
+	
+	/**
+	Default constructor
+	*/
+	required init?(coder aDecoder: NSCoder) {
+		super.init(coder: aDecoder)
+	}
+	
+	private func loadViewFromNib() {
+		let bundle = Bundle(for: type(of: self))
+		let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
+		nib.instantiate(withOwner: self, options: nil).first as! UIView
+	}
+	
+	/**
+	Default constructor.
+	:param: s Custom identifier
+	:param: i Custom identifier
+	*/
+	init(s: String, i: Int) {
+		print("ROWGALLERY:DEBUG: Init \(s), \(i)")
+		super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
+		loadViewFromNib()
+		v = self
+		v.frame = bounds
+		v.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+		v.translatesAutoresizingMaskIntoConstraints = true
+		
+		container.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+		container.translatesAutoresizingMaskIntoConstraints = true
+		
+		container.frame = v.bounds
+		v.addSubview(container)
+		
+		//Populate review array
+		//print("ROWGALLERY:DEBUG: Populating preview array")
+		preview = [photo0, photo1, photo2, photo3]
+		
+		// Set tap recognizer
+		/*print("ROW_BLOG:DEBUG: set tap recognizer")
+		let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector (self.openPost (_:)))
+		tapRecognizer.delegate = (UIApplication.shared.delegate as! AppDelegate).controller
+		addGestureRecognizer(tapRecognizer)*/
+	}
+	
+	/**
+	Default constructor for the interface builder
+	*/
+	override init(frame: CGRect){
+		super.init(frame: frame)
+	}
+	
+	
+	
+	/**
+	Changes the title of the album. Decodes HTML.
+	:param: text The new title.
+	*/
+	func setTitle(text: String){
+		title.text = "  \(text.stripHtml())"
+	}
+	
+	/**
+	Changes the preview image of the album.
+	If null or empty, the igage is hidden.
+	:param: path The new text.
+	*/
+	func setImage(idx: Int, filename: String){
+		if (filename == ""){
+			print("ROWGALLERY:LOG: No image.")
+			//TODO hide the imageview
+		}
+		else{
+			print("Set image \(filename)")
+			let path = "img/galeria/thumb/\(filename)"
+			preview[idx].setImage(localPath: path, remotePath: "https://margolariak.com/\(path)")
+		}
+	}
+	
+}

+ 152 - 0
app/RowGallery.xib

@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
+        <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="RowGallery" customModule="app">
+            <connections>
+                <outlet property="container" destination="5s9-Le-qTP" id="Z8m-m7-LEO"/>
+                <outlet property="photo0" destination="ALA-B7-xYr" id="gBh-vt-C7l"/>
+                <outlet property="photo1" destination="1yK-KV-day" id="uHg-pA-CYk"/>
+                <outlet property="photo2" destination="FJP-ZD-LGA" id="7As-zB-f1E"/>
+                <outlet property="photo3" destination="Xwd-Zx-bfE" id="wvz-zu-nXM"/>
+                <outlet property="title" destination="0t2-77-n8R" id="JXv-hD-axV"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" userLabel="RowGallery" customClass="RowGallery" customModule="app">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5s9-Le-qTP" userLabel="Container">
+                    <rect key="frame" x="-0.5" y="183" width="375" height="300"/>
+                    <subviews>
+                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hif-f7-Vxg" userLabel="Entry">
+                            <rect key="frame" x="10" y="10" width="355" height="280"/>
+                            <subviews>
+                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0t2-77-n8R">
+                                    <rect key="frame" x="0.0" y="10" width="355" height="21"/>
+                                    <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
+                                    <color key="textColor" red="0.1529411765" green="0.33333333329999998" blue="0.45098039220000002" alpha="1" colorSpace="calibratedRGB"/>
+                                    <nil key="highlightedColor"/>
+                                </label>
+                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="PhotoPlaceholder" translatesAutoresizingMaskIntoConstraints="NO" id="ALA-B7-xYr" userLabel="Photo0">
+                                    <rect key="frame" x="10" y="41" width="162.5" height="108"/>
+                                    <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="108" id="iiK-OG-AZy"/>
+                                    </constraints>
+                                    <userDefinedRuntimeAttributes>
+                                        <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
+                                            <color key="value" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                        </userDefinedRuntimeAttribute>
+                                        <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
+                                            <real key="value" value="1"/>
+                                        </userDefinedRuntimeAttribute>
+                                    </userDefinedRuntimeAttributes>
+                                </imageView>
+                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="PhotoPlaceholder" translatesAutoresizingMaskIntoConstraints="NO" id="1yK-KV-day" userLabel="Photo1">
+                                    <rect key="frame" x="182.5" y="41" width="162.5" height="108"/>
+                                    <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="108" id="vrH-X3-6Rl"/>
+                                    </constraints>
+                                    <userDefinedRuntimeAttributes>
+                                        <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
+                                            <real key="value" value="1"/>
+                                        </userDefinedRuntimeAttribute>
+                                        <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
+                                            <color key="value" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                        </userDefinedRuntimeAttribute>
+                                    </userDefinedRuntimeAttributes>
+                                </imageView>
+                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="PhotoPlaceholder" translatesAutoresizingMaskIntoConstraints="NO" id="FJP-ZD-LGA" userLabel="Photo2">
+                                    <rect key="frame" x="10" y="162" width="162.5" height="108"/>
+                                    <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="108" id="U9z-FX-Qxl"/>
+                                    </constraints>
+                                    <userDefinedRuntimeAttributes>
+                                        <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
+                                            <color key="value" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                        </userDefinedRuntimeAttribute>
+                                        <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
+                                            <real key="value" value="1"/>
+                                        </userDefinedRuntimeAttribute>
+                                    </userDefinedRuntimeAttributes>
+                                </imageView>
+                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="PhotoPlaceholder" translatesAutoresizingMaskIntoConstraints="NO" id="Xwd-Zx-bfE" userLabel="Photo3">
+                                    <rect key="frame" x="182.5" y="162" width="162.5" height="108"/>
+                                    <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="108" id="lL5-Te-XTy"/>
+                                    </constraints>
+                                    <userDefinedRuntimeAttributes>
+                                        <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
+                                            <color key="value" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                        </userDefinedRuntimeAttribute>
+                                        <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
+                                            <real key="value" value="1"/>
+                                        </userDefinedRuntimeAttribute>
+                                    </userDefinedRuntimeAttributes>
+                                </imageView>
+                            </subviews>
+                            <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <constraints>
+                                <constraint firstItem="ALA-B7-xYr" firstAttribute="top" secondItem="0t2-77-n8R" secondAttribute="bottom" constant="10" id="0t2-P2-3gu"/>
+                                <constraint firstItem="FJP-ZD-LGA" firstAttribute="leading" secondItem="hif-f7-Vxg" secondAttribute="leading" constant="10" id="5bO-l4-LGu"/>
+                                <constraint firstItem="1yK-KV-day" firstAttribute="trailing" secondItem="0t2-77-n8R" secondAttribute="trailing" constant="-10" id="DVh-LJ-p9e"/>
+                                <constraint firstItem="ALA-B7-xYr" firstAttribute="width" secondItem="hif-f7-Vxg" secondAttribute="width" multiplier="0.5" constant="-15" id="FKW-tk-kAd"/>
+                                <constraint firstItem="FJP-ZD-LGA" firstAttribute="width" secondItem="hif-f7-Vxg" secondAttribute="width" multiplier="0.5" constant="-15" id="G3l-Qc-THc"/>
+                                <constraint firstItem="ALA-B7-xYr" firstAttribute="leading" secondItem="0t2-77-n8R" secondAttribute="leading" constant="10" id="HoJ-in-dXf"/>
+                                <constraint firstItem="0t2-77-n8R" firstAttribute="centerX" secondItem="hif-f7-Vxg" secondAttribute="centerX" id="Paz-Pk-eSy"/>
+                                <constraint firstItem="Xwd-Zx-bfE" firstAttribute="width" secondItem="hif-f7-Vxg" secondAttribute="width" multiplier="0.5" constant="-15" id="QPQ-1R-oUR"/>
+                                <constraint firstItem="1yK-KV-day" firstAttribute="top" secondItem="0t2-77-n8R" secondAttribute="bottom" constant="10" id="Qxa-Ti-08x"/>
+                                <constraint firstItem="0t2-77-n8R" firstAttribute="top" secondItem="hif-f7-Vxg" secondAttribute="top" constant="10" id="WYO-vy-VPP"/>
+                                <constraint firstItem="FJP-ZD-LGA" firstAttribute="bottom" secondItem="hif-f7-Vxg" secondAttribute="bottom" constant="-10" id="amo-wJ-6JX"/>
+                                <constraint firstItem="0t2-77-n8R" firstAttribute="width" secondItem="hif-f7-Vxg" secondAttribute="width" id="bDV-Kx-fRp"/>
+                                <constraint firstItem="Xwd-Zx-bfE" firstAttribute="bottom" secondItem="hif-f7-Vxg" secondAttribute="bottom" constant="-10" id="hN9-fv-fa5"/>
+                                <constraint firstItem="1yK-KV-day" firstAttribute="width" secondItem="0t2-77-n8R" secondAttribute="width" multiplier="0.5" constant="-15" id="mnN-Gq-pa3"/>
+                                <constraint firstItem="Xwd-Zx-bfE" firstAttribute="trailing" secondItem="hif-f7-Vxg" secondAttribute="trailing" constant="-10" id="sfm-VE-DCx"/>
+                            </constraints>
+                            <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
+                                    <color key="value" red="0.42745098039215684" green="0.41176470588235292" blue="0.56470588235294117" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                </userDefinedRuntimeAttribute>
+                                <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
+                                    <integer key="value" value="1"/>
+                                </userDefinedRuntimeAttribute>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                    <integer key="value" value="3"/>
+                                </userDefinedRuntimeAttribute>
+                            </userDefinedRuntimeAttributes>
+                        </view>
+                    </subviews>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="300" id="7Yh-0e-ajC"/>
+                        <constraint firstAttribute="bottom" secondItem="hif-f7-Vxg" secondAttribute="bottom" constant="10" id="KJt-VS-2f3"/>
+                        <constraint firstItem="hif-f7-Vxg" firstAttribute="trailing" secondItem="5s9-Le-qTP" secondAttribute="trailing" constant="-10" id="dQW-pn-Jio"/>
+                        <constraint firstAttribute="top" secondItem="hif-f7-Vxg" secondAttribute="top" constant="-10" id="hXG-tn-58e"/>
+                        <constraint firstItem="hif-f7-Vxg" firstAttribute="leading" secondItem="5s9-Le-qTP" secondAttribute="leading" constant="10" id="noN-5r-cCi"/>
+                    </constraints>
+                    <edgeInsets key="layoutMargins" top="8" left="8" bottom="8" right="8"/>
+                </view>
+            </subviews>
+            <constraints>
+                <constraint firstItem="5s9-Le-qTP" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="58W-bA-0zy"/>
+                <constraint firstItem="5s9-Le-qTP" firstAttribute="width" secondItem="iN0-l3-epB" secondAttribute="width" id="96p-IK-UFf"/>
+                <constraint firstItem="5s9-Le-qTP" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="aM7-gO-87G"/>
+            </constraints>
+        </view>
+    </objects>
+    <resources>
+        <image name="PhotoPlaceholder" width="170" height="108"/>
+    </resources>
+</document>

+ 101 - 0
app/RowHomeGallery.swift

@@ -0,0 +1,101 @@
+// 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 UIKit
+
+/**
+Extension of UIView to be formatted as sections.
+*/
+@IBDesignable class RowHomeGallery: UIView {
+	
+	//This view
+	var v: UIView!
+	
+	@IBOutlet weak var container: UIView!
+	@IBOutlet weak var photo0: UIImageView!
+	@IBOutlet weak var photo1: UIImageView!
+	@IBOutlet weak var photo2: UIImageView!
+	@IBOutlet weak var photo3: UIImageView!
+	
+	var photos: [UIImageView] = []
+	
+	/**
+	Default constructor
+	*/
+	required init?(coder aDecoder: NSCoder) {
+		super.init(coder: aDecoder)
+	}
+	
+	private func loadViewFromNib() {
+		let bundle = Bundle(for: type(of: self))
+		let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
+		nib.instantiate(withOwner: self, options: nil).first as! UIView
+	}
+	
+	/**
+	Default constructor.
+	:param: s Custom identifier
+	:param: i Custom identifier
+	*/
+	init(s: String, i: Int) {
+		super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
+		loadViewFromNib()
+		v = self
+		v.frame = bounds
+		v.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+		v.translatesAutoresizingMaskIntoConstraints = true
+		container.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+		container.translatesAutoresizingMaskIntoConstraints = true
+		
+		container.frame = v.bounds
+		v.addSubview(container)
+		
+		photos = [photo0, photo1, photo2, photo3]
+		
+
+		
+		//TODO Set click listeners
+	}
+	
+	/**
+	Default constructor for the interface builder
+	*/
+	override init(frame: CGRect){
+		super.init(frame: frame)
+	}
+	
+	/**
+	Changes the preview image.
+	If null or empty, the igage is hidden.
+	:param: path The new text.
+	*/
+	func setImage(idx: Int, filename: String){
+		if (filename == ""){
+			print("ROWHOMEGALLERY:LOG: No image.")
+			//TODO hide the imageview
+		}
+		else{
+			let path = "img/galeria/thumb/\(filename)"
+			photos[idx].setImage(localPath: path, remotePath: "https://margolariak.com/\(path)")
+		}
+	}
+	
+}

+ 112 - 0
app/RowHomeGallery.xib

@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
+        <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="RowHomeGallery" customModule="app">
+            <connections>
+                <outlet property="container" destination="fQL-ej-f6f" id="gat-5m-Nlc"/>
+                <outlet property="photo0" destination="dnB-DT-XBi" id="Gcn-A3-qVV"/>
+                <outlet property="photo1" destination="WDB-y4-09J" id="yCC-HU-nfj"/>
+                <outlet property="photo2" destination="anB-pq-Srl" id="VWm-9P-5aK"/>
+                <outlet property="photo3" destination="fDa-I0-n0C" id="oyE-AI-yhP"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="RowHomeGallery" customModule="app">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fQL-ej-f6f" userLabel="Container">
+                    <rect key="frame" x="-0.5" y="0.0" width="375" height="230"/>
+                    <subviews>
+                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wVc-lu-Pqh" userLabel="Entry">
+                            <rect key="frame" x="10" y="10" width="355" height="230"/>
+                            <subviews>
+                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="PhotoPlaceholder" translatesAutoresizingMaskIntoConstraints="NO" id="dnB-DT-XBi" userLabel="Photo0">
+                                    <rect key="frame" x="10" y="10" width="162.5" height="100"/>
+                                    <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="100" id="c49-em-SBK"/>
+                                    </constraints>
+                                </imageView>
+                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="PhotoPlaceholder" translatesAutoresizingMaskIntoConstraints="NO" id="WDB-y4-09J" userLabel="Photo1">
+                                    <rect key="frame" x="182.5" y="10" width="162.5" height="100"/>
+                                    <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="100" id="PMB-24-syn"/>
+                                    </constraints>
+                                </imageView>
+                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="PhotoPlaceholder" translatesAutoresizingMaskIntoConstraints="NO" id="anB-pq-Srl" userLabel="Photo2">
+                                    <rect key="frame" x="10" y="120" width="162.5" height="100"/>
+                                    <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="100" id="A9o-VC-FHH"/>
+                                    </constraints>
+                                </imageView>
+                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="PhotoPlaceholder" translatesAutoresizingMaskIntoConstraints="NO" id="fDa-I0-n0C" userLabel="Photo3">
+                                    <rect key="frame" x="182.5" y="120" width="162.5" height="100"/>
+                                    <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                    <constraints>
+                                        <constraint firstAttribute="height" constant="100" id="Lw8-Ie-YJH"/>
+                                    </constraints>
+                                </imageView>
+                            </subviews>
+                            <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <constraints>
+                                <constraint firstItem="dnB-DT-XBi" firstAttribute="width" secondItem="wVc-lu-Pqh" secondAttribute="width" multiplier="0.5" constant="-15" id="68Z-py-m5z"/>
+                                <constraint firstItem="anB-pq-Srl" firstAttribute="top" secondItem="dnB-DT-XBi" secondAttribute="bottom" constant="10" id="Bad-nG-5z5"/>
+                                <constraint firstItem="dnB-DT-XBi" firstAttribute="leading" secondItem="wVc-lu-Pqh" secondAttribute="leading" constant="10" id="D5O-yf-YW8"/>
+                                <constraint firstItem="fDa-I0-n0C" firstAttribute="top" secondItem="WDB-y4-09J" secondAttribute="bottom" constant="10" id="EAz-Ai-4fI"/>
+                                <constraint firstItem="anB-pq-Srl" firstAttribute="leading" secondItem="wVc-lu-Pqh" secondAttribute="leading" constant="10" id="EBa-JH-t1r"/>
+                                <constraint firstItem="anB-pq-Srl" firstAttribute="width" secondItem="wVc-lu-Pqh" secondAttribute="width" multiplier="0.5" constant="-15" id="EcJ-3D-reB"/>
+                                <constraint firstAttribute="height" constant="230" id="Ffn-YP-qLO"/>
+                                <constraint firstItem="WDB-y4-09J" firstAttribute="top" secondItem="wVc-lu-Pqh" secondAttribute="top" constant="10" id="NRB-ED-7lT"/>
+                                <constraint firstItem="fDa-I0-n0C" firstAttribute="width" secondItem="wVc-lu-Pqh" secondAttribute="width" multiplier="0.5" constant="-15" id="gYW-t2-gNJ"/>
+                                <constraint firstItem="WDB-y4-09J" firstAttribute="trailing" secondItem="wVc-lu-Pqh" secondAttribute="trailing" constant="-10" id="lWA-u1-9Oi"/>
+                                <constraint firstItem="dnB-DT-XBi" firstAttribute="top" secondItem="wVc-lu-Pqh" secondAttribute="top" constant="10" id="mWE-kd-0X9"/>
+                                <constraint firstItem="fDa-I0-n0C" firstAttribute="trailing" secondItem="wVc-lu-Pqh" secondAttribute="trailing" constant="-10" id="tJB-Qz-gmc"/>
+                                <constraint firstItem="WDB-y4-09J" firstAttribute="width" secondItem="wVc-lu-Pqh" secondAttribute="width" multiplier="0.5" constant="-15" id="tJI-ji-ciu"/>
+                            </constraints>
+                            <edgeInsets key="layoutMargins" top="8" left="8" bottom="8" right="8"/>
+                            <userDefinedRuntimeAttributes>
+                                <userDefinedRuntimeAttribute type="color" keyPath="borderColor">
+                                    <color key="value" red="0.42745098039215684" green="0.41176470588235292" blue="0.56470588235294117" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                                </userDefinedRuntimeAttribute>
+                                <userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
+                                    <integer key="value" value="1"/>
+                                </userDefinedRuntimeAttribute>
+                                <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                    <integer key="value" value="3"/>
+                                </userDefinedRuntimeAttribute>
+                            </userDefinedRuntimeAttributes>
+                        </view>
+                    </subviews>
+                    <constraints>
+                        <constraint firstItem="wVc-lu-Pqh" firstAttribute="bottom" secondItem="fQL-ej-f6f" secondAttribute="bottom" constant="10" id="4Qm-4E-T6T"/>
+                        <constraint firstAttribute="trailing" secondItem="wVc-lu-Pqh" secondAttribute="trailing" constant="10" id="Gw9-3i-bdM"/>
+                        <constraint firstItem="wVc-lu-Pqh" firstAttribute="top" secondItem="fQL-ej-f6f" secondAttribute="top" constant="10" id="JpE-6m-QpJ"/>
+                        <constraint firstItem="wVc-lu-Pqh" firstAttribute="leading" secondItem="fQL-ej-f6f" secondAttribute="leading" constant="10" id="sx2-Al-2U2"/>
+                    </constraints>
+                    <edgeInsets key="layoutMargins" top="8" left="8" bottom="8" right="8"/>
+                </view>
+            </subviews>
+            <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <constraints>
+                <constraint firstItem="fQL-ej-f6f" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="D1e-8E-fga"/>
+                <constraint firstItem="fQL-ej-f6f" firstAttribute="width" secondItem="iN0-l3-epB" secondAttribute="width" id="Pfz-ns-fxp"/>
+                <constraint firstItem="fQL-ej-f6f" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="r6U-3K-HqE"/>
+            </constraints>
+        </view>
+    </objects>
+    <resources>
+        <image name="PhotoPlaceholder" width="170" height="108"/>
+    </resources>
+</document>

+ 173 - 5
app/Sync.swift

@@ -87,8 +87,8 @@ class Sync{
 			//let dataFestivalEventImage : [String] = self.getTable(data: strData!, table: "festival_event_image")
 			//let dataFestivalOffer : [String] = self.getTable(data: strData!, table: "festival_offer")
 			//let dataPeople : [String] = self.getTable(data: strData!, table: "people")
-			//let dataPhoto : [String] = self.getTable(data: strData!, table: "photo")
-			//let dataPhotoAlbum : [String] = self.getTable(data: strData!, table: "photo_album")
+			let dataPhoto : [String] = self.getTable(data: strData!, table: "photo")
+			let dataPhotoAlbum : [String] = self.getTable(data: strData!, table: "photo_album")
 			//let dataPhotoComment : [String] = self.getTable(data: strData!, table: "photo_comment")
 			let dataPlace : [String] = self.getTable(data: strData!, table: "place")
 			let dataPost : [String] = self.getTable(data: strData!, table: "post")
@@ -112,6 +112,8 @@ class Sync{
 			self.saveTablePlace(entries: dataPlace)
 			
 			self.saveTableAlbum(entries: dataAlbum)
+			self.saveTablePhoto(entries: dataPhoto)
+			self.saveTablePhotoAlbum(entries: dataPhotoAlbum)
 			
 			//DEBUG: Tester, Debug only
 			// Test if a entity has entries
@@ -1121,7 +1123,6 @@ class Sync{
 	Saves the data in the table.
 	:param: entries Array of strings containing the rows of the table, in JSON format.
 	*/
-	//CHECK: New (and probably better format than the others.)
 	func saveTableAlbum(entries : [String]){
 		
 		print("SYNC:LOG: Saving table Album.")
@@ -1169,12 +1170,12 @@ class Sync{
 			//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)
-			row.setValue(title_es, forKey: "title_es")
+			row.setValue(title_en, forKey: "title_en")
 			
 			//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)
-			row.setValue(title_es, forKey: "title_es")
+			row.setValue(title_eu, forKey: "title_eu")
 			
 			//Get description_es
 			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
@@ -1212,4 +1213,171 @@ class Sync{
 			}
 		}
 	}
+	
+	/**
+	Saves the data in the table.
+	:param: entries Array of strings containing the rows of the table, in JSON format.
+	*/
+	func saveTablePhoto(entries : [String]){
+		
+		print("SYNC:LOG: Saving table Photo.")
+		
+		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: "Photo", in: context)
+		
+		var row: NSManagedObject
+		
+		//Delete all previous entries
+		let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Photo")
+		let request = NSBatchDeleteRequest(fetchRequest: fetch)
+		do {
+			try context.execute(request)
+		} catch let error as NSError  {
+			print("SYNC:ERROR: Could not clean up Photo: \(error), \(error.userInfo).")
+		} catch {
+			print("SYNC:ERROR: Could not clean up Photo entity.")
+		}
+		
+		//Loop new entries
+		for entry in entries{
+			
+			row = NSManagedObject(entity: entity!, insertInto: context)
+			
+			//Get id
+			var str = entry
+			let id : Int = Int(str.subStr(start : str.indexOf(target : "\"id\":")! + 6, end : str.indexOf(target : ",\"")! - 2))!
+			row.setValue(id, forKey: "id")
+			
+			//Get file
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			let file : String = str.subStr(start : str.indexOf(target : "\"file\":")! + 8, end : str.indexOf(target : ",\"")! - 2)
+			row.setValue(file, forKey: "file")
+			
+			//Get permalink
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			let permalink : String = str.subStr(start : str.indexOf(target : "\"permalink\":")! + 13, end : str.indexOf(target : ",\"")! - 2)
+			row.setValue(permalink, forKey: "permalink")
+			
+			//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)
+			row.setValue(title_es, forKey: "title_es")
+			
+			//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)
+			row.setValue(title_en, forKey: "title_en")
+			
+			//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)
+			row.setValue(title_eu, forKey: "title_eu")
+			
+			//Get description_es
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			let description_es : String = str.subStr(start : str.indexOf(target : "\"description_es\":")! + 18, end : str.indexOf(target : ",\"")! - 2)
+			if (description_es != "ul"){ //From "null"
+				row.setValue(description_es, forKey: "description_es")
+			}
+			
+			//Get description_en
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			let description_en : String = str.subStr(start : str.indexOf(target : "\"description_en\":")! + 18, end : str.indexOf(target : ",\"")! - 2)
+			if (description_en != "ul"){ //From "null"
+				row.setValue(description_en, forKey: "description_en")
+			}
+			
+			//Get description_eu
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			let description_eu : String = str.subStr(start : str.indexOf(target : "\"description_eu\":")! + 18, end : str.indexOf(target : ",\"")! - 2)
+			if (description_eu != "ul"){ //From "null"
+				row.setValue(description_eu, forKey: "description_eu")
+			}
+			
+			//Get uploaded
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
+			let uploaded = dateFormatter.date(from: str.subStr(start : str.indexOf(target : "\"uploaded\":")! + 12, end : str.indexOf(target : ",\"")! - 2))!
+			row.setValue(uploaded, forKey: "uploaded")
+			
+			//TODO: Ignoting place
+			//TODO: Ignoring width
+			//TODO: Ignoring height
+			//TODO: Ignoring size
+			//TODO: Ignoring username
+			
+			//Save CoreData
+			do {
+				try context.save()
+			} catch let error as NSError  {
+				print("SYNC:ERROR: Could not store Photo with id \(id): \(error), \(error.userInfo).")
+			} catch {
+				print("SYNC:ERROR: Could not store Photo with id \(id).")
+			}
+		}
+	}
+	
+	/**
+	Saves the data in the table.
+	:param: entries Array of strings containing the rows of the table, in JSON format.
+	*/
+	func saveTablePhotoAlbum(entries : [String]){
+		
+		print("SYNC:LOG: Saving table Photo_album.")
+		
+		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: "Photo_album", in: context)
+		
+		var row: NSManagedObject
+		
+		//Delete all previous entries
+		let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Photo_album")
+		let request = NSBatchDeleteRequest(fetchRequest: fetch)
+		do {
+			try context.execute(request)
+		} catch let error as NSError  {
+			print("SYNC:ERROR: Could not clean up Photo_album: \(error), \(error.userInfo).")
+		} catch {
+			print("SYNC:ERROR: Could not clean up Photo_album entity.")
+		}
+		
+		//Loop new entries
+		for entry in entries{
+			
+			row = NSManagedObject(entity: entity!, insertInto: context)
+			
+			//Get photo
+			var str = entry
+			let photo : Int = Int(str.subStr(start : str.indexOf(target : "\"photo\":")! + 9, end : str.indexOf(target : ",\"")! - 2))!
+			row.setValue(photo, forKey: "photo")
+			
+			//Get album
+			str = str.subStr(start : str.indexOf(target : ",\"")! + 1, end : str.length - 1)
+			let album : Int = Int(str.subStr(start : str.indexOf(target : "\"album\":")! + 9, end : str.length - 2))!
+			row.setValue(album, forKey: "album")
+			
+			//Save CoreData
+			do {
+				try context.save()
+			} catch let error as NSError  {
+				print("SYNC:ERROR: Could not store Photo_album entry \(error.userInfo).")
+			} catch {
+				print("SYNC:ERROR: Could not store Photo_album entry.")
+			}
+		}
+	}
 }