Inigo Valentin 10 gadi atpakaļ
revīzija
522b903642
100 mainītis faili ar 8692 papildinājumiem un 0 dzēšanām
  1. 39 0
      .gitignore
  2. 229 0
      .idea/codeStyleSettings.xml
  3. 24 0
      .idea/gradle.xml
  4. 10 0
      .idea/inspectionProfiles/Project_Default.xml
  5. 7 0
      .idea/inspectionProfiles/profiles_settings.xml
  6. 12 0
      .idea/runConfigurations.xml
  7. 25 0
      app/build.gradle
  8. 4 0
      app/lint.xml
  9. 69 0
      app/src/main/AndroidManifest.xml
  10. 51 0
      app/src/main/java/com/ivalentin/gm/AboutLayout.java
  11. 171 0
      app/src/main/java/com/ivalentin/gm/ActivityFutureLayout.java
  12. 266 0
      app/src/main/java/com/ivalentin/gm/ActivityLayout.java
  13. 118 0
      app/src/main/java/com/ivalentin/gm/ActivityPastLayout.java
  14. 231 0
      app/src/main/java/com/ivalentin/gm/AlarmReceiver.java
  15. 161 0
      app/src/main/java/com/ivalentin/gm/AlbumLayout.java
  16. 677 0
      app/src/main/java/com/ivalentin/gm/AroundLayout.java
  17. 246 0
      app/src/main/java/com/ivalentin/gm/BlogLayout.java
  18. 36 0
      app/src/main/java/com/ivalentin/gm/BootReceiver.java
  19. 76 0
      app/src/main/java/com/ivalentin/gm/CustomScrollView.java
  20. 63 0
      app/src/main/java/com/ivalentin/gm/Distance.java
  21. 96 0
      app/src/main/java/com/ivalentin/gm/DownloadImage.java
  22. 257 0
      app/src/main/java/com/ivalentin/gm/Event.java
  23. 95 0
      app/src/main/java/com/ivalentin/gm/FakeLinkTextView.java
  24. 73 0
      app/src/main/java/com/ivalentin/gm/FetchURL.java
  25. 629 0
      app/src/main/java/com/ivalentin/gm/GM.java
  26. 177 0
      app/src/main/java/com/ivalentin/gm/GalleryLayout.java
  27. 897 0
      app/src/main/java/com/ivalentin/gm/HomeLayout.java
  28. 10 0
      app/src/main/java/com/ivalentin/gm/LablancaLayout.java
  29. 293 0
      app/src/main/java/com/ivalentin/gm/LocationLayout.java
  30. 568 0
      app/src/main/java/com/ivalentin/gm/MainActivity.java
  31. 284 0
      app/src/main/java/com/ivalentin/gm/MainLayout.java
  32. 203 0
      app/src/main/java/com/ivalentin/gm/PostComment.java
  33. 171 0
      app/src/main/java/com/ivalentin/gm/PostLayout.java
  34. 607 0
      app/src/main/java/com/ivalentin/gm/ScheduleLayout.java
  35. 231 0
      app/src/main/java/com/ivalentin/gm/SettingsLayout.java
  36. 306 0
      app/src/main/java/com/ivalentin/gm/Sync.java
  37. BIN
      app/src/main/res/drawable-xhdpi/pinpoint_gm.png
  38. BIN
      app/src/main/res/drawable-xxhdpi/pinpoint_gm.png
  39. 14 0
      app/src/main/res/drawable/album.xml
  40. BIN
      app/src/main/res/drawable/alpha.png
  41. 18 0
      app/src/main/res/drawable/arrowbutton.xml
  42. 18 0
      app/src/main/res/drawable/arrowbuttonpressed.xml
  43. 13 0
      app/src/main/res/drawable/arrowbuttonselector.xml
  44. 18 0
      app/src/main/res/drawable/background_app.xml
  45. 18 0
      app/src/main/res/drawable/background_menu.xml
  46. 15 0
      app/src/main/res/drawable/button.xml
  47. 11 0
      app/src/main/res/drawable/button_selector.xml
  48. 15 0
      app/src/main/res/drawable/buttonpressed.xml
  49. BIN
      app/src/main/res/drawable/comment.png
  50. 18 0
      app/src/main/res/drawable/datebar.xml
  51. 14 0
      app/src/main/res/drawable/dialog_schedule.xml
  52. 11 0
      app/src/main/res/drawable/dialog_schedule_map.xml
  53. BIN
      app/src/main/res/drawable/divider.png
  54. 9 0
      app/src/main/res/drawable/entry.xml
  55. 11 0
      app/src/main/res/drawable/home_section_title.xml
  56. BIN
      app/src/main/res/drawable/ic_launcher.png
  57. BIN
      app/src/main/res/drawable/ic_launcher_old.png
  58. BIN
      app/src/main/res/drawable/ic_notification.png
  59. BIN
      app/src/main/res/drawable/icon_about.png
  60. BIN
      app/src/main/res/drawable/icon_activities.png
  61. BIN
      app/src/main/res/drawable/icon_around.png
  62. BIN
      app/src/main/res/drawable/icon_blog.png
  63. BIN
      app/src/main/res/drawable/icon_gallery.png
  64. BIN
      app/src/main/res/drawable/icon_gm.png
  65. BIN
      app/src/main/res/drawable/icon_go.png
  66. BIN
      app/src/main/res/drawable/icon_home.png
  67. BIN
      app/src/main/res/drawable/icon_lablanca.png
  68. BIN
      app/src/main/res/drawable/icon_location.png
  69. BIN
      app/src/main/res/drawable/icon_news.png
  70. BIN
      app/src/main/res/drawable/icon_program.png
  71. BIN
      app/src/main/res/drawable/icon_settings.png
  72. 14 0
      app/src/main/res/drawable/input.xml
  73. 11 0
      app/src/main/res/drawable/location_map.xml
  74. BIN
      app/src/main/res/drawable/menu.png
  75. BIN
      app/src/main/res/drawable/pinpoint.png
  76. BIN
      app/src/main/res/drawable/pinpoint_gm.png
  77. BIN
      app/src/main/res/drawable/pinpoint_map.png
  78. BIN
      app/src/main/res/drawable/price_day.png
  79. BIN
      app/src/main/res/drawable/price_offer.png
  80. 13 0
      app/src/main/res/drawable/schedule_entry.xml
  81. BIN
      app/src/main/res/drawable/schedule_point.png
  82. BIN
      app/src/main/res/drawable/schedule_timeline.png
  83. 9 0
      app/src/main/res/drawable/section.xml
  84. BIN
      app/src/main/res/drawable/social_facebook.png
  85. BIN
      app/src/main/res/drawable/social_googleplus.png
  86. BIN
      app/src/main/res/drawable/social_instagram.png
  87. BIN
      app/src/main/res/drawable/social_mail.png
  88. BIN
      app/src/main/res/drawable/social_twitter.png
  89. BIN
      app/src/main/res/drawable/social_web.png
  90. BIN
      app/src/main/res/drawable/social_whatsapp.png
  91. BIN
      app/src/main/res/drawable/social_youtube.png
  92. BIN
      app/src/main/res/drawable/spinner_spinning.gif
  93. BIN
      app/src/main/res/drawable/spinner_stop.png
  94. 8 0
      app/src/main/res/drawable/timeline.xml
  95. 18 0
      app/src/main/res/drawable/titlebar.xml
  96. 281 0
      app/src/main/res/layout/activity_main.xml
  97. 139 0
      app/src/main/res/layout/dialog_around.xml
  98. 22 0
      app/src/main/res/layout/dialog_change_username.xml
  99. 77 0
      app/src/main/res/layout/dialog_notification.xml
  100. 485 0
      app/src/main/res/layout/dialog_prices.xml

+ 39 - 0
.gitignore

@@ -0,0 +1,39 @@
+ 
+# Built application files
+/*/build/
+
+# Crashlytics configuations
+com_crashlytics_export_strings.xml
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Gradle generated files
+.gradle/
+
+# Signing files
+.signing/
+
+# User-specific configurations
+.idea/libraries/
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/.name
+.idea/compiler.xml
+.idea/copyright/profiles_settings.xml
+.idea/encodings.xml
+.idea/misc.xml
+.idea/modules.xml
+.idea/scopes/scope_settings.xml
+.idea/vcs.xml
+*.iml
+
+# OS-specific files
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+.directory

+ 229 - 0
.idea/codeStyleSettings.xml

@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectCodeStyleSettingsManager">
+    <option name="PER_PROJECT_SETTINGS">
+      <value>
+        <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
+        <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
+        <option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
+          <value />
+        </option>
+        <option name="IMPORT_LAYOUT_TABLE">
+          <value>
+            <package name="android" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="com" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="junit" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="net" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="org" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="java" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="javax" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="" withSubpackages="true" static="false" />
+            <emptyLine />
+            <package name="" withSubpackages="true" static="true" />
+            <emptyLine />
+          </value>
+        </option>
+        <option name="RIGHT_MARGIN" value="100" />
+        <AndroidXmlCodeStyleSettings>
+          <option name="USE_CUSTOM_SETTINGS" value="true" />
+        </AndroidXmlCodeStyleSettings>
+        <Objective-C-extensions>
+          <option name="GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES" value="ASK" />
+          <option name="RELEASE_STYLE" value="IVAR" />
+          <option name="TYPE_QUALIFIERS_PLACEMENT" value="BEFORE" />
+          <file>
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
+          </file>
+          <class>
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
+            <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
+          </class>
+          <extensions>
+            <pair source="cpp" header="h" />
+            <pair source="c" header="h" />
+          </extensions>
+        </Objective-C-extensions>
+        <XML>
+          <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
+        </XML>
+        <codeStyleSettings language="XML">
+          <option name="FORCE_REARRANGE_MODE" value="1" />
+          <indentOptions>
+            <option name="CONTINUATION_INDENT_SIZE" value="4" />
+          </indentOptions>
+          <arrangement>
+            <rules>
+              <section>
+                <rule>
+                  <match>
+                    <AND>
+                      <NAME>xmlns:android</NAME>
+                      <XML_NAMESPACE>^$</XML_NAMESPACE>
+                    </AND>
+                  </match>
+                </rule>
+              </section>
+              <section>
+                <rule>
+                  <match>
+                    <AND>
+                      <NAME>xmlns:.*</NAME>
+                      <XML_NAMESPACE>^$</XML_NAMESPACE>
+                    </AND>
+                  </match>
+                  <order>BY_NAME</order>
+                </rule>
+              </section>
+              <section>
+                <rule>
+                  <match>
+                    <AND>
+                      <NAME>.*:id</NAME>
+                      <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                    </AND>
+                  </match>
+                </rule>
+              </section>
+              <section>
+                <rule>
+                  <match>
+                    <AND>
+                      <NAME>.*:name</NAME>
+                      <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                    </AND>
+                  </match>
+                </rule>
+              </section>
+              <section>
+                <rule>
+                  <match>
+                    <AND>
+                      <NAME>name</NAME>
+                      <XML_NAMESPACE>^$</XML_NAMESPACE>
+                    </AND>
+                  </match>
+                </rule>
+              </section>
+              <section>
+                <rule>
+                  <match>
+                    <AND>
+                      <NAME>style</NAME>
+                      <XML_NAMESPACE>^$</XML_NAMESPACE>
+                    </AND>
+                  </match>
+                </rule>
+              </section>
+              <section>
+                <rule>
+                  <match>
+                    <AND>
+                      <NAME>.*</NAME>
+                      <XML_NAMESPACE>^$</XML_NAMESPACE>
+                    </AND>
+                  </match>
+                  <order>BY_NAME</order>
+                </rule>
+              </section>
+              <section>
+                <rule>
+                  <match>
+                    <AND>
+                      <NAME>.*:layout_width</NAME>
+                      <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                    </AND>
+                  </match>
+                </rule>
+              </section>
+              <section>
+                <rule>
+                  <match>
+                    <AND>
+                      <NAME>.*:layout_height</NAME>
+                      <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                    </AND>
+                  </match>
+                </rule>
+              </section>
+              <section>
+                <rule>
+                  <match>
+                    <AND>
+                      <NAME>.*:layout_.*</NAME>
+                      <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                    </AND>
+                  </match>
+                  <order>BY_NAME</order>
+                </rule>
+              </section>
+              <section>
+                <rule>
+                  <match>
+                    <AND>
+                      <NAME>.*:width</NAME>
+                      <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                    </AND>
+                  </match>
+                  <order>BY_NAME</order>
+                </rule>
+              </section>
+              <section>
+                <rule>
+                  <match>
+                    <AND>
+                      <NAME>.*:height</NAME>
+                      <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                    </AND>
+                  </match>
+                  <order>BY_NAME</order>
+                </rule>
+              </section>
+              <section>
+                <rule>
+                  <match>
+                    <AND>
+                      <NAME>.*</NAME>
+                      <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
+                    </AND>
+                  </match>
+                  <order>BY_NAME</order>
+                </rule>
+              </section>
+              <section>
+                <rule>
+                  <match>
+                    <AND>
+                      <NAME>.*</NAME>
+                      <XML_NAMESPACE>.*</XML_NAMESPACE>
+                    </AND>
+                  </match>
+                  <order>BY_NAME</order>
+                </rule>
+              </section>
+            </rules>
+          </arrangement>
+        </codeStyleSettings>
+      </value>
+    </option>
+    <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default (1)" />
+  </component>
+</project>

+ 24 - 0
.idea/gradle.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GradleSettings">
+    <option name="linkedExternalProjectsSettings">
+      <GradleProjectSettings>
+        <option name="distributionType" value="LOCAL" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="gradleHome" value="$APPLICATION_HOME_DIR$/gradle/gradle-2.10" />
+        <option name="modules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/app" />
+          </set>
+        </option>
+        <option name="myModules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/app" />
+          </set>
+        </option>
+      </GradleProjectSettings>
+    </option>
+  </component>
+</project>

+ 10 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,10 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="AndroidLintRtlCompat" enabled="false" level="ERROR" enabled_by_default="false" />
+    <inspection_tool class="LoggerInitializedWithForeignClass" enabled="false" level="WARNING" enabled_by_default="false">
+      <option name="loggerClassName" value="org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger" />
+      <option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" />
+    </inspection_tool>
+  </profile>
+</component>

+ 7 - 0
.idea/inspectionProfiles/profiles_settings.xml

@@ -0,0 +1,7 @@
+<component name="InspectionProjectProfileManager">
+  <settings>
+    <option name="PROJECT_PROFILE" value="Project Default" />
+    <option name="USE_PROJECT_PROFILE" value="true" />
+    <version value="1.0" />
+  </settings>
+</component>

+ 12 - 0
.idea/runConfigurations.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RunConfigurationProducerService">
+    <option name="ignoredProducers">
+      <set>
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
+        <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
+      </set>
+    </option>
+  </component>
+</project>

+ 25 - 0
app/build.gradle

@@ -0,0 +1,25 @@
+apply plugin: 'com.android.application'
+
+android {
+    compileSdkVersion 23
+    buildToolsVersion "23.0.3"
+
+    defaultConfig {
+        applicationId "com.ivalentin.gm"
+        minSdkVersion 9
+        targetSdkVersion 22
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
+        }
+    }
+}
+
+dependencies {
+    compile 'com.android.support:support-v4:22.2.1'
+    compile 'com.android.support:appcompat-v7:22.2.1'
+    compile 'com.google.android.gms:play-services:+'
+}

+ 4 - 0
app/lint.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<lint>
+    <issue id="DuplicateIds" severity="informational" />
+</lint>

+ 69 - 0
app/src/main/AndroidManifest.xml

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.ivalentin.gm"
+    android:versionCode="7"
+    android:versionName="1.5" >
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+    
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> 
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    
+    <uses-permission android:name="android.permission.VIBRATE"/>
+    
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="22" />
+    
+    <uses-feature
+        android:glEsVersion="0x00020000"
+        android:required="true"/>
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme"
+        android:supportsRtl="true"
+        android:isGame="false"
+        android:allowClearUserData="true">
+        
+        <meta-data
+    		android:name="com.google.android.gms.version"
+    		android:value="@integer/google_play_services_version" />
+        
+        <meta-data
+    		android:name="com.google.android.geo.API_KEY"
+    		android:value="AIzaSyC6DgCJRiBkYiNUivE0VH9fsTZDbfVDpS0"/>
+        
+        <activity
+            android:name=".MainActivity"
+            android:theme="@style/Theme.NoTitle"
+            android:windowSoftInputMode="adjustPan"
+            android:label="@string/app_name">
+            
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+				
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        
+        <receiver
+            android:process=":remote"
+            android:name=".AlarmReceiver"/>
+        
+        <receiver
+            android:name=".BootReceiver"
+			android:enabled="false">
+		    <intent-filter>
+		        <action android:name="android.intent.action.BOOT_COMPLETED"></action>
+		    </intent-filter>
+		</receiver>
+    </application>
+
+</manifest>

+ 51 - 0
app/src/main/java/com/ivalentin/gm/AboutLayout.java

@@ -0,0 +1,51 @@
+package com.ivalentin.gm;
+
+import android.annotation.SuppressLint;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebView;
+
+/**
+ * Layout that show information about the app and the developer. 
+ * It's pretty much static.
+ * 
+ * @see Fragment
+ * 
+ * @author Iñigo Valentin
+ *
+ */
+public class AboutLayout extends Fragment{
+
+	/**
+	 * Run when the fragment is inflated.
+	 * Assigns views, gets the date and does the first call to the {@link populate function}.
+	 * 
+	 * @param inflater A LayoutInflater to manage views
+	 * @param container The container View
+	 * @param savedInstanceState Bundle containing the state
+	 * 
+	 * @return the fragment view
+	 * 
+	 * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
+	 */
+	@SuppressLint("InflateParams") //Throws unknown error when done properly.
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+		
+		//Load the layout.
+		View view = inflater.inflate(R.layout.fragment_layout_about, null);
+		
+		//Set the title
+		((MainActivity) getActivity()).setSectionTitle(view.getContext().getString(R.string.menu_about));
+		
+		//Set some tricky webView to show some text	.    
+	    WebView wvCode = (WebView) view.findViewById(R.id.wv_about_code);
+	    wvCode.loadData(view.getContext().getString(R.string.about_code), "text/html", "UTF-8");
+	    
+	    //Return the view itself.
+		return view;
+	}
+}

+ 171 - 0
app/src/main/java/com/ivalentin/gm/ActivityFutureLayout.java

@@ -0,0 +1,171 @@
+package com.ivalentin.gm;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebView;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.File;
+import java.util.Locale;
+
+/**
+ * Created by seavenois on 14/06/16.
+ */
+public class ActivityFutureLayout extends Fragment {
+
+    //Main View
+    private View view;
+
+    String currLang;
+
+    Context context;
+
+    @SuppressLint("InflateParams") //Throws unknown error when done properly.
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+        //Load the layout
+        view = inflater.inflate(R.layout.fragment_layout_activity_future, null);
+        context = view.getContext();
+
+        //Get bundled id
+        Bundle bundle = this.getArguments();
+        int id = bundle.getInt("activity", -1);
+        if (id == -1){
+            //TODO: Error, do something
+        }
+
+        //Get data from database
+        SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+        final Cursor cursor;
+        currLang = Locale.getDefault().getDisplayLanguage();
+        if (!currLang.equals("es") && !currLang.equals("eu")){
+            currLang = "en";
+        }
+        cursor = db.rawQuery("SELECT id, title_" + currLang+ " AS title, text_" + currLang + " AS text, date, city, price FROM activity WHERE id = " + id + ";", null);
+        cursor.moveToFirst();
+
+        //Get display elements
+        ImageView images[] = new ImageView[5];
+        images[0] = (ImageView) view.findViewById(R.id.iv_activity_future_0);
+        images[1] = (ImageView) view.findViewById(R.id.iv_activity_future_1);
+        images[2] = (ImageView) view.findViewById(R.id.iv_activity_future_2);
+        images[3] = (ImageView) view.findViewById(R.id.iv_activity_future_3);
+        images[4] = (ImageView) view.findViewById(R.id.iv_activity_future_4);
+
+        TextView tvTitle = (TextView) view.findViewById(R.id.tv_activity_future_title);
+        TextView tvDate = (TextView) view.findViewById(R.id.tv_activity_future_date);
+        TextView tvCity = (TextView) view.findViewById(R.id.tv_activity_future_city);
+        TextView tvPrice = (TextView) view.findViewById(R.id.tv_activity_future_price);
+        WebView wvText = (WebView) view.findViewById(R.id.wv_activity_future_text);
+
+        //Set fields
+        tvTitle.setText(cursor.getString(1));
+        ((MainActivity) getActivity()).setSectionTitle(cursor.getString(1));
+        wvText.loadDataWithBaseURL(null, cursor.getString(2), "text/html", "utf-8", null);
+        tvDate.setText(GM.formatDate(cursor.getString(3) + " 00:00:00", currLang, false));
+        tvPrice.setText(cursor.getString(5) + "€");
+        tvCity.setText(cursor.getString(4));
+
+        //Get images
+        Cursor imageCursor = db.rawQuery("SELECT image, idx FROM activity_image WHERE activity = " + id + " ORDER BY idx LIMIT 5;", null);
+        int i = 0;
+        while (imageCursor.moveToNext()) {
+            String image = imageCursor.getString(0);
+
+            //Check if image exists
+            File f;
+            f = new File(this.getContext().getFilesDir().toString() + "/img/actividades/preview/" + image);
+            if (f.exists()){
+                //If the image exists, set it.
+                Bitmap myBitmap = BitmapFactory.decodeFile(this.getContext().getFilesDir().toString() + "/img/actividades/preview/" + image);
+                images[i].setImageBitmap(myBitmap);
+            }
+            else {
+                //If not, create directories and download asynchronously
+                File fpath;
+                fpath = new File(this.getContext().getFilesDir().toString() + "/img/actividades/preview/");
+                fpath.mkdirs();
+                new DownloadImage(GM.SERVER + "/img/actividades/preview/" + image, this.getContext().getFilesDir().toString() + "/img/actividades/preview/" + image, images[i]).execute();
+            }
+            images[i].setVisibility(View.VISIBLE);
+            i ++;
+        }
+        imageCursor.close();
+        cursor.close();
+
+        //Get itinerary
+        Cursor cursorItinerary = db.rawQuery("SELECT id, activity_schedule.name_" + currLang + " AS name, description_" + currLang + " AS description, start, place.name_" + currLang + " AS placename, address_" + currLang + " AS address, lat, lon FROM activity_schedule, place WHERE activity_schedule.place = place.id AND activity = " + id + ";", null);
+        if (cursorItinerary.getCount() <= 0){
+            LinearLayout sch = (LinearLayout) view.findViewById(R.id.ll_activity_future_schedule);
+            sch.setVisibility(View.GONE);
+        }
+        else{
+            LinearLayout list = (LinearLayout) view.findViewById(R.id.ll_activity_future_schedule_list);
+            LinearLayout entry;
+            LayoutInflater factory = LayoutInflater.from(getActivity());
+            while (cursorItinerary.moveToNext()) {
+                //Create a new row
+                entry = (LinearLayout) factory.inflate(R.layout.row_activity_schedule, null);
+
+                //Set margins
+                //LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+                //layoutParams.setMargins(10, 10, 10, 25);
+                //entry.setLayoutParams(layoutParams);
+
+                //Set time
+                TextView tvSchTime = (TextView) entry.findViewById(R.id.tv_row_activity_itinerary_time);
+                tvSchTime.setText(cursor.getString(3).substring(11, 16));
+
+                //Set title
+                TextView tvSchTitle = (TextView) entry.findViewById(R.id.tv_row_activity_itinerary_title);
+                tvSchTitle.setText(cursor.getString(1));
+
+                //Set description
+                TextView tvSchDescription = (TextView) entry.findViewById(R.id.tv_row_activity_itinerary_description);
+                if (cursor.getString(1).equals(cursor.getString(2)) == false){
+                    tvSchDescription.setVisibility(View.GONE);
+                }
+                else {
+                    tvSchTitle.setText(cursor.getString(2));
+                }
+
+                //Set place
+                TextView tvSchPlace = (TextView) entry.findViewById(R.id.tv_row_activity_itinerary_place);
+                tvSchPlace.setText(cursor.getString(4));
+
+                //Set address
+                TextView tvSchAddress = (TextView) entry.findViewById(R.id.tv_row_activity_itinerary_address);
+                if (cursor.getString(4).equals(cursor.getString(5)) == false){
+                    tvSchAddress.setVisibility(View.GONE);
+                }
+                else {
+                    tvSchAddress.setText(cursor.getString(5));
+                }
+
+                //TODO: Add an onclick listener on image that shows a map
+
+                list.addView(entry);
+            }
+        }
+
+
+        cursorItinerary.close();
+        db.close();
+        return view;
+    }
+}

+ 266 - 0
app/src/main/java/com/ivalentin/gm/ActivityLayout.java

@@ -0,0 +1,266 @@
+package com.ivalentin.gm;
+
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.text.Html;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.io.File;
+import java.util.Locale;
+
+/**
+ * Created by seavenois on 09/06/16.
+ */
+public class ActivityLayout extends Fragment{
+
+    //Main View
+    private View view;
+
+    /**
+     * Run when the fragment is inflated.
+     * Assigns views, gets the date and does the first call to the {@link #populate} function.
+     *
+     * @param inflater A LayoutInflater to manage views
+     * @param container The container View
+     * @param savedInstanceState Bundle containing the state
+     *
+     * @return The fragment view
+     *
+     * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
+     */
+    @SuppressLint("InflateParams") //Throws unknown error when done properly.
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+        //Load the layout
+        view = inflater.inflate(R.layout.fragment_layout_activities, null);
+
+        //Set the title
+        ((MainActivity) getActivity()).setSectionTitle(view.getContext().getString(R.string.menu_activities));
+
+        populate();
+        return view;
+    }
+
+    /**
+     * Populates the list of activities.
+     * It uses the default layout as parent.
+     */
+    public void populate(){
+        LinearLayout llListFuture = (LinearLayout) view.findViewById(R.id.ll_activities_future_list);
+        LinearLayout llListPast = (LinearLayout) view.findViewById(R.id.ll_activities_past_list);
+        LinearLayout entry;
+
+        //An inflater
+        LayoutInflater factory = LayoutInflater.from(getActivity());
+
+        SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+        final Cursor cursor;
+        String currLang = Locale.getDefault().getDisplayLanguage();
+        if (!currLang.equals("es") && !currLang.equals("eu")){
+            currLang = "en";
+        }
+
+        //Get data from the database of the future activities
+        cursor = db.rawQuery("SELECT id, date, city, title_" + currLang+ " AS title, text_" + currLang + " AS text, price FROM activity WHERE date >= date('now') ORDER BY date DESC;", null);
+        if (cursor.getCount() > 0) {
+            TextView tvNoFuture = (TextView) view.findViewById(R.id.tv_activities_no_future);
+            tvNoFuture.setVisibility(View.GONE);
+
+            //Print rows
+            while (cursor.moveToNext()) {
+                //Create a new row
+                entry = (LinearLayout) factory.inflate(R.layout.row_activity_future, null);
+
+                //Set margins
+                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+                layoutParams.setMargins(10, 10, 10, 25);
+                entry.setLayoutParams(layoutParams);
+
+                //Set title
+                TextView tvTitle = (TextView) entry.findViewById(R.id.tv_row_activity_future_title);
+                tvTitle.setText(cursor.getString(3));
+
+                //Set city
+                TextView tvCity = (TextView) entry.findViewById(R.id.tv_row_activity_future_city);
+                tvCity.setText(cursor.getString(2));
+
+                //Set price
+                TextView tvPrice = (TextView) entry.findViewById(R.id.tv_row_activity_future_price);
+                tvPrice.setText(cursor.getString(5) + "€");
+
+                //Set text
+                String text = Html.fromHtml(cursor.getString(4)).toString();
+                if (text.length() > 180) {
+                    text = text.substring(0, 180) + "...";
+                }
+                TextView tvText = (TextView) entry.findViewById(R.id.tv_row_activity_future_text);
+                tvText.setText(text);
+
+                //Set date
+                TextView tvDate = (TextView) entry.findViewById(R.id.tv_row_activity_future_date);
+                tvDate.setText(GM.formatDate(cursor.getString(1) + " 00:00:00", currLang, false));
+
+                //Set hidden id
+                TextView tvId = (TextView) entry.findViewById(R.id.tv_row_activity_future_hidden);
+                tvId.setText(cursor.getString(0));
+
+                //Get image
+                ImageView iv = (ImageView) entry.findViewById(R.id.iv_row_activity_future);
+                Cursor cursorImage = db.rawQuery("SELECT image FROM activity_image WHERE activity = " + cursor.getString(0) + " ORDER BY idx LIMIT 1;", null);
+                if (cursorImage.getCount() > 0) {
+                    cursorImage.moveToFirst();
+                    String image = cursorImage.getString(0);
+
+                    //Check if image exists
+                    File f;
+                    f = new File(this.getContext().getFilesDir().toString() + "/img/actividades/miniature/" + image);
+                    if (f.exists()) {
+                        //If the image exists, set it.
+                        Bitmap myBitmap = BitmapFactory.decodeFile(this.getContext().getFilesDir().toString() + "/img/actividades/miniature/" + image);
+                        iv.setImageBitmap(myBitmap);
+                    } else {
+                        //If not, create directories and download asynchronously
+                        File fpath;
+                        fpath = new File(this.getContext().getFilesDir().toString() + "/img/actividades/miniature/");
+                        fpath.mkdirs();
+                        new DownloadImage(GM.SERVER + "/img/actividades/miniature/" + image, this.getContext().getFilesDir().toString() + "/img/actividades/miniature/" + image, iv).execute();
+                    }
+                }
+
+                //Set onCLickListener
+                entry.setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        //Toast.makeText(getActivity(), "OPENING POST", Toast.LENGTH_LONG).show();
+                        Fragment fragment = new ActivityFutureLayout();
+                        Bundle bundle = new Bundle();
+                        //Pass post id
+                        int id = Integer.parseInt(((TextView) v.findViewById(R.id.tv_row_activity_future_hidden)).getText().toString());
+                        bundle.putInt("activity", id);
+                        fragment.setArguments(bundle);
+
+                        FragmentManager fm = ActivityLayout.this.getActivity().getSupportFragmentManager();
+                        FragmentTransaction ft = fm.beginTransaction();
+
+                        ft.replace(R.id.activity_main_content_fragment, fragment);
+                        ft.addToBackStack("activity_" + id);
+                        ft.commit();
+                    }
+                });
+
+                //Add to the list
+                llListFuture.addView(entry);
+            }
+            cursor.close();
+
+        }
+
+        //Get data from the database of the past activities
+        Cursor cursorPast = db.rawQuery("SELECT id, date, city, title_" + currLang + " AS title, text_" + currLang + " AS text, after_" + currLang + " AS after FROM activity WHERE date < date('now') ORDER BY date DESC;", null);
+
+
+        //Print rows
+        while (cursorPast.moveToNext()) {
+            //Create a new row
+            entry = (LinearLayout) factory.inflate(R.layout.row_activity_past, null);
+
+            //Set margins
+            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+            layoutParams.setMargins(10, 10, 10, 25);
+            entry.setLayoutParams(layoutParams);
+
+            //Set title
+            TextView tvTitle = (TextView) entry.findViewById(R.id.tv_row_activity_past_title);
+            tvTitle.setText(cursorPast.getString(3));
+
+            //Set text
+            String text;
+            if (cursorPast.getString(5).length() < 1){
+                text = Html.fromHtml(cursorPast.getString(4)).toString();
+            }
+            else{
+                text = Html.fromHtml(cursorPast.getString(5)).toString();
+            }
+            if (text.length() > 130) {
+                text = text.substring(0, 130) + "...";
+            }
+            TextView tvText = (TextView) entry.findViewById(R.id.tv_row_activity_past_text);
+            tvText.setText(text);
+
+            //Set date
+            TextView tvDate = (TextView) entry.findViewById(R.id.tv_row_activity_past_date);
+            tvDate.setText(GM.formatDate(cursorPast.getString(1) + " 00:00:00", currLang, false));
+
+            //Set hidden id
+            TextView tvId = (TextView) entry.findViewById(R.id.tv_row_activity_past_hidden);
+            tvId.setText(cursorPast.getString(0));
+
+            //Get image
+            ImageView iv = (ImageView) entry.findViewById(R.id.iv_row_activity_past);
+            Cursor cursorImage = db.rawQuery("SELECT image FROM activity_image WHERE activity = " + cursorPast.getString(0) + " ORDER BY idx LIMIT 1;", null);
+            if (cursorImage.getCount() > 0) {
+                cursorImage.moveToFirst();
+                String image = cursorImage.getString(0);
+
+                //Check if image exists
+                File f;
+                f = new File(this.getContext().getFilesDir().toString() + "/img/actividades/miniature/" + image);
+                if (f.exists()) {
+                    //If the image exists, set it.
+                    Bitmap myBitmap = BitmapFactory.decodeFile(this.getContext().getFilesDir().toString() + "/img/actividades/miniature/" + image);
+                    iv.setImageBitmap(myBitmap);
+                } else {
+                    //If not, create directories and download asynchronously
+                    File fpath;
+                    fpath = new File(this.getContext().getFilesDir().toString() + "/img/actividades/miniature/");
+                    fpath.mkdirs();
+                    new DownloadImage(GM.SERVER + "/img/actividades/miniature/" + image, this.getContext().getFilesDir().toString() + "/img/actividades/miniature/" + image, iv).execute();
+                }
+            }
+
+            //Set onCLickListener
+            entry.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                //Toast.makeText(getActivity(), "OPENING POST", Toast.LENGTH_LONG).show();
+                Fragment fragment = new ActivityPastLayout();
+                Bundle bundle = new Bundle();
+                //Pass post id
+                int id = Integer.parseInt(((TextView) v.findViewById(R.id.tv_row_activity_past_hidden)).getText().toString());
+                bundle.putInt("activity", id);
+                fragment.setArguments(bundle);
+
+                FragmentManager fm = ActivityLayout.this.getActivity().getSupportFragmentManager();
+                FragmentTransaction ft = fm.beginTransaction();
+
+                ft.replace(R.id.activity_main_content_fragment, fragment);
+                ft.addToBackStack("activity_" + id);
+                ft.commit();
+                }
+            });
+
+            //Add to the list
+            llListPast.addView(entry);
+        }
+        cursorPast.close();
+        db.close();
+
+
+
+    }
+}

+ 118 - 0
app/src/main/java/com/ivalentin/gm/ActivityPastLayout.java

@@ -0,0 +1,118 @@
+package com.ivalentin.gm;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebView;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.File;
+import java.util.Locale;
+
+/**
+ * Created by seavenois on 14/06/16.
+ */
+public class ActivityPastLayout extends Fragment {
+
+    //Main View
+    private View view;
+
+    String currLang;
+
+    Context context;
+
+    @SuppressLint("InflateParams") //Throws unknown error when done properly.
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+        //Load the layout
+        view = inflater.inflate(R.layout.fragment_layout_activity_past, null);
+        context = view.getContext();
+
+        //Get bundled id
+        Bundle bundle = this.getArguments();
+        int id = bundle.getInt("activity", -1);
+        if (id == -1){
+            //TODO: Error, do something
+        }
+
+        //Get data from database
+        SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+        final Cursor cursor;
+        currLang = Locale.getDefault().getDisplayLanguage();
+        if (!currLang.equals("es") && !currLang.equals("eu")){
+            currLang = "en";
+        }
+        cursor = db.rawQuery("SELECT id, title_" + currLang+ " AS title, text_" + currLang + " AS text, date, city, after_" + currLang + " AS after FROM activity WHERE id = " + id + ";", null);
+        cursor.moveToFirst();
+
+        //Get display elements
+        ImageView images[] = new ImageView[5];
+        images[0] = (ImageView) view.findViewById(R.id.iv_activity_past_0);
+        images[1] = (ImageView) view.findViewById(R.id.iv_activity_past_1);
+        images[2] = (ImageView) view.findViewById(R.id.iv_activity_past_2);
+        images[3] = (ImageView) view.findViewById(R.id.iv_activity_past_3);
+        images[4] = (ImageView) view.findViewById(R.id.iv_activity_past_4);
+
+        TextView tvTitle = (TextView) view.findViewById(R.id.tv_activity_past_title);
+        TextView tvDate = (TextView) view.findViewById(R.id.tv_activity_past_date);
+        TextView tvCity = (TextView) view.findViewById(R.id.tv_activity_past_city);
+        WebView wvText = (WebView) view.findViewById(R.id.wv_activity_past_text);
+
+        //Set fields
+        tvTitle.setText(cursor.getString(1));
+        ((MainActivity) getActivity()).setSectionTitle(cursor.getString(1));
+        if (cursor.getString(5).length() < 1) {
+            wvText.loadDataWithBaseURL(null, cursor.getString(2), "text/html", "utf-8", null);
+        }
+        else{
+            wvText.loadDataWithBaseURL(null, cursor.getString(5), "text/html", "utf-8", null);
+        }
+        tvDate.setText(GM.formatDate(cursor.getString(3) + " 00:00:00", currLang, false));
+        tvCity.setText(cursor.getString(4));
+
+        //Get images
+        Cursor imageCursor = db.rawQuery("SELECT image, idx FROM activity_image WHERE activity = " + id + " ORDER BY idx LIMIT 5;", null);
+        //imageCursor.moveToFirst();
+        int i = 0;
+        while (imageCursor.moveToNext()) {
+            String image = imageCursor.getString(0);
+
+            //Check if image exists
+            File f;
+            f = new File(this.getContext().getFilesDir().toString() + "/img/actividades/preview/" + image);
+            if (f.exists()){
+                //If the image exists, set it.
+                Bitmap myBitmap = BitmapFactory.decodeFile(this.getContext().getFilesDir().toString() + "/img/actividades/preview/" + image);
+                images[i].setImageBitmap(myBitmap);
+            }
+            else {
+                //If not, create directories and download asynchronously
+                File fpath;
+                fpath = new File(this.getContext().getFilesDir().toString() + "/img/actividades/preview/");
+                fpath.mkdirs();
+                new DownloadImage(GM.SERVER + "/img/actividades/preview/" + image, this.getContext().getFilesDir().toString() + "/img/actividades/preview/" + image, images[i]).execute();
+            }
+            images[i].setVisibility(View.VISIBLE);
+            i ++;
+        }
+        imageCursor.close();
+
+        cursor.close();
+        db.close();
+        return view;
+    }
+}

+ 231 - 0
app/src/main/java/com/ivalentin/gm/AlarmReceiver.java

@@ -0,0 +1,231 @@
+package com.ivalentin.gm;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import android.app.AlarmManager;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.graphics.BitmapFactory;
+import android.media.RingtoneManager;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.TaskStackBuilder;
+import android.support.v4.content.WakefulBroadcastReceiver;
+import android.util.Log;
+
+/**
+ * Manages alarms to perform actions in the background, such as sync and receive notifications.
+ * 
+ * @see WakefulBroadcastReceiver
+ * 
+ * @author Iñigo Valentin
+ *
+ */
+public class AlarmReceiver extends WakefulBroadcastReceiver {
+	
+    // The app's AlarmManager, which provides access to the system alarm services.
+    private AlarmManager alarmMgr;
+    
+    // The pending intent that is triggered when the alarm fires.
+    private PendingIntent alarmIntent;
+  
+    /**
+     * Actions to be performed when an alarm is received. 
+     * Performs a full sync, and gets the pending notifications.
+     * 
+     * @param context Context of the activity or application
+     * @param intent Receiver intent
+     * 
+     * @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)
+     */
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        
+    	Log.d("Alarm", "Received");
+    	
+    	//Synchronize database. //TODO: I don't think i need this here.
+    	//new Sync(context).execute();
+
+		//The received web page, line by line.
+		List<String> output = null;
+		
+		//Boolean that will prevent the process to go on if something goes wrong.
+		boolean success = true;
+		    	
+		//Open the preferences to be available several times later.
+		SharedPreferences settings = context.getSharedPreferences(GM.PREF, Context.MODE_PRIVATE);
+		
+		FetchURL fu;
+		
+		//Check if the user wants to receive notifications
+		if (settings.getInt(GM.PREF_NOTIFICATION , GM.DEFAULT_PREF_NOTIFICATION) == 1){
+			success = true;
+			
+			//Get the file
+			try{
+				fu = new FetchURL();
+				fu.Run(GM.SERVER + "/app/notifications.php");
+				Log.d("Alarm", "Fetched notifications");
+
+				//Parse info
+				String o = fu.getOutput().toString();
+				while (o.indexOf("<notification>") != -1){
+					//Get non-language-dependant fields
+					String notification = o.substring(o.indexOf("<notification>") + 14, o.indexOf("</notification>"));
+					String id = notification.substring(notification.indexOf("<id>") + 4, notification.indexOf("</id>"));
+					String action = notification.substring(notification.indexOf("<id>") + 4, notification.indexOf("</id>"));
+
+					//Is the notification seen already?
+					if(settings.getBoolean(GM.NOTIFICATION_SEEN_ + id, false) == false){
+
+						//If not, get language dependant values
+						String currLang = Locale.getDefault().getDisplayLanguage();
+						String text, title;
+						switch (currLang){
+							case "es":
+								title = notification.substring(notification.indexOf("<title_es>") + 10, notification.indexOf("</title_es>"));
+								text = notification.substring(notification.indexOf("<text_es>") + 9, notification.indexOf("</text_es>"));
+								break;
+							case "eu":
+								title = notification.substring(notification.indexOf("<title_eu>") + 10, notification.indexOf("</title_eu>"));
+								text = notification.substring(notification.indexOf("<text_eu>") + 9, notification.indexOf("</text_eu>"));
+								break;
+							default:
+								title = notification.substring(notification.indexOf("<title_en>") + 10, notification.indexOf("</title_en>"));
+								text = notification.substring(notification.indexOf("<text_en>") + 9, notification.indexOf("</text_en>"));
+								break;
+						}
+
+						//Get the notification manager ready
+						NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+
+						//Variables to create intents for each notification
+						Intent resultIntent;
+						TaskStackBuilder stackBuilder;
+
+						//Send the notification.
+						NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
+								.setSmallIcon(R.drawable.ic_notification)
+								.setContentTitle(title)
+								.setAutoCancel(true)
+								.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher))
+								.setVibrate((new long[] { 400, 400, 400}))
+								.setColor(context.getResources().getColor(R.color.background_notification))
+								.setSubText(context.getString(R.string.app_name))
+								.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
+								.setContentText(text);
+
+						// Creates an intent for an Activity to be launched from the notification.
+						resultIntent = new Intent(context, MainActivity.class);
+						resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+
+						//Set extras depending on type.
+						resultIntent.putExtra(GM.EXTRA_TEXT, text);
+						resultIntent.putExtra(GM.EXTRA_TITLE, title);
+						resultIntent.putExtra(GM.EXTRA_ACTION, action);
+
+						//Add the intent to the notification.
+						stackBuilder = TaskStackBuilder.create(context);
+						stackBuilder.addParentStack(MainActivity.class);
+
+						// Adds the Intent that starts the Activity to the top of the stack.
+						stackBuilder.addNextIntent(resultIntent);
+						PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
+						mBuilder.setContentIntent(resultPendingIntent);
+
+						//Actually send the notification.
+						mNotificationManager.notify(Integer.parseInt(id), mBuilder.build());
+
+						//Mark as notified
+						SharedPreferences.Editor editor = settings.edit();
+						editor.putBoolean(GM.NOTIFICATION_SEEN_ + id, true);
+						editor.commit();
+					}
+				o = o.substring(o.indexOf("</notification>") + 15);
+				}
+			}
+			catch(Exception ex) {
+				Log.e("Notification error", "Error fetching remote file: " + ex.toString());
+				success = false;
+			}
+    	}
+		
+		//Get location
+		boolean result = false;
+		fu = new FetchURL();
+		fu.Run(GM.SERVER + "/app/location.php");
+		String lat = "", lon = "";
+		output = fu.getOutput();
+		Log.d("Alarm", "Fetched location");
+		for(int i = 0; i < output.size(); i++){
+			if (output.get(i).length() >= 25){
+				if (output.get(i).substring(0, 25).equals("<location>none</location>"))
+					result = false;
+			}
+			if (output.get(i).length() >= 6){
+				if (output.get(i).substring(0, 5).equals("<lat>")){
+					lat = output.get(i).substring(5, output.get(i).length()-6);
+					result = true;
+				}
+				if (output.get(i).substring(0, 5).equals("<lon>")){
+					lon = output.get(i).substring(5, output.get(i).length()-6);
+					result = true;
+				}
+			}
+		}
+		if (result){
+			SharedPreferences.Editor editor = settings.edit();
+	    	editor.putString(GM.PREF_GM_LATITUDE, lat);
+	    	editor.putString(GM.PREF_GM_LONGITUDE, lon);
+	    	DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
+	    	Date date = new Date();
+	    	editor.putString(GM.PREF_GM_LOCATION, dateFormat.format(date));
+	    	editor.commit();
+		}
+    }
+
+    /**
+     * Sets a repeating alarm. 
+     * When the alarm fires, the app broadcasts an Intent to this WakefulBroadcastReceiver.
+     * @param context The context of the app
+     */
+    public void setAlarm(Context context) {
+        alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
+        Intent intent = new Intent(context, AlarmReceiver.class);
+        alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
+        
+        //Set the alarm cycle.
+        alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, GM.PERIOD_SYNC, GM.PERIOD_SYNC, alarmIntent);
+        
+        // Enable SampleBootReceiver to automatically restart the alarm when the device is rebooted.
+        ComponentName receiver = new ComponentName(context, BootReceiver.class);
+        PackageManager pm = context.getPackageManager();
+        pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);           
+    }
+
+    /**
+     * Cancels the alarm.
+     * @param context
+     */
+    public void cancelAlarm(Context context) {
+    	
+        // If the alarm has been set, cancel it.
+        if (alarmMgr!= null) 
+            alarmMgr.cancel(alarmIntent);
+        
+        //Disable SampleBootReceiver so that it doesn't automatically restart the alarm when the device is rebooted.
+        ComponentName receiver = new ComponentName(context, BootReceiver.class);
+        PackageManager pm = context.getPackageManager();
+
+        pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
+    }
+    
+}

+ 161 - 0
app/src/main/java/com/ivalentin/gm/AlbumLayout.java

@@ -0,0 +1,161 @@
+package com.ivalentin.gm;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebView;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.io.File;
+import java.util.Locale;
+
+/**
+ * Created by seavenois on 14/06/16.
+ */
+public class AlbumLayout extends Fragment {
+
+    //Main View
+    private View view;
+
+    String currLang;
+
+    Context context;
+
+    @SuppressLint("InflateParams") //Throws unknown error when done properly.
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+        //Load the layout
+        view = inflater.inflate(R.layout.fragment_layout_album, null);
+        context = view.getContext();
+
+        //Get bundled id
+        Bundle bundle = this.getArguments();
+        int id = bundle.getInt("album", -1);
+        if (id == -1){
+            //TODO: Error, do something
+        }
+
+        //Get data from database
+        SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+        final Cursor cursor;
+        currLang = Locale.getDefault().getDisplayLanguage();
+        if (!currLang.equals("es") && !currLang.equals("eu")){
+            currLang = "en";
+        }
+        cursor = db.rawQuery("SELECT id, name_" + currLang + " AS name, description_" + currLang + " AS description FROM album WHERE id = " + id + ";", null);
+        cursor.moveToFirst();
+
+        //Set album elements
+        TextView tvTitle = (TextView) view.findViewById(R.id.tv_album_title);
+        TextView tvDescription = (TextView) view.findViewById(R.id.tv_album_description);
+        tvTitle.setText(cursor.getString(1));
+        if (cursor.getString(2).length() < 1){
+            tvDescription.setVisibility(View.GONE);
+        }
+        else {
+            tvDescription.setText(cursor.getString(2));
+        }
+        cursor.close();
+
+
+
+
+
+        //Assign elements
+        LinearLayout llList = (LinearLayout) view.findViewById(R.id.ll_album_list);
+        LinearLayout entry;
+
+        //An inflater
+        LayoutInflater factory = LayoutInflater.from(getActivity());
+
+        String image;
+        Cursor imageCursor = db.rawQuery("SELECT id, title_" + currLang + " AS title, file, width, height FROM photo, photo_album WHERE photo = id AND album = " + id + " ORDER BY uploaded DESC;", null);
+        while (imageCursor.moveToNext()){
+            //Create a new row
+            entry = (LinearLayout) factory.inflate(R.layout.row_album, null);
+
+            //Set margins
+            //LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+            //layoutParams.setMargins(10, 10, 10, 25);
+            //entry.setLayoutParams(layoutParams);
+
+            //Set title
+            TextView tvTitleLeft = (TextView) entry.findViewById(R.id.tv_row_album_title_left);
+            tvTitleLeft.setText(imageCursor.getString(1));
+
+            //Set id
+            TextView tvHiddenLeft = (TextView) entry.findViewById(R.id.tv_row_album_hidden_left);
+            tvHiddenLeft.setText(imageCursor.getString(0));
+
+            //Set image
+            ImageView ivLeft = (ImageView) entry.findViewById(R.id.iv_row_album_left);
+            image = imageCursor.getString(2);
+            //Check if image exists
+            File f;
+            f = new File(this.getContext().getFilesDir().toString() + "/img/galeria/preview/" + image);
+            if (f.exists()){
+                //If the image exists, set it.
+                Bitmap myBitmap = BitmapFactory.decodeFile(this.getContext().getFilesDir().toString() + "/img/galeria/preview/" + image);
+                ivLeft.setImageBitmap(myBitmap);
+            }
+            else {
+                //If not, create directories and download asynchronously
+                File fpath;
+                fpath = new File(this.getContext().getFilesDir().toString() + "/img/galeria/preview/");
+                fpath.mkdirs();
+                new DownloadImage(GM.SERVER + "/img/galeria/preview/" + image, this.getContext().getFilesDir().toString() + "/img/galeria/preview/" + image, ivLeft).execute();
+            }
+            
+            //If odd pass, to the right line
+            if (imageCursor.moveToNext()){
+
+                LinearLayout llRight = (LinearLayout) entry.findViewById(R.id.ll_row_album_right);
+                llRight.setVisibility(View.VISIBLE);
+
+                //Set title
+                TextView tvTitleRight = (TextView) entry.findViewById(R.id.tv_row_album_title_right);
+                tvTitleRight.setText(imageCursor.getString(1));
+
+                //Set id
+                TextView tvHiddenRight = (TextView) entry.findViewById(R.id.tv_row_album_hidden_right);
+                tvHiddenRight.setText(imageCursor.getString(0));
+
+                //Set image
+                ImageView ivRight = (ImageView) entry.findViewById(R.id.iv_row_album_right);
+                image = imageCursor.getString(2);
+                //Check if image exists
+                f = new File(this.getContext().getFilesDir().toString() + "/img/galeria/preview/" + image);
+                if (f.exists()){
+                    //If the image exists, set it.
+                    Bitmap myBitmap = BitmapFactory.decodeFile(this.getContext().getFilesDir().toString() + "/img/galeria/preview/" + image);
+                    ivRight.setImageBitmap(myBitmap);
+                }
+                else {
+                    //If not, create directories and download asynchronously
+                    File fpath;
+                    fpath = new File(this.getContext().getFilesDir().toString() + "/img/galeria/preview/");
+                    fpath.mkdirs();
+                    new DownloadImage(GM.SERVER + "/img/galeria/preview/" + image, this.getContext().getFilesDir().toString() + "/img/galeria/preview/" + image, ivRight).execute();
+                }
+            }
+
+            llList.addView(entry);
+        }
+
+        imageCursor.close();
+        db.close();
+        return view;
+    }
+}

+ 677 - 0
app/src/main/java/com/ivalentin/gm/AroundLayout.java

@@ -0,0 +1,677 @@
+package com.ivalentin.gm;
+
+import java.text.DecimalFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Locale;
+
+import com.google.android.gms.maps.CameraUpdate;
+import com.google.android.gms.maps.CameraUpdateFactory;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.MapView;
+import com.google.android.gms.maps.MapsInitializer;
+import com.google.android.gms.maps.OnMapReadyCallback;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.MarkerOptions;
+
+import android.annotation.SuppressLint;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.DialogInterface.OnCancelListener;
+import android.content.DialogInterface.OnShowListener;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.drawable.Drawable;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.content.res.ResourcesCompat;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * Layout that show event close to the user in both time and space. 
+ * It implements LocationListener so it can detect changes in the user location. 
+ * It implements OnMapReadyCallback so a map can be shown when an item is clicked.
+ * 
+ * @see Fragment
+ * @see LocationListener
+ * @see OnMapReadyCallback
+ * 
+ * @author Iñigo Valentin
+ *
+ */
+public class AroundLayout extends Fragment implements LocationListener, OnMapReadyCallback{
+
+	//The location of the user
+	private double[] coordinates = new double[2];
+	
+	//LocationManager to provide the location
+	private LocationManager locationManager;
+	
+	//The location provider
+	private String provider;
+	
+	//Layout where event rows will be added
+	private LinearLayout list;
+	
+	//Layout to be shown when no GPS detected
+	private LinearLayout noGps;
+	
+	//Layout to be shown when no events
+	private LinearLayout noEvents;
+	
+	//Main View
+	private View view;
+	
+	//Map stuff for the dialog
+	private MapView mapView;
+	private Bundle bund;
+	private GoogleMap map;
+	private LatLng location;
+	private String markerName = "";
+
+	/**
+	 * Remove the location listener updates when Activity is paused.
+	 * 
+	 * @see android.support.v4.app.Fragment#onPause()
+	 */
+	@Override
+	public void onPause() {
+		if (map != null)
+			map.setMyLocationEnabled(false);
+		if (mapView != null){
+			mapView.onPause();
+		}
+		super.onPause();
+		locationManager.removeUpdates(this);
+	}
+	
+	/**
+	 * Run when the fragment is inflated.
+	 * Assigns views, gets the date and does the first call to the {@link populate function}.
+	 * 
+	 * @param inflater A LayoutInflater to manage views
+	 * @param container The container View
+	 * @param savedInstanceState Bundle containing the state
+	 * 
+	 * @return The fragment view
+	 * 
+	 * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
+	 */
+	@SuppressLint("InflateParams") //Throws unknown error when done properly.
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+		
+		//Load the layout
+		view = inflater.inflate(R.layout.fragment_layout_around, null);		
+		
+		//Set the title
+		((MainActivity) getActivity()).setSectionTitle(view.getContext().getString(R.string.menu_lablanca_around));
+		
+		//Get the location passed from MainActivity so we don't have to wait for it to be acquired.
+		Bundle bundle = this.getArguments();
+		coordinates[0] = bundle.getDouble("lat", 0);
+		coordinates[1] = bundle.getDouble("lon", 0);
+		
+		//Assign parent layout
+		list = (LinearLayout) view.findViewById(R.id.ll_around_list);
+		noGps = (LinearLayout) view.findViewById(R.id.ll_around_no_gps);
+		noEvents = (LinearLayout) view.findViewById(R.id.ll_around_no_events);
+		
+		//"Open Settings" button, shown when GPS is off.
+		Button btSettings = (Button) view.findViewById(R.id.bt_around_no_gps);
+		btSettings.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				view.getContext().startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS));
+			}
+		});
+		
+		//"View Schedule" button, shown when no events.
+		Button btSchedule = (Button) view.findViewById(R.id.bt_around_no_events);
+		btSchedule.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				((MainActivity) getActivity()).loadSection(GM.SECTION_LABLANCA_SCHEDULE, false);
+			}
+			
+		});
+		
+		//Set Location manager.
+		locationManager = (LocationManager) view.getContext().getSystemService(Context.LOCATION_SERVICE);
+		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 5, this);
+		
+		//Show and hide sections depending on the GPS status.
+		if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
+			//Populate the activity list
+			list.setVisibility(View.VISIBLE);
+			noGps.setVisibility(View.GONE);
+			populateAround(list);
+		}
+		else{
+			list.setVisibility(View.GONE);
+			noGps.setVisibility(View.VISIBLE);
+		}
+						
+		//Return the fragment view
+		return view;
+	}
+	
+	/**
+	 * Populates the list of activities around. 
+	 * It uses the default layout as parent.
+	 */
+	public void populateAround(){
+		LinearLayout list = (LinearLayout) this.getView().findViewById(R.id.ll_around_list);
+		populateAround(list);
+	}
+	
+	/**
+	 * Populates the list of activities around.
+	 * 
+	 * @param list The layout where the event will be placed.
+	 */
+	@SuppressLint("InflateParams") //Views are added from a loop: I can't specify the parent when inflating.
+	private void populateAround(LinearLayout list){
+		
+		//A list of events.
+		ArrayList<Event> eventList = new ArrayList<Event>();
+		Event event;
+		
+		//A layout to be populated with an event.
+		LinearLayout entry;
+		
+		//Touchable layout of each entry
+		LinearLayout llTouch;
+		
+		//An inflater
+        LayoutInflater factory = LayoutInflater.from(view.getContext());
+        
+        //TextViews in each row
+        TextView tvRowTitle, tvRowDescription, tvRowAddress, tvRowDistance, tvRowTime, tvRowId;
+        
+        //Icon next to the location text
+        Drawable icon = ResourcesCompat.getDrawable(getResources(), R.drawable.pinpoint, null);
+        icon.setBounds(0, 0, 80, 80);
+				
+		//Read from database
+		SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+		Cursor cursor = db.rawQuery("SELECT schedule, gm, event.name, event.description, place.name, address, lat, lon, start, end, host, event.id FROM event, place WHERE schedule = 1 AND event.place = place.id;", null);
+		
+		//Make the list empty, in case we are not populating it for the first time.
+        list.removeAllViews();
+        
+        //Elements to parse, format and calculate times.
+        Calendar cal;
+		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
+		SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.US);
+		SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd-", Locale.US);
+		Date date = new Date();
+		Date startMinus30, endMinus15, startPlus30;
+		
+		//Decimal formatter to write text
+		DecimalFormat df = new DecimalFormat("#.#");
+		
+		//Holds the distance between the user and the event
+		double distance;
+        
+        
+        //Loop thorough every returned row, creating an event for each suitable row.
+        while (cursor.moveToNext()){
+        	
+        	//Operate with dates to see if the event close in time.       	
+        	try{
+				cal = Calendar.getInstance();
+			    cal.setTime(dateFormat.parse(cursor.getString(8)));
+			    cal.add(Calendar.MINUTE, -30);
+			    startMinus30 = cal.getTime();
+			    cal = Calendar.getInstance();
+			    cal.setTime(dateFormat.parse(cursor.getString(8)));
+			    cal.add(Calendar.MINUTE, 30);
+			    startPlus30 = cal.getTime();
+			    
+			    //Events with end date
+			    if (cursor.getString(9) != null){
+			    	cal = Calendar.getInstance();
+				    cal.setTime(dateFormat.parse(cursor.getString(9)));
+				    cal.add(Calendar.MINUTE, -15);
+				    endMinus15 = cal.getTime();
+				    
+				    //If in range
+				    if (date.after(startMinus30) && date.before(endMinus15)){
+				    	event = new Event(cursor.getInt(11), cursor.getString(2), cursor.getString(3), cursor.getInt(1), cursor.getInt(0), cursor.getString(4), cursor.getString(10), new double[] {cursor.getDouble(6), cursor.getDouble(7)}, cursor.getString(8), cursor.getString(9));
+			        	eventList.add(event);
+				    }
+			    }
+			    //Events without end time
+			    else{
+			    	if (date.after(startMinus30) && date.before(startPlus30)){
+			    		event = new Event(cursor.getInt(11), cursor.getString(2), cursor.getString(3), cursor.getInt(1), cursor.getInt(0), cursor.getString(4), cursor.getString(10), new double[] {cursor.getDouble(6), cursor.getDouble(7)}, cursor.getString(8), cursor.getString(9));
+			        	eventList.add(event);
+			    	}
+			    }
+				
+			}
+			catch (ParseException e){
+				Log.e("Error parsing date for around event", e.toString());
+			}
+        }
+        
+        //Close the cursor and the database
+        cursor.close();
+        db.close();
+        
+        //Sort the event list.
+        Collections.sort(eventList);
+        
+        //Loop events in the list.
+        if (eventList.size() == 0){
+        	//If no events around
+        	list.setVisibility(View.GONE);
+        	noEvents.setVisibility(View.VISIBLE);
+        }
+        else{
+        	//If there are events being hold now or close in time.
+        	list.setVisibility(View.VISIBLE);
+        	noEvents.setVisibility(View.GONE);
+        	
+        	//Loop events
+	        for(int i = 0; i < eventList.size(); i++){
+	        	
+	        	//Create a new row
+	        	entry = (LinearLayout) factory.inflate(R.layout.row_around, null);
+	        	
+	        	//Set id
+	        	tvRowId = (TextView) entry.findViewById(R.id.tv_row_around_id);
+	        	tvRowId.setText(Integer.toString(eventList.get(i).getId()));
+	        	
+	        	//Set title
+	        	tvRowTitle = (TextView) entry.findViewById(R.id.tv_row_around_title);
+	        	tvRowTitle.setText(eventList.get(i).getName());
+	        	
+	        	//Set description
+	        	tvRowDescription = (TextView) entry.findViewById(R.id.tv_row_around_description);
+	        	tvRowDescription.setText(eventList.get(i).getDescription());
+	        	
+	        	//Set address
+	        	tvRowAddress = (TextView) entry.findViewById(R.id.tv_row_around_address);
+	        	tvRowAddress.setText(eventList.get(i).getPlace());
+	        	
+	        	//Set distance
+	        	tvRowDistance = (TextView) entry.findViewById(R.id.tv_row_around_distance);
+	        	distance = eventList.get(i).getDistance(coordinates);
+	        	if (distance < 1000){
+	        		tvRowDistance.setText(String.format(getResources().getString(R.string.around_distance), Math.round(distance), getResources().getString(R.string.meters), Math.round(distance * 0.012)));
+	        	}
+	        	else
+	        		tvRowDistance.setText(String.format(getResources().getString(R.string.around_distance), df.format(distance / 1000), getResources().getString(R.string.kilometers), Math.round(distance * 0.012)));
+	        	
+	        	//Set time
+	        	tvRowTime = (TextView) entry.findViewById(R.id.tv_row_around_time);
+	        	Date tm;
+				try {
+					tm = eventList.get(i).getStart();
+					if (dayFormat.format(tm).equals(dayFormat.format(date)))
+		        		tvRowTime.setText(view.getContext().getString(R.string.today) + " " + timeFormat.format(tm));
+		        	else
+		        		tvRowTime.setText(view.getContext().getString(R.string.tomorrow) + " " + timeFormat.format(tm));
+				}
+				catch (Exception e) {
+					Log.e("Around event date error", e.toString());
+				}
+	        	
+				//Set touch event that will show a dialog.
+				llTouch = (LinearLayout) entry.findViewById(R.id.ll_row_around_content);
+				llTouch.setOnClickListener(new OnClickListener(){
+					@Override
+					public void onClick(View v) {
+		            	TextView tvId = (TextView) v.findViewById(R.id.tv_row_around_id);
+		            	int id = Integer.parseInt(tvId.getText().toString());
+		            	Log.e("TOUCH", "#" +id);
+						showDialog(id);
+					}
+	        	});
+				
+	        	//Add the entry to the list.
+	        	list.addView(entry);
+			}
+        }
+	}
+	
+	/**
+	 * Shows a dialog with info about an event.
+	 * 
+	 * @param id The id of the event
+	 */
+	private void showDialog(int id){
+		
+		//Create the dialog
+		final Dialog dialog = new Dialog(getActivity());
+		
+		//Set window
+		dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+		dialog.setContentView(R.layout.dialog_around);
+		
+		//Date formatters
+		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
+		SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd-", Locale.US);
+		SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.US);
+ 
+		//Set the custom dialog components - text, image and button
+		TextView tvTitle = (TextView) dialog.findViewById(R.id.tv_dialog_around_title);
+		TextView tvDescription = (TextView) dialog.findViewById(R.id.tv_dialog_around_description);
+		TextView tvDate = (TextView) dialog.findViewById(R.id.tv_dialog_around_date);
+		TextView tvTime = (TextView) dialog.findViewById(R.id.tv_dialog_around_time);
+		TextView tvPlace = (TextView) dialog.findViewById(R.id.tv_dialog_around_place);
+		TextView tvAddress = (TextView) dialog.findViewById(R.id.tv_dialog_around_address);
+		Button btClose = (Button) dialog.findViewById(R.id.bt_around_close);
+		
+		//Get info about the event
+		SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+		Cursor cursor = db.rawQuery("SELECT event.id, event.name, description, start, end, place.name, address, lat, lon FROM event, place WHERE place.id = event.place AND event.id = " + id + ";", null);
+		if (cursor.getCount() > 0){
+			cursor.moveToNext();
+		
+			//Set title
+			tvTitle.setText(cursor.getString(1));
+			markerName = cursor.getString(1);
+			
+			//Set description
+			tvDescription.setText(cursor.getString(2));
+			
+			//Set date
+			try{
+				Date day = dateFormat.parse(cursor.getString(3));
+				Date date = new Date();
+				
+				//If the event is today, show "Today" instead of the date.
+				if (dayFormat.format(day).equals(dayFormat.format(date))){
+					tvDate.setText(dialog.getContext().getString(R.string.today));
+				}
+				else{
+					Calendar cal = Calendar.getInstance();
+				    cal.setTime(date);
+				    cal.add(Calendar.HOUR_OF_DAY, 24);
+				    
+				    //If the event is tomorrow, show "Tomorrow" instead of the date.
+				    if (dayFormat.format(cal.getTime()).equals(dayFormat.format(date))){
+				    	tvDate.setText(dialog.getContext().getString(R.string.tomorrow));
+				    }
+					
+				    //Else, show the date
+				    else{
+				    	SimpleDateFormat printFormat = new SimpleDateFormat("dd MMMM", Locale.US);
+				    	tvDate.setText(printFormat.format(day));
+				    }
+				}
+			}
+			catch (Exception ex){
+				Log.e("Error parsing around event date", ex.toString());
+			}
+			
+			//Set time
+			try{
+				if (cursor.getString(4) == null)
+					tvTime.setText(timeFormat.format(dateFormat.parse(cursor.getString(3))));
+				else
+					tvTime.setText(timeFormat.format(dateFormat.parse(cursor.getString(3))) + " - " + timeFormat.format(timeFormat.parse(cursor.getString(4))));
+			}
+			catch (ParseException ex){
+				Log.e("Error parsing around event time", ex.toString());
+			}
+			
+			//Set place
+			tvPlace.setText(cursor.getString(5));
+			tvAddress.setText(cursor.getString(6));
+			
+			//Set up map
+			location = new LatLng(Double.parseDouble(cursor.getString(7)), Double.parseDouble(cursor.getString(8)));
+			mapView = (MapView) dialog.findViewById(R.id.mv_dialog_around_map);
+			mapView.onCreate(bund);
+			
+			//Close db connection
+			cursor.close();
+			db.close();
+			
+			//Set close button			
+        	btClose.setOnClickListener(new OnClickListener() {
+    			@Override
+    			public void onClick(View v) {
+    				dialog.dismiss();
+    			}
+    		});
+			
+        	//Actions to take when the dialog is cancelled
+			dialog.setOnCancelListener(new OnCancelListener(){
+				@Override
+				public void onCancel(DialogInterface dialog) {
+					if (map != null)
+						map.setMyLocationEnabled(false);
+					if (mapView != null){
+    					mapView.onResume();
+    					mapView.onDestroy();
+    				}					
+				}
+			});
+        	
+			//Show the dialog
+			WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();
+			lp.dimAmount = 0.0f;
+			dialog.show();
+			
+			//Start the map
+			startMap();
+			mapView.onResume();
+			dialog.setOnShowListener(new OnShowListener(){
+				@Override
+				public void onShow(DialogInterface dialog) {
+					// Gets to GoogleMap from the MapView and does initialization stuff
+					startMap();		
+				}
+			});
+		}
+	}
+	
+	/**
+	 * Starts the map in the dialog.
+	 */
+	private void startMap(){
+		mapView.getMapAsync(this);
+	}
+	
+	/**
+	 * Called when the fragment is brought back into the foreground. 
+	 * Resumes the map and the location manager.
+	 * 
+	 * @see android.support.v4.app.Fragment#onResume()
+	 */
+	@Override
+	public void onResume() {
+		if (mapView != null)
+			mapView.onResume();
+		if (map != null)
+			map.setMyLocationEnabled(true);
+		Criteria criteria = new Criteria();
+	    provider = locationManager.getBestProvider(criteria, false);
+		locationManager.requestLocationUpdates(provider, 5000, 10, this);
+		super.onResume();
+	}
+
+	/**
+	 * Called when the fragment is destroyed. 
+	 * Finishes the map. 
+	 * 
+	 * @see android.support.v4.app.Fragment#onDestroy()
+	 */
+	@Override
+	public void onDestroy() {
+		super.onDestroy();
+		if (map != null)
+			map.setMyLocationEnabled(false);
+		if (mapView != null){
+			mapView.onResume();
+			mapView.onDestroy();
+		}
+	}
+	
+	
+
+	/**
+	 * Called in a situation of low memory.
+	 * Lets the map handle this situation.
+	 * 
+	 * @see android.support.v4.app.Fragment#onLowMemory()
+	 */
+	@Override
+	public void onLowMemory() {
+		super.onLowMemory();
+		if (mapView != null){
+			mapView.onResume();
+			mapView.onLowMemory();
+		}
+	}
+
+	/**
+	 * Called when the map is ready to be displayed. 
+	 * Sets the map options and a marker for the map.
+	 * 
+	 * @param googleMap The map to be shown
+	 * 
+	 * @see com.google.android.gms.maps.OnMapReadyCallback#onMapReady(com.google.android.gms.maps.GoogleMap)
+	 */
+	@Override
+	public void onMapReady(GoogleMap googleMap) {
+		this.map = googleMap;
+		map.setMyLocationEnabled(true);
+		
+		map.getUiSettings().setMyLocationButtonEnabled(false);
+		map.setMyLocationEnabled(true);
+		// Needs to call MapsInitializer before doing any CameraUpdateFactory calls
+		try {
+			MapsInitializer.initialize(this.getActivity());
+			CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(location, 14);
+			map.animateCamera(cameraUpdate);
+		} catch (Exception e) {
+			Log.e("Error initializing mapss", e.toString());
+		}
+		//Set GM marker
+		MarkerOptions mo = new MarkerOptions();
+		mo.title(markerName);
+		mo.position(location);
+		map.addMarker(mo);
+		
+	}
+	
+	/**
+	 * Called when the user location changes. 
+	 * Recalculates the list of events.
+	 * 
+	 * @param location The new location
+	 * 
+	 * @see android.location.LocationListener#onLocationChanged(android.location.Location)
+	 */
+	@Override
+    public void onLocationChanged(Location location) {
+    	double lat = location.getLatitude();
+		double lng = location.getLongitude();
+		coordinates[0] = lat;
+		coordinates[1] = lng;
+		//Check GPS status
+		if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
+			//Populate the activity list
+			list.setVisibility(View.VISIBLE);
+			noGps.setVisibility(View.GONE);
+			noEvents.setVisibility(View.GONE);
+			populateAround(list);
+		}
+		else{
+			list.setVisibility(View.GONE);
+			noEvents.setVisibility(View.GONE);
+			noGps.setVisibility(View.VISIBLE);
+		}
+    }
+	
+	
+    /**
+     * Called when a location provider is disabled. 
+     * Recalculates the list of events.
+     * 
+     * @param provider The name of the provider
+     * 
+     * @see android.location.LocationListener#onProviderDisabled(java.lang.String)
+     */
+    @Override
+    public void onProviderDisabled(String provider) {
+    	//Check GPS status
+		if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
+			//Populate the activity list
+			list.setVisibility(View.VISIBLE);
+			noGps.setVisibility(View.GONE);
+			noEvents.setVisibility(View.GONE);
+			populateAround(list);
+		}
+		else{
+			list.setVisibility(View.GONE);
+			noEvents.setVisibility(View.GONE);
+			noGps.setVisibility(View.VISIBLE);
+		}
+    }
+    
+    /**
+     * Called when a location provider is enabled.
+     * Recalculates the list of events.
+     * 
+     * @param provider The name of the provider
+     * 
+     * @see android.location.LocationListener#onProviderEnabled(java.lang.String)
+     */
+    @Override
+    public void onProviderEnabled(String provider) {
+    	//Check GPS status
+		if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
+			//Populate the activity list
+			list.setVisibility(View.VISIBLE);
+			noGps.setVisibility(View.GONE);
+			noEvents.setVisibility(View.GONE);
+			populateAround(list);
+		}
+		else{
+			list.setVisibility(View.GONE);
+			noEvents.setVisibility(View.GONE);
+			noGps.setVisibility(View.VISIBLE);
+		}
+    }
+    
+    /**
+     * Called when the location provider changes it's state. 
+     * Does nothing, all useful cases are handled outside here.
+     * 
+     * @param provider The name of the provider
+     * @param status Status code of the provider
+     * @param extras Extras passed 
+     * 
+     * @see android.location.LocationListener#onStatusChanged(java.lang.String, int, android.os.Bundle)
+     */
+    @Override
+    public void onStatusChanged(String provider, int status, Bundle extras) { }
+		
+}
+

+ 246 - 0
app/src/main/java/com/ivalentin/gm/BlogLayout.java

@@ -0,0 +1,246 @@
+package com.ivalentin.gm;
+
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.text.Html;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.File;
+import java.util.Locale;
+
+/**
+ * Created by seavenois on 09/06/16.
+ */
+public class BlogLayout extends Fragment{
+
+    //Main View
+    private View view;
+
+    int offset = 0;
+    int totalPost = 0;
+
+    /**
+     * Run when the fragment is inflated.
+     * Assigns views, gets the date and does the first call to the {@link #populate} function.
+     *
+     * @param inflater A LayoutInflater to manage views
+     * @param container The container View
+     * @param savedInstanceState Bundle containing the state
+     *
+     * @return The fragment view
+     *
+     * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
+     */
+    @SuppressLint("InflateParams") //Throws unknown error when done properly.
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+        //Load the layout
+        view = inflater.inflate(R.layout.fragment_layout_blog, null);
+
+        //Set the title
+        ((MainActivity) getActivity()).setSectionTitle(view.getContext().getString(R.string.menu_blog));
+
+        //Get total posts
+        SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+        Cursor cursor = db.rawQuery("SELECT id FROM post;", null);
+        totalPost = cursor.getCount();
+        cursor.close();
+        db.close();
+
+        //Assign pager buttons
+        final Button btnPrevious = (Button) view.findViewById(R.id.bt_blog_previous);
+        final Button btnNext = (Button) view.findViewById(R.id.bt_blog_next);
+
+        btnPrevious.setOnClickListener(new View.OnClickListener() {
+           @Override
+           public void onClick(View v) {
+               offset -= 5;
+               btnNext.setVisibility(View.VISIBLE);
+               populate(offset);
+               if (offset == 0){
+                   v.setVisibility(View.GONE);
+               }
+           }
+        });
+
+        btnNext.setOnClickListener(new View.OnClickListener() {
+           @Override
+           public void onClick(View v) {
+               offset += 5;
+               btnPrevious.setVisibility(View.VISIBLE);
+               populate(offset);
+               if (offset >= totalPost - 5){
+                   v.setVisibility(View.GONE);
+               }
+           }
+        });
+
+        populate(offset);
+
+        return view;
+    }
+
+    /**
+     * Called when the fragment is brought back into the foreground.
+     * Resumes the map and the location manager.
+     *
+     * @see android.support.v4.app.Fragment#onResume()
+     */
+    @Override
+    public void onResume(){
+        Log.e("offset", "" + offset);
+        Log.e("total", "" + totalPost);
+        //Assign pager buttons
+        Button btnPrevious = (Button) view.findViewById(R.id.bt_blog_previous);
+        Button btnNext = (Button) view.findViewById(R.id.bt_blog_next);
+        if (offset == 0){
+            btnPrevious.setVisibility(View.GONE);
+        }
+        else{
+            btnPrevious.setVisibility(View.VISIBLE);
+        }
+        if (offset >= totalPost - 5){
+            btnNext.setVisibility(View.GONE);
+        }
+        else{
+            btnNext.setVisibility(View.VISIBLE);
+        }
+        super.onResume();
+    }
+
+    public void populate(){
+        populate(0);
+    }
+
+    /**
+     * Populates the list of activities around.
+     * It uses the default layout as parent.
+     */
+    public void populate(int offset){
+
+        //Assign elements
+        LinearLayout llList = (LinearLayout) view.findViewById(R.id.ll_blog_list);
+        LinearLayout entry;
+
+        //An inflater
+        LayoutInflater factory = LayoutInflater.from(getActivity());
+
+        SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+        final Cursor cursor;
+        String currLang = Locale.getDefault().getDisplayLanguage();
+        if (!currLang.equals("es") && !currLang.equals("eu")){
+            currLang = "en";
+        }
+
+        //Get data from the database
+        cursor = db.rawQuery("SELECT id, title_" + currLang+ " AS title, text_" + currLang + " AS text, dtime FROM post ORDER BY dtime DESC LIMIT 5 OFFSET " + offset + ";", null);
+
+        //Clear the list
+        llList.removeAllViews();
+
+        //Loop
+        while (cursor.moveToNext()){
+
+            //Create a new row
+            entry = (LinearLayout) factory.inflate(R.layout.row_blog, null);
+
+            //Set margins
+            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+            layoutParams.setMargins(10, 10, 10, 25);
+            entry.setLayoutParams(layoutParams);
+
+            //Set title
+            TextView tvTitle = (TextView) entry.findViewById(R.id.tv_row_blog_title);
+            tvTitle.setText(cursor.getString(1));
+
+            //Set text
+            String text = Html.fromHtml(cursor.getString(2)).toString();
+            if (text.length() > 180){
+                text = text.substring(0, 180) + "...";
+            }
+            TextView tvText = (TextView) entry.findViewById(R.id.tv_row_blog_text);
+            tvText.setText(text);
+
+            //Set date
+            TextView tvDate = (TextView) entry.findViewById(R.id.tv_row_blog_date);
+            tvDate.setText(GM.formatDate(cursor.getString(3), currLang, false));
+
+            //Set hidden id
+            TextView tvId = (TextView) entry.findViewById(R.id.tv_row_blog_hidden);
+            tvId.setText(cursor.getString(0));
+
+            //Get image
+            ImageView iv = (ImageView) entry.findViewById(R.id.iv_row_blog_image);
+            Cursor cursorImage = db.rawQuery("SELECT image FROM post_image WHERE post = " + cursor.getString(0) +" ORDER BY idx LIMIT 1;", null);
+            if (cursorImage.getCount() > 0){
+                cursorImage.moveToFirst();
+                String image = cursorImage.getString(0);
+
+                //Check if image exists
+                File f;
+                f = new File(this.getContext().getFilesDir().toString() + "/img/blog/miniature/" + image);
+                if (f.exists()){
+                    //If the image exists, set it.
+                    Bitmap myBitmap = BitmapFactory.decodeFile(this.getContext().getFilesDir().toString() + "/img/blog/miniature/" + image);
+                    iv.setImageBitmap(myBitmap);
+                }
+                else {
+                    //If not, create directories and download asynchronously
+                    File fpath;
+                    fpath = new File(this.getContext().getFilesDir().toString() + "/img/blog/miniature/");
+                    fpath.mkdirs();
+                    new DownloadImage(GM.SERVER + "/img/blog/miniature/" + image, this.getContext().getFilesDir().toString() + "/img/blog/miniature/" + image, iv).execute();
+                }
+            }
+
+            //Count comments
+            Cursor cursorComment = db.rawQuery("SELECT * FROM post_comment WHERE post = " + cursor.getString(0) +";", null);
+            TextView tvDetails = (TextView) entry.findViewById(R.id.tv_row_blog_details);
+            tvDetails.setText(" " + cursorComment.getCount());
+
+            //Set onCLickListener
+            entry.setOnClickListener(new View.OnClickListener(){
+                @Override
+                public void onClick(View v) {
+                //Toast.makeText(getActivity(), "OPENING POST", Toast.LENGTH_LONG).show();
+                Fragment fragment = new PostLayout();
+                Bundle bundle = new Bundle();
+                //Pass post id
+                int id = Integer.parseInt(((TextView) v.findViewById(R.id.tv_row_blog_hidden)).getText().toString());
+                bundle.putInt("post", id);
+                fragment.setArguments(bundle);
+
+                FragmentManager fm = BlogLayout.this.getActivity().getSupportFragmentManager();
+                FragmentTransaction ft = fm.beginTransaction();
+
+                ft.replace(R.id.activity_main_content_fragment, fragment);
+                ft.addToBackStack("post_" + id);
+                ft.commit();
+                }
+            });
+
+            //Add to the list
+            llList.addView(entry);
+        }
+
+    }
+}

+ 36 - 0
app/src/main/java/com/ivalentin/gm/BootReceiver.java

@@ -0,0 +1,36 @@
+package com.ivalentin.gm;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Broadcast receiver that receives the BOOT_COMPLETED event and sets an alarm.
+ * 
+ * @see BroadCastReceiver
+ * 
+ * @author Iñigo Valentin
+ *
+ */
+public class BootReceiver extends BroadcastReceiver {
+	
+	//The AlarmReceiver
+	private AlarmReceiver alarm = new AlarmReceiver();
+	
+	/**
+	 * Called when the BroadCasteReceiver is receiving an Intent broadcast. 
+	 * Starts an alarm. 
+	 * 
+	 * @param context Context of the application
+	 * @param intent Receiver intent
+	 * 
+	 * @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)
+	 */
+	@Override
+	public void onReceive(Context context, Intent intent) {
+		//If the event is BOOT_COMPLETED...
+		if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED"))
+			//... set the alarm.
+			alarm.setAlarm(context);
+	}
+}

+ 76 - 0
app/src/main/java/com/ivalentin/gm/CustomScrollView.java

@@ -0,0 +1,76 @@
+package com.ivalentin.gm;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.ScrollView;
+
+/**
+ * An extended ScrollView. 
+ * It allows to be swept from the left to open the application menu.
+ * 
+ * @author Iñigo Valentin
+ * 
+ * @see ScrollView
+ *
+ */
+public class CustomScrollView extends ScrollView{
+	
+	/**
+     * Constructor.
+     * 
+     * @param context The context of the app or Activity.
+     */
+	public CustomScrollView(Context context) {
+		super(context);
+	}
+	
+	/**
+     * Constructor.
+     * 
+     * @param context The context of the app or Activity.
+     * @param attrs Attributes.
+     */
+	public CustomScrollView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    /**
+     * Constructor.
+     * 
+     * @param context The context of the app or Activity.
+     * @param attrs Attributes.
+     * @param defStyle Default style.
+     */
+    public CustomScrollView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+	
+	/**
+	 * Overrides the default onTouchListener. 
+	 * 
+	 * If the motion is in the leftmost part of the screen, the event is not 
+	 * passed along and the menu is shown.
+	 * 
+	 * @see android.widget.ScrollView#onTouchEvent(android.view.MotionEvent)
+	 * 
+	 * @param ev The MotionEvent triggering the action
+	 * 
+	 * @return True if the app handles the motion (i.e. to slide), false otherwise (normal event)
+	 */
+	@SuppressLint("ClickableViewAccessibility") //Disturbs the sliding process
+	@Override
+    public boolean onTouchEvent(MotionEvent ev) {
+		int width = this.getWidth();
+		super.onTouchEvent(ev);
+		if (ev.getX() <  (float) width / 10){
+			
+			return false;
+		}
+		else{
+			return true;
+		}				
+	}
+
+}

+ 63 - 0
app/src/main/java/com/ivalentin/gm/Distance.java

@@ -0,0 +1,63 @@
+package com.ivalentin.gm;
+
+/**
+ * Static class that allows to calculate the distance between tho 
+ * sets of GPS coordinates.
+ * 
+ * @author Iñigo Valentin
+ *
+ */
+public final class Distance {
+	
+	/**
+	 * Calculates the distance between two points (given the latitude/longitude of those points). 
+	 * 
+	 * Official Web site: http://www.geodatasource.com 
+	 * GeoDataSource.com (C) All Rights Reserved 2015
+	 * 
+	 * @param lat1 Latitude of the first point
+	 * @param lon1 Longitude of the first point
+	 * @param lat2 Latitude of the second point
+	 * @param lon2 Longitude of the second point
+	 * @param unit The result unit. 'M' for statute miles (default), 'K' for kilometers and 'N' for nautical miles.
+	 * 
+	 * @return The distance between the points
+	 */
+	public static final double calculateDistance(double lat1, double lon1, double lat2, double lon2, char unit) {
+		double theta = lon1 - lon2;
+		double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
+		dist = Math.acos(dist);
+		dist = rad2deg(dist);
+		dist = dist * 60 * 1.1515;
+		if (unit == 'K') {
+			dist = dist * 1.609344;
+		}
+		else if (unit == 'N') {
+			dist = dist * 0.8684;
+		}
+		return (dist);
+	}
+	
+	/**
+	 * Converts decimal degrees to radians.
+	 * 
+	 * @param deg Decimal degrees.
+	 * 
+	 * @return Radians.
+	 */
+	private static final double deg2rad(double deg) {
+		return (deg * Math.PI / 180.0);
+	}
+	
+	/**
+	 * Converts radians to decimal degrees.
+	 * 
+	 * @param rad Radans.
+	 * 
+	 * @return Decimal degrees.
+	 */
+	private static final double rad2deg(double rad) {
+		return (rad * 180 / Math.PI);
+	}
+	
+}

+ 96 - 0
app/src/main/java/com/ivalentin/gm/DownloadImage.java

@@ -0,0 +1,96 @@
+package com.ivalentin.gm;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.util.Log;
+import android.widget.ImageView;
+
+import java.io.BufferedInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLConnection;
+
+class DownloadImage extends AsyncTask<String, String, String> {
+
+    String file;
+    String path;
+    ImageView iv;
+
+    public DownloadImage(String file, String path, ImageView iv) {
+        super();
+        this.file = file;
+        this.path = path;
+        this.iv = iv;
+    }
+
+    /**
+     * Before starting background thread
+     * */
+    @Override
+    protected void onPreExecute() {
+        super.onPreExecute();
+    }
+
+    /**
+     * Downloading file in background thread
+     * */
+    @Override
+    protected String doInBackground(String... f_url) {
+        int count;
+        try {
+
+            URL url = new URL(file);
+
+            URLConnection conection = url.openConnection();
+            conection.connect();
+
+            // input stream to read file - with 8k buffer
+            InputStream input = new BufferedInputStream(url.openStream(), 8192);
+
+            // Output stream to write file
+
+            OutputStream output = new FileOutputStream(path);
+            byte data[] = new byte[1024];
+
+            long total = 0;
+            while ((count = input.read(data)) != -1) {
+                total += count;
+
+                // writing data to file
+                output.write(data, 0, count);
+
+            }
+
+            // flushing output
+            output.flush();
+
+            // closing streams
+            output.close();
+            input.close();
+
+        } catch (Exception e) {
+            Log.e("Error downloading: ", e.getMessage());
+        }
+
+        return null;
+    }
+
+
+
+    /**
+     * After completing background task
+     * **/
+    @Override
+    protected void onPostExecute(String file_url) {
+        Log.d("File downloaded", path);
+        Bitmap myBitmap = BitmapFactory.decodeFile(path);
+
+        //ImageView myImage = (ImageView) findViewById(R.id.imageviewTest);
+
+        iv.setImageBitmap(myBitmap);
+    }
+
+}

+ 257 - 0
app/src/main/java/com/ivalentin/gm/Event.java

@@ -0,0 +1,257 @@
+package com.ivalentin.gm;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * An event holds information about an activity of the festival
+ * 
+ * @author Iñigo Valentin
+ * 
+ * @see Comparable
+ *
+ */
+public class Event implements Comparable<Event>{
+	
+	private String name, description, place, host;
+	private double[] coordinates = new double[2];
+	private Date start, end;
+	private boolean gm, schedule;
+	private Integer distance = null;
+	private double[] location = new double[2];
+	private int id;
+	
+	
+	/**
+	 * Constructor.
+	 * 
+	 * @param name Name of the event.
+	 * @param description Description of the event.
+	 * @param gm 1 if it's a Margolari event, 0 otherwise.
+	 * @param schedule 1 if it's an event from the municipal schedule, 0 otherwise.
+	 * @param place Name of the place where the event is hold.
+	 * @param host Name of the people/organization that organizes the event. Can be null.
+	 * @param coordinates Array of doubles [latitude, longitude].
+	 * @param start String whit the date and time of the start of the event, in the format yyyy-MM-dd HH:mm:ss.
+	 * @param end String whit the date and time of the end of the event, in the format yyyy-MM-dd HH:mm:ss. Can be null.
+	 */
+	public Event(int id, String name, String description, int gm, int schedule, String place, String host, double[] coordinates, String start, String end){
+		super();
+		this.id = id;
+		this.name = name;
+		this.description = description;
+		this.place = place;
+		if (gm == 1)
+			this.gm = true;
+		else
+			this.gm = false;
+		if (schedule == 1)
+			this.schedule = true;
+		else
+			this.schedule = false;
+		this.host = host;
+		this.coordinates = coordinates;
+		DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
+		try{
+			this.start = format.parse(start);
+		}
+		catch (Exception ex){
+			start = null;
+		}
+		try{
+			this.end = format.parse(end);
+		}
+		catch (Exception ex){
+			end = null;
+		}
+	}
+	
+	/**
+	 * Return the id of the event
+	 * 
+	 * @return the id of the event
+	 */
+	public int getId(){
+		return id;
+	}
+	
+	/**
+	 * Return the name of the event.
+	 * @return The name of the event.
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * Return the description of the event.
+	 * @return The description of the event.
+	 */
+	public String getDescription() {
+		return description;
+	}
+	
+	/**
+	 * Checks if the event is a Margolari one.
+	 * @return true if it's a Margolari event, false otherwise.
+	 */
+	public boolean isGm(){
+		return gm;
+	}
+	
+	/**
+	 * Checks if the event is an official one.
+	 * @return true if it's an official event, false otherwise.
+	 */
+	public boolean isSchedule(){
+		return schedule;
+	}
+	
+	/**
+	 * Return the place of the event.
+	 * @return The place of the event.
+	 */
+	public String getPlace() {
+		return place;
+	}
+	
+	/**
+	 * Return the host of the event.
+	 * @return The host of the event.
+	 */
+	public String getHost() {
+		return host;
+	}
+	
+	/**
+	 * Return the event coordinates.
+	 * @return The coordinates of the event [latitude, longitude].
+	 */
+	public double[] getCoordinates() {
+		return coordinates;
+	}
+	
+	/**
+	 * Return the event start time.
+	 * @return The event start date and time.
+	 */
+	public Date getStart() {
+		return start;
+	}
+	
+	/**
+	 * Return the event end time.
+	 * @return The event end date and time.
+	 */
+	public Date getEnd() {
+		return end;
+	}
+	
+	/**
+	 * Calculates the event distance to a given point.
+	 * 
+	 * @param loc Array of doubles [latitude, longitude] to calculate the distance of the event from.
+	 * @return The distance, in meters, between the event and the given point.
+	 */
+	public Integer getDistance(double loc[]){
+		location = loc;
+		distance = Math.round((long) (Distance.calculateDistance(location[0], location[1], coordinates[0], coordinates[1], 'K') * 1000));
+		return distance;
+	}
+	
+	/**
+	 * Gets the distance between the event location and a location previously provided using getDistance(double loc[]). 
+	 * 
+	 * @return The distance, in meters, between the event and the location set when calling getDistance(double loc[]). If it wasn't called, it will be null.
+	 */
+	public Integer getDistance(){
+		if (location == null)
+			return null;
+		else
+			return getDistance(location);
+	}
+	
+	/**
+	 * Return the time between the current time and the start of the event.
+	 * @return The time, in minutes, to the event start. A positive value indicates that the event is in the future, and a negative indicates that the event has already started.
+	 */
+	public long getTimeToStart(){
+		Date now = new Date();
+		long dif = (start.getTime() / 60000) - (now.getTime() / 60000);
+		return dif;
+	}
+	
+	/**
+	 * Return the time between the current time and the end of the event.
+	 * @return The time, in minutes, to the event end. A positive value indicates that the event is in the future, and a negative indicates that the event has already started. If the event doesn't have an end date, it will return 0.
+	 */
+	public long getTimeToEnd(){
+		if (end == null)
+			return 0;
+		Date now = new Date();
+		long dif = (start.getTime() / 60000) - (now.getTime() / 60000);
+		return dif;
+	}
+	
+	/**
+	 * Compares the event to another event to establish a relative order. 
+	 * The order is based on the time and the distance to the user.
+	 * 
+	 * @see java.lang.Comparable#compareTo(java.lang.Object)
+	 * 
+	 * @param Other event to compare to this.
+	 * 
+	 * @return Negative integer if this instance is less than another, positive if it's greater, 0 if they are equal.
+	 */
+	@Override
+	public int compareTo(Event another) {
+		float distanceDif, timeDif;
+		float result;
+		
+		
+		//Get distance difference
+		if (getDistance() == null && another.getDistance() == null)
+			distanceDif = 0;
+		else if (getDistance() == null)
+			distanceDif = -1;
+		else if (another.getDistance() == null)
+			distanceDif = 1;
+		else{
+			distanceDif = getDistance() - another.getDistance();
+			if (getDistance() > another.getDistance()){
+				if (getDistance() == 0)
+					distanceDif = 1;
+				else
+					distanceDif = distanceDif / getDistance();
+			}
+			else{
+				if (another.getDistance() == 0)
+					distanceDif = -1;
+				else
+					distanceDif = distanceDif / another.getDistance();
+			}
+		}
+		
+		//Get time to start difference
+		timeDif = Math.abs(getTimeToStart()) - Math.abs(another.getTimeToStart());
+		if (getTimeToStart() > another.getTimeToStart()){
+			if (getTimeToStart() == 0)
+				timeDif = 1;
+			else
+				timeDif = timeDif / getTimeToStart();
+		}
+		else{
+			if (another.getTimeToStart() == 0)
+				timeDif = -1;
+			else
+				timeDif = timeDif / another.getTimeToStart();
+			
+		}
+		
+		result = timeDif + distanceDif;
+		
+		return Math.round(result);
+	}
+}

+ 95 - 0
app/src/main/java/com/ivalentin/gm/FakeLinkTextView.java

@@ -0,0 +1,95 @@
+package com.ivalentin.gm;
+
+import android.content.Context;
+import android.text.Editable;
+import android.text.SpannableString;
+import android.text.TextWatcher;
+import android.text.style.UnderlineSpan;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+/**
+ * Extension of TextView to make some text look like links.
+ * 
+ * Although the click function s not implemented here, the text is given
+ * the appearance of a link: blue and underlined.
+ * 
+ * @author Iñigo Valentin
+ *
+ * @see TextView
+ */
+public class FakeLinkTextView extends TextView{
+
+	//Indicates if the text is being modified
+	private boolean modifyingText = false;
+
+	/**
+     * Constructor.
+     * 
+     * @param context The context of the app or Activity.
+     */
+	public FakeLinkTextView(Context context){
+		super(context);
+		init();
+	}
+
+	/**
+     * Constructor.
+     * 
+     * @param context The context of the app or Activity.
+     * @param attrs Attributes.
+     */
+	public FakeLinkTextView(Context context, AttributeSet attrs){
+		super(context, attrs);
+		init();
+	}
+
+	/**
+     * Constructor.
+     * 
+     * @param context The context of the app or Activity.
+     * @param attrs Attributes.
+     * @param defStyle Default style.
+     */
+	public FakeLinkTextView(Context context, AttributeSet attrs, int defStyle){
+		super(context, attrs, defStyle);
+		init();
+	}
+
+	/**
+	 * Sets a TextWatcher for the FakeLinkTextView that sets it's color and calls 
+	 * a function to underline it. 
+	 */
+	private void init(){
+		addTextChangedListener(new TextWatcher(){
+			@Override
+			public void beforeTextChanged(CharSequence s, int start, int count, int after){ }
+
+			@Override
+			public void onTextChanged(CharSequence s, int start, int before, int count){ }
+
+			@Override
+			public void afterTextChanged(Editable s){
+				if (modifyingText == false){
+					underlineText();
+					setTextColor(getResources().getColor(R.color.link));
+				}
+			}
+		});
+		underlineText();
+	}
+
+	/**
+	 * Underlines the text.
+	 */
+	private void underlineText(){
+		if (modifyingText == false){
+			modifyingText = true;
+			SpannableString content = new SpannableString(getText());
+			content.setSpan(new UnderlineSpan(), 0, content.length(), 0);
+			setText(content);
+			modifyingText = false;
+		}
+	}
+	
+}

+ 73 - 0
app/src/main/java/com/ivalentin/gm/FetchURL.java

@@ -0,0 +1,73 @@
+package com.ivalentin.gm;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class that fetches an online page.
+ * 
+ * @author Inigo Valentin
+ *
+ */
+public class FetchURL {
+ 
+	//List of strings that will contain the output, line by line
+	private List<String> output;
+	private String url;
+  
+	/**
+	 * Constructor.
+	 */
+	public FetchURL(){
+		output = new ArrayList<String>();
+	}
+  
+	/**
+	 * Returns the content of the fetched page.
+	 * 
+	 * @return A List of strings containing the lines of the web page.
+	 */
+	public List<String> getOutput(){
+		return output;
+	}
+  
+		
+	/**
+	 * Actually fetches the web page.
+	 * 
+	 * @param u The URL to fetch.
+	 */
+	public void Run(String u){
+		url = u;
+		Thread t =  new Thread() {
+			public void run() {  
+				URL textUrl;
+				try {
+					textUrl = new URL(url);
+					BufferedReader bufferReader = new BufferedReader(new InputStreamReader(textUrl.openStream()));
+					String StringBuffer;
+					List<String> lines = new ArrayList<String>();
+					while ((StringBuffer = bufferReader.readLine()) != null) {
+						lines.add(StringBuffer);
+					}
+					bufferReader.close();
+					output = lines;
+				}
+				catch (Exception e) {
+					e.printStackTrace();
+					output.add(e.toString());
+				}
+			}
+		};
+		t.start();
+		try {
+			t.join();
+		}
+		catch (InterruptedException e) {
+			e.printStackTrace();
+		}
+	} 
+}

+ 629 - 0
app/src/main/java/com/ivalentin/gm/GM.java

@@ -0,0 +1,629 @@
+package com.ivalentin.gm;
+
+import android.util.Log;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * Final class that contains useful static values to be used across the app.
+ * 
+ * @author Iñigo Valentin
+ *
+ */
+public final class GM {
+	
+	/**
+	 * Address where the web server is
+	 */
+	static final String SERVER = "http://margolariak.es";
+	
+	/**
+	 * Duration of the menu sliding animation.
+	 */
+	static final int MENU_SLIDING_DURATION = 500;
+	
+	/**
+	 * Interval between menu sliding queries. 
+	 */
+	static final int MENU_QUERY_INTERVAL = 16;
+	
+	/**
+	 * Period of time (in seconds) at the end of witch the app will perform a sync.
+	 */
+	static final int PERIOD_SYNC = 10 * 60 * 1000;
+	
+	/**
+	 * Name of the preference to store the user code with.
+	 */
+	static final String USER_CODE = "prefcode";
+	
+	/**
+	 * Name of the preference to store the user name with.
+	 */
+	static final String USER_NAME = "prefname";
+	
+	/**
+	 * Constant to diferentiate schedules".
+	 */
+	static final String SCHEDULE = "schedule";
+	
+	/**
+	 * Constant to set extras on the main intent.
+	 */
+	static final String EXTRA_TITLE = "title";
+	
+	/**
+	 * Constant to set extras on the main intent.
+	 */
+	static final String EXTRA_TEXT = "text";
+	
+	/**
+	 * Constant to set extras on the main intent.
+	 */
+	static final String EXTRA_ACTION = "action";
+	
+	/**
+	 * Value for {@see GM.EXTRA_ACTION} that opens the oficial schedule.
+	 */
+	static final String EXTRA_ACTION_SCHEDULE = "schedule";
+	
+	/**
+	 * Value for {@see GM.EXTRA_ACTION} that opens the GM schedule.
+	 */
+	static final String EXTRA_ACTION_GM = "gm";
+	
+	/**
+	 * Constant for section "Home".
+	 */
+	static final byte SECTION_HOME = 0;
+
+	/**
+	 * Constant for La Blanca section "Location".
+	 */
+	static final byte SECTION_LOCATION = 1;
+
+	/**
+	 * Constant for section "La Blanca".
+	 */
+	static final byte SECTION_LABLANCA = 2;
+
+	/**
+	 * Constant for La Blanca section "Festival schedule".
+	 */
+	static final byte SECTION_LABLANCA_SCHEDULE = 20;
+
+	/**
+	 * Constant for La Blanca section "Gasteizko Margolariak Schedule".
+	 */
+	static final byte SECTION_LABLANCA_GM_SCHEDULE = 21;
+
+	/**
+	 * Constant for La Blanca section "Around me".
+	 */
+	static final byte SECTION_LABLANCA_AROUND = 22;
+
+	/**
+	 * Constant for section "Activities".
+	 */
+	static final byte SECTION_ACTIVITIES = 3;
+
+	/**
+	 * Constant for section "Blog".
+	 */
+	static final byte SECTION_BLOG = 4;
+
+	/**
+	 * Constant for section "Gallery".
+	 */
+	static final byte SECTION_GALLERY = 5;
+
+	/**
+	 * Constant for section "About".
+	 */
+	static final byte SECTION_ABOUT = 6;
+
+	/**
+	 * Constant for section "Settings".
+	 */
+	static final byte SECTION_SETTINGS = 7;
+
+	/**
+	 * Name of the preference group for the app.
+	 */
+	static final String PREF = "gmpreferences";
+	
+	/**
+	 * Name of the preference to store the database version with.
+	 */
+	static final String PREF_DB_VERSION = "prefDbVersion";
+
+	/**
+	 * Name of the preference to store the setting that allows user to upload comments.
+	 */
+	static final String PREF_DB_PHOTOS = "prefDbPhotos";
+
+	/**
+	 * Name of the preference that indicates if we are on festivals.
+	 */
+	static final String PREF_DB_FESTIVALS = "prefDbFestivals";
+	
+	/**
+	 * Name of the preference indicating if the user wants to to receive notifications intended for the general public.
+	 */
+	static final String PREF_NOTIFICATION = "prefNotification";
+	
+	/**
+	 * Default value of the preference indicating if the user wants to to receive notifications intended for the general public.
+	 */
+	static final int DEFAULT_PREF_NOTIFICATION = 1;
+	
+	/**
+	 * Name of the preference indicating if the user wants to to receive notifications intended for margolari people.
+	 */
+	static final String PREF_NOTIFICATION_GM = "prefNotificationGm";
+	
+	/**
+	 * Default value of the preference indicating if the user wants to to receive notifications intended for margolari people.
+	 */
+	static final int DEFAULT_PREF_NOTIFICATION_GM = 1;
+	
+	/**
+	 * Name of the preference indicating if the user is Margolari.
+	 */
+	static final String PREF_GM = "prefGM";
+	
+	/**
+	 * Default value of the preference indicating if the user is Margolari.
+	 */
+	static final int DEFAULT_PREF_GM = 0;
+	
+	/**
+	 * Name of the preference indicating the user name.
+	 */
+	static final String PREF_USERNAME = "prefUsername";
+	
+	/**
+	 * Default value of the preference indicating the user name.
+	 */
+	static final String DEFAULT_PREF_USERNAME = "";
+	
+	/**
+	 * Header of a preference to indicate received notifications.
+	 */
+	static final String NOTIFICATION_SEEN_ ="notificationSeen";
+	
+	/**
+	 * Default value for the {//@link GM.PREF_DB_VERSION}  preference
+	 */
+	static final int DEFAULT_PREF_DB_VERSION = -2;
+	
+	/**
+	 * Name of the preference to store GM location's latitude.
+	 */
+	static final String PREF_GM_LATITUDE = "gmlat";
+	
+	/**
+	 * Name of the preference to store GM location's longitude.
+	 */
+	static final String PREF_GM_LONGITUDE = "gmlon";
+	
+	/**
+	 * Name of the preference to store GM last location timestamp.
+	 */
+	static final String PREF_GM_LOCATION = "gmlocationtime";
+	
+	/**
+	 * Day constant. Refers to July the 25.
+	 */
+	static final int DAY_25 = 0;
+	
+	/**
+	 * Day constant. Refers to August the 4.
+	 */
+	static final int DAY_4 = 1;
+	
+	/**
+	 * Day constant. Refers to August the 5.
+	 */
+	static final int DAY_5 = 2;
+	
+	/**
+	 * Day constant. Refers to August the 6.
+	 */
+	static final int DAY_6 = 3;
+	
+	/**
+	 * Day constant. Refers to August the 7.
+	 */
+	static final int DAY_7 = 4;
+	
+	/**
+	 * Day constant. Refers to August the 8.
+	 */
+	static final int DAY_8 = 5;
+	
+	/**
+	 * Day constant. Refers to August the 9.
+	 */
+	static final int DAY_9 = 6;
+	
+	/**
+	 * Total number of days of the festivals.
+	 */
+	static final int TOTAL_DAYS = 7;
+	
+	/**
+	 * Name of the database
+	 */
+	static final String DB_NAME = "gm";
+	
+	/**
+	 * Name of the table "place" in the database.
+	 */
+	static final String DB_PLACE = "place";
+	
+	/**
+	 * Name of the table "people" in the database.
+	 */
+	static final String DB_PEOPLE = "people";
+	
+	/**
+	 * Name of the table "event" in the database.
+	 */
+	static final String DB_EVENT = "event";
+	
+	/**
+	 * Name of the table "notification" in the database.
+	 */
+	static final String DB_NOTIFICATION = "notification";
+	
+	/**
+	 * Name of the column "id" in the table "place" in the database.
+	 */
+	static final String DB_PLACE_ID = "id";
+	
+	/**
+	 * Index of the column "id" in the table "place" in the database.
+	 */
+	static final int BD_PLACE_ID_INDEX = 0;
+	
+	/**
+	 * Name of the column "name" in the table "place" in the database.
+	 */
+	static final String DB_PLACE_NAME = "name";
+	
+	/**
+	 * Index of the column "name" in the table "place" in the database.
+	 */
+	static final int BD_PLACE_NAME_INDEX = 1;
+	
+	/**
+	 * Name of the column "address" in the table "place" in the database.
+	 */
+	static final String DB_PLACE_ADDRESS = "address";
+	
+	/**
+	 * Index of the column "address" in the table "place" in the database.
+	 */
+	static final int BD_PLACE_ADDRESS_INDEX = 2;
+	
+	/**
+	 * Name of the column "cp" in the table "place" in the database.
+	 */
+	static final String DB_PLACE_CP = "cp";
+	
+	/**
+	 * Index of the column "cp" in the table "place" in the database.
+	 */
+	static final int BD_PLACE_CP_INDEX = 3;
+	
+	/**
+	 * Name of the column "lat" in the table "place" in the database.
+	 */
+	static final String DB_PLACE_LATITUDE = "lat";
+	
+	/**
+	 * Index of the column "lat" in the table "place" in the database.
+	 */
+	static final int BD_PLACE_LATITUDE_INDEX = 4;
+	
+	/**
+	 * Name of the column "lon" in the table "place" in the database.
+	 */
+	static final String DB_PLACE_LONGITUDE = "lon";
+	
+	/**
+	 * Index of the column "lon" in the table "place" in the database.
+	 */
+	static final int BD_PLACE_LONGITUDE_INDEX = 5;
+	
+	/**
+	 * Name of the column "id" in the table "people" in the database.
+	 */
+	static final String DB_PEOPLE_ID = "id";
+	
+	/**
+	 * Index of the column "id" in the table "people" in the database.
+	 */
+	static final int BD_PEOPLE_ID_INDEX = 0;
+	
+	/**
+	 * Name of the column "name" in the table "people" in the database.
+	 */
+	static final String DB_PEOPLE_NAME = "name";
+	
+	/**
+	 * Index of the column "name" in the table "people" in the database.
+	 */
+	static final int BD_PEOPLE_NAME_INDEX = 1;
+	
+	/**
+	 * Name of the column "link" in the table "people" in the database.
+	 */
+	static final String DB_PEOPLE_LINK = "link";
+	
+	/**
+	 * Index of the column "link" in the table "people" in the database.
+	 */
+	static final int BD_PEOPLE_LINK_INDEX = 2;
+	
+	/**
+	 * Name of the column "id" in the table "event" in the database.
+	 */
+	static final String DB_EVENT_ID = "id";
+	
+	/**
+	 * Index of the column "id" in the table "event" in the database.
+	 */
+	static final int BD_EVENT_ID_INDEX = 0;
+	
+	/**
+	 * Name of the column "schedule" in the table "event" in the database.
+	 */
+	static final String DB_EVENT_SCHEDULE = "schedule";
+	
+	/**
+	 * Index of the column "schedule" in the table "event" in the database.
+	 */
+	static final int BD_EVENT_SCHEDULE_INDEX = 1;
+	
+	/**
+	 * Name of the column "gm" in the table "event" in the database.
+	 */
+	static final String DB_EVENT_GM = "gm";
+	
+	/**
+	 * Index of the column "gm" in the table "event" in the database.
+	 */
+	static final int BD_EVENT_GM_INDEX = 2;
+	
+	/**
+	 * Name of the column "name" in the table "event" in the database.
+	 */
+	static final String DB_EVENT_NAME = "name";
+	
+	/**
+	 * Index of the column "name" in the table "event" in the database.
+	 */
+	static final int BD_EVENT_NAME_INDEX = 3;
+	
+	/**
+	 * Name of the column "description" in the table "event" in the database.
+	 */
+	static final String DB_EVENT_DESCRIPTION = "description";
+	
+	/**
+	 * Index of the column "description" in the table "event" in the database.
+	 */
+	static final int BD_EVENT_DESCRIPTION_INDEX = 4;
+	
+	/**
+	 * Name of the column "host" in the table "event" in the database.
+	 */
+	static final String DB_EVENT_HOST = "host";
+	
+	/**
+	 * Index of the column "host" in the table "event" in the database.
+	 */
+	static final int BD_EVENT_HOST_INDEX = 5;
+	
+	/**
+	 * Name of the column "place" in the table "event" in the database.
+	 */
+	static final String DB_EVENT_PLACE = "place";
+	
+	/**
+	 * Index of the column "place" in the table "event" in the database.
+	 */
+	static final int BD_EVENT_PLACE_INDEX = 6;
+	
+	/**
+	 * Name of the column "start" in the table "event" in the database.
+	 */
+	static final String DB_EVENT_START = "start";
+	
+	/**
+	 * Index of the column "start" in the table "event" in the database.
+	 */
+	static final int BD_EVENT_START_INDEX = 7;
+	
+	/**
+	 * Name of the column "end" in the table "event" in the database.
+	 */
+	static final String DB_EVENT_END = "end";
+	
+	/**
+	 * Index of the column "end" in the table "event" in the database.
+	 */
+	static final int BD_EVENT_END_INDEX = 8;
+	
+	/**
+	 * Name of the column "id" in the table "notification" in the database.
+	 */
+	static final String DB_NOTIFICATION_ID = "id";
+	
+	/**
+	 * Index of the column "id" in the table "notification" in the database.
+	 */
+	static final int BD_NOTIFICATION_ID_INDEX = 0;
+	
+	/**
+	 * Name of the column "user" in the table "notification" in the database.
+	 */
+	static final String DB_NOTIFICATION_USER = "user";
+	
+	/**
+	 * Index of the column "user" in the table "notification" in the database.
+	 */
+	static final int BD_NOTIFICATION_USER_INDEX = 1;
+	
+	/**
+	 * Name of the column "time" in the table "notification" in the database.
+	 */
+	static final String DB_NOTIFICATION_TIME = "time";
+	
+	/**
+	 * Index of the column "time" in the table "notification" in the database.
+	 */
+	static final int BD_NOTIFICATION_TIME_INDEX = 2;
+	
+	/**
+	 * Name of the column "duration" in the table "notification" in the database.
+	 */
+	static final String DB_NOTIFICATION_DURATION = "duration";
+	
+	/**
+	 * Index of the column "id" in the table "notification" in the database.
+	 */
+	static final int BD_NOTIFICATION_DURATION_INDEX = 3;
+	
+	/**
+	 * Name of the column "type" in the table "notification" in the database.
+	 */
+	static final String DB_NOTIFICATION_TYPE = "type";
+	
+	/**
+	 * Index of the column "type" in the table "notification" in the database.
+	 */
+	static final int BD_NOTIFICATION_TYPE_INDEX = 4;
+	
+	/**
+	 * Name of the column "title" in the table "notification" in the database.
+	 */
+	static final String DB_NOTIFICATION_TITLE = "title";
+	
+	/**
+	 * Index of the column "title" in the table "notification" in the database.
+	 */
+	static final int BD_NOTIFICATION_TITLE_INDEX = 5;
+	
+	/**
+	 * Name of the column "text" in the table "notification" in the database.
+	 */
+	static final String DB_NOTIFICATION_TEXT = "text";
+	
+	/**
+	 * Index of the column "text" in the table "notification" in the database.
+	 */
+	static final int BD_NOTIFICATION_TEXT_INDEX = 6;
+	
+	/**
+	 * Name of the column "gm" in the table "notification" in the database.
+	 */
+	static final String DB_NOTIFICATION_GM = "gm";
+	
+	/**
+	 * Index of the column "text" in the table "notification" in the database.
+	 */
+	static final int BD_NOTIFICATION_GM_INDEX = 7;
+	
+	/**
+	 * The desired accuracy of the GPS coordinates, used to provide location updates, in meters.
+	 */
+	static final int LOCATION_ACCURACY = 20;
+
+	/**
+	 * Formats a datetime format strings and returns a human readable date, depending on the language
+	 *
+	 * @param dateString String in a datetime format
+	 * @param lang Language (es, en, eu)
+	 * @param includeTime Also returns the hour and minutes
+	 *
+	 * @return The fragment view
+	 *
+	 * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
+	 */
+	public static final String formatDate(String dateString, String lang, boolean includeTime){
+
+		String output = "";
+
+		String dayNameEs[] = {"dummy", "Domingo",  "Lunes", "Martes", "Mi&eacute;rcoles", "Jueves", "Viernes", "S&aacute;bado"};
+		String dayNameEn[] = {"dummy", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
+		String dayNameEu[] = {"dummy", "igandea", "astelehena", "asteartea", "asteazkena", "osteguna", "ostirala", "larumbata"};
+		String monthNameEs[] = {"enero", " febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"};
+		String monthNameEn[] = {"January", "February", "March", "April", "May", "June", "July", "Augost", "September", "Octuber", "November", "December"};
+		String monthNameEu[] = {"urtarrilaren", "otsailaren", "martxoaren", "apirilaren", "maiatzaren", "ekainaren", "uztailaren", "abuztuaren", "irailaren", "urriaren", "azaroaren", "abenduaren"};
+
+		if (lang != "es" && lang != "eu"){
+			lang = "en";
+		}
+		DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.ENGLISH);
+		SimpleDateFormat df;
+		Date date;
+		try{
+			date = format.parse(dateString);
+			df = new SimpleDateFormat("yyyy");
+			String year = df.format(date);
+			//df = new SimpleDateFormat("uu");
+			//int dayNumber = Integer.parseInt(df.format(date));
+			df = new SimpleDateFormat("dd");
+			String day = df.format(date);
+			//df = new SimpleDateFormat("dd");
+			//int monthNumber = Integer.parseInt(df.format(date));
+			df = new SimpleDateFormat("hh:mm");
+			String time = df.format(date);
+			String dayName, monthName;
+
+			Calendar calendar = Calendar.getInstance();
+			calendar.setTime(date);
+			int dayNumber = calendar.get(Calendar.DAY_OF_WEEK);
+			int monthNumber = calendar.get(Calendar.MONTH);
+
+			switch (lang){
+				case "es":
+					dayName = dayNameEs[dayNumber];
+					monthName = monthNameEs[monthNumber];
+					output = dayName + ", " + dayNumber + " de " + monthName + " de " + year;
+					if (includeTime){
+						output = output + " a las " + time;
+					}
+					break;
+				case "eu":
+					dayName = dayNameEu[dayNumber];
+					monthName = monthNameEu[monthNumber];
+					output = year + "ko" + monthName + " " + dayNumber + "an, " + dayName;
+					if (includeTime){
+						output = output + " " + time + "etan";
+					}
+					break;
+				default:
+					dayName = dayNameEn[dayNumber];
+					monthName = monthNameEn[monthNumber];
+					output = dayName + ", " + monthName + " " + dayNumber + ", " + year;
+					if (includeTime){
+						output = output + " " + time;
+					}
+					break;
+			}
+		}
+		catch(Exception ex){
+			Log.e("Date format error", ex.toString());
+		}
+
+		return output;
+	}
+}

+ 177 - 0
app/src/main/java/com/ivalentin/gm/GalleryLayout.java

@@ -0,0 +1,177 @@
+package com.ivalentin.gm;
+
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.text.Html;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.io.File;
+import java.util.Locale;
+
+/**
+ * Created by seavenois on 09/06/16.
+ */
+public class GalleryLayout extends Fragment{
+
+    //Main View
+    private View view;
+
+    /**
+     * Run when the fragment is inflated.
+     * Assigns views, gets the date and does the first call to the {@link #populate} function.
+     *
+     * @param inflater A LayoutInflater to manage views
+     * @param container The container View
+     * @param savedInstanceState Bundle containing the state
+     *
+     * @return The fragment view
+     *
+     * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
+     */
+    @SuppressLint("InflateParams") //Throws unknown error when done properly.
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+        //Load the layout
+        view = inflater.inflate(R.layout.fragment_layout_gallery, null);
+
+        //Set the title
+        ((MainActivity) getActivity()).setSectionTitle(view.getContext().getString(R.string.menu_gallery));
+
+        populate();
+
+        return view;
+    }
+
+    /**
+     * Populates the list of activities around.
+     * It uses the default layout as parent.
+     */
+    public void populate(){
+
+        //Assign elements
+        LinearLayout llList = (LinearLayout) view.findViewById(R.id.ll_gallery_album_list);
+        LinearLayout entry;
+
+        //An inflater
+        LayoutInflater factory = LayoutInflater.from(getActivity());
+
+        SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+        final Cursor cursor;
+        String currLang = Locale.getDefault().getDisplayLanguage();
+        if (!currLang.equals("es") && !currLang.equals("eu")){
+            currLang = "en";
+        }
+
+        //Get data from the database
+        cursor = db.rawQuery("SELECT id, name_" + currLang+ " AS title FROM album ORDER BY random();", null);
+
+        //Loop
+        while (cursor.moveToNext()){
+
+            //Create a new row
+            entry = (LinearLayout) factory.inflate(R.layout.row_gallery, null);
+
+            //Set margins
+            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+            layoutParams.setMargins(10, 10, 10, 25);
+            entry.setLayoutParams(layoutParams);
+
+            //Set title
+            TextView tvTitle = (TextView) entry.findViewById(R.id.tv_row_gallery_title);
+            tvTitle.setText(cursor.getString(1));
+
+            //Set hidden id
+            TextView tvId = (TextView) entry.findViewById(R.id.tv_row_gallery_hidden);
+            tvId.setText(cursor.getString(0));
+
+            //Get images
+            ImageView preview[] = new ImageView[4];
+            preview[0] = (ImageView) entry.findViewById(R.id.iv_row_gallery_0);
+            preview[1] = (ImageView) entry.findViewById(R.id.iv_row_gallery_1);
+            preview[2] = (ImageView) entry.findViewById(R.id.iv_row_gallery_2);
+            preview[3] = (ImageView) entry.findViewById(R.id.iv_row_gallery_3);
+
+            //Set counter
+            Cursor cursorImage = db.rawQuery("SELECT id, file, width, height FROM photo, photo_album WHERE photo = id AND album = " + cursor.getString(0) + " ORDER BY random() LIMIT 4;", null);
+            TextView tvPhotoCounter = (TextView) entry.findViewById(R.id.tv_row_gallery_counter);
+            tvPhotoCounter.setText(String.format(getResources().getQuantityString(R.plurals.gallery_photo_count, cursorImage.getCount()), cursorImage.getCount()));
+
+            int i = 0;
+            while (cursorImage.moveToNext()){
+                String image = cursorImage.getString(1);
+
+                //Check if image exists
+                File f;
+                f = new File(this.getContext().getFilesDir().toString() + "/img/galeria/miniature/" + image);
+                if (f.exists()){
+                    //If the image exists, set it.
+                    Bitmap myBitmap = BitmapFactory.decodeFile(this.getContext().getFilesDir().toString() + "/img/galeria/miniature/" + image);
+                    preview[i].setImageBitmap(myBitmap);
+                }
+                else {
+                    //If not, create directories and download asynchronously
+                    File fpath;
+                    fpath = new File(this.getContext().getFilesDir().toString() + "/img/galeria/miniature/");
+                    fpath.mkdirs();
+                    new DownloadImage(GM.SERVER + "/img/galeria/miniature/" + image, this.getContext().getFilesDir().toString() + "/img/galeria/miniature/" + image, preview[i]).execute();
+                }
+                i ++;
+
+            }
+
+
+            //Set onCLickListener
+            entry.setOnClickListener(new View.OnClickListener(){
+                @Override
+                public void onClick(View v) {
+                    //Toast.makeText(getActivity(), "OPENING POST", Toast.LENGTH_LONG).show();
+                    //TODO: Change
+                    Fragment fragment = new AlbumLayout();
+                    Bundle bundle = new Bundle();
+                    //Pass post id
+                    int id = Integer.parseInt(((TextView) v.findViewById(R.id.tv_row_gallery_hidden)).getText().toString());
+                    bundle.putInt("album", id);
+                    fragment.setArguments(bundle);
+
+                    FragmentManager fm = GalleryLayout.this.getActivity().getSupportFragmentManager();
+                    FragmentTransaction ft = fm.beginTransaction();
+
+                    ft.replace(R.id.activity_main_content_fragment, fragment);
+                    ft.addToBackStack("album_" + id);
+                    ft.commit();
+                    //setSectionTitle(title);
+                }
+            });
+
+            //Set onClick event
+            /*content = (LinearLayout) entry.findViewById(R.id.ll_row_schedule_content);
+            content.setOnClickListener(new View.OnClickListener(){
+                @Override
+                public void onClick(View v) {
+                    TextView tvName = (TextView) v.findViewById(R.id.tv_row_schedule_id);
+                    int id = Integer.parseInt(tvName.getText().toString());
+                    showDialog(id);
+                }
+            });*/
+
+            //Add to the list
+            llList.addView(entry);
+        }
+
+    }
+}

+ 897 - 0
app/src/main/java/com/ivalentin/gm/HomeLayout.java

@@ -0,0 +1,897 @@
+package com.ivalentin.gm;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Locale;
+
+import com.google.android.gms.maps.CameraUpdate;
+import com.google.android.gms.maps.CameraUpdateFactory;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.MapView;
+import com.google.android.gms.maps.MapsInitializer;
+import com.google.android.gms.maps.OnMapReadyCallback;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.MarkerOptions;
+
+import android.annotation.SuppressLint;
+import android.app.Dialog;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.support.v4.app.Fragment;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.text.Html;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * Section that will be seen when the app is started. 
+ * Contains info from almost every other section.
+ * 
+ * @author Iñigo Valentin
+ * 
+ * @see Fragment
+ *
+ */
+public class HomeLayout extends Fragment implements LocationListener, OnMapReadyCallback{
+
+	//The location manager
+	LocationManager locationManager;
+	Location listener;
+	
+	//The location of the user
+	private double[] coordinates = new double[2];
+	
+	//Layouts for each section
+	private LinearLayout llLocation, llLablanca, llGmschedule, llCityschedule, llAround, llGallery, llSocial;
+
+	//Language
+	private String currLang;
+	
+	//Map stuff for the dialog
+	private MapView mapView;
+	private Bundle bund;
+	private GoogleMap map;
+	private LatLng location;
+	private String markerName = "";
+	
+	/**
+	 * Run when the fragment is inflated.
+	 * Assigns views, gets the date and does the first call to the {//@link populate function}.
+	 * 
+	 * @param inflater A LayoutInflater to handle the views
+	 * @param container The parent View
+	 * //@param sanvedInstanceState Bundle with the saved state
+	 * 
+	 * @return The fragment view
+	 * 
+	 * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
+	 */
+	@SuppressLint("InflateParams") //Throws unknown error when done properly.
+	@Override
+	public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
+
+		//Load the layout.
+		View view = inflater.inflate(R.layout.fragment_layout_home, null);
+
+		//Get language
+		currLang = Locale.getDefault().getDisplayLanguage();
+		if (!currLang.equals("es") && !currLang.equals("eu")){
+			currLang = "en";
+		}
+				
+		//Set Location manager
+		locationManager = (LocationManager) view.getContext().getSystemService(Context.LOCATION_SERVICE);
+		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 5, this);
+		
+		//Set the title
+		((MainActivity) getActivity()).setSectionTitle(view.getContext().getString(R.string.menu_home));
+	    
+		//Get the location passed from MainActivity so we dont have to wait for it to be aquired.
+		Bundle bundle = this.getArguments();
+		coordinates[0] = bundle.getDouble("lat", 0);
+		coordinates[1] = bundle.getDouble("lon", 0);
+		
+		//Get current date
+		Calendar cal;
+		Date maxDate;
+		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
+		SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd-", Locale.US);
+		SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.US);
+		Date date = new Date();
+		
+		//Assign the layouts
+		llLocation = (LinearLayout) view.findViewById(R.id.ll_home_section_location);
+		llLablanca = (LinearLayout) view.findViewById(R.id.ll_home_section_lablanca);
+		llGmschedule = (LinearLayout) view.findViewById(R.id.ll_home_section_gmschedule);
+		llCityschedule = (LinearLayout) view.findViewById(R.id.ll_home_section_cityschedule);
+		llAround = (LinearLayout) view.findViewById(R.id.ll_home_section_around);
+
+
+		llGallery = (LinearLayout) view.findViewById(R.id.ll_home_section_gallery);
+		llSocial = (LinearLayout) view.findViewById(R.id.ll_home_section_social);
+
+		//Set onClick events for links
+		//TODO: Dont do it like this, do it in separate functions
+		llLocation.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				((MainActivity) getActivity()).loadSection(GM.SECTION_LOCATION, false);
+			}
+		});
+		llLablanca.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				((MainActivity) getActivity()).loadSection(GM.SECTION_LABLANCA, false);
+			}
+		});
+		llGmschedule.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				((MainActivity) getActivity()).loadSection(GM.SECTION_LABLANCA_GM_SCHEDULE, false);
+			}
+		});
+		llCityschedule.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				((MainActivity) getActivity()).loadSection(GM.SECTION_LABLANCA_SCHEDULE, false);
+			}
+		});
+		llAround.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				((MainActivity) getActivity()).loadSection(GM.SECTION_LABLANCA_AROUND, false);
+			}
+		});
+
+
+		//Set up the blog section
+		setUpBlog(view);
+
+		//Set up activities sections
+		if (setUpFutureActivities(view) == 0){
+			setUpPastActivities(view);
+		}
+
+		//Set up the gallery section
+		setUpGallery(view);
+
+
+		//TODO: Add listeners for social
+
+	    //Return the view itself.
+		return view;
+	}
+
+	/**
+	 * Populates the Gallery section of the home screen.
+	 * Loads four photos.
+	 * Tapping them takes to the respective album, tapping anywhere else, to the gallery section.
+	 *
+	 * @return The number of entries shown
+	 */
+	private int setUpGallery(View view) {
+		int counter = 0;
+
+		//Set onClick listener of section
+		LinearLayout llGallery = (LinearLayout) view.findViewById(R.id.ll_home_section_gallery);
+		//Set click listener
+		llGallery.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				((MainActivity) getActivity()).loadSection(GM.SECTION_GALLERY, false);
+			}
+		});
+
+		//Assign views
+		ImageView ivPhoto[] = new ImageView[4];
+		ivPhoto[0] = (ImageView) view.findViewById(R.id.iv_home_section_gallery_0);
+		ivPhoto[1] = (ImageView) view.findViewById(R.id.iv_home_section_gallery_1);
+		ivPhoto[2] = (ImageView) view.findViewById(R.id.iv_home_section_gallery_2);
+		ivPhoto[3] = (ImageView) view.findViewById(R.id.iv_home_section_gallery_3);
+
+		TextView tvHidden[] = new TextView[4];
+		tvHidden[0] = (TextView) view.findViewById(R.id.tv_home_section_gallery_hidden_0);
+		tvHidden[1] = (TextView) view.findViewById(R.id.tv_home_section_gallery_hidden_1);
+		tvHidden[2] = (TextView) view.findViewById(R.id.tv_home_section_gallery_hidden_2);
+		tvHidden[3] = (TextView) view.findViewById(R.id.tv_home_section_gallery_hidden_3);
+
+		//Get data from the database of the future activities
+		SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+		Cursor cursor = db.rawQuery("SELECT id, album, file, uploaded FROM photo, photo_album WHERE id = photo ORDER BY uploaded DESC LIMIT 4;", null);
+
+		while (cursor.moveToNext()){
+
+			//Set id
+			ivPhoto[counter].setTag(R.string.key_0, cursor.getString(0));
+			ivPhoto[counter].setTag(R.string.key_1, cursor.getString(1));
+
+			//Set image
+			String image = cursor.getString(2);
+			//Check if image exists
+			File f;
+			f = new File(this.getContext().getFilesDir().toString() + "/img/galeria/preview/" + image);
+			if (f.exists()) {
+				//If the image exists, set it.
+				Bitmap myBitmap = BitmapFactory.decodeFile(this.getContext().getFilesDir().toString() + "/img/galeria/preview/" + image);
+				ivPhoto[counter].setImageBitmap(myBitmap);
+			} else {
+				//If not, create directories and download asynchronously
+				File fpath;
+				fpath = new File(this.getContext().getFilesDir().toString() + "/img/galeria/preview/");
+				fpath.mkdirs();
+				new DownloadImage(GM.SERVER + "/img/galeria/preview/" + image, this.getContext().getFilesDir().toString() + "/img/galeria/preview/" + image, ivPhoto[counter]).execute();
+			}
+
+			//Set listeners for images
+			ivPhoto[counter].setOnClickListener(new View.OnClickListener() {
+				@Override
+				public void onClick(View v) {
+					Fragment fragment = new AlbumLayout();
+					Bundle bundle = new Bundle();
+
+					int photoId = Integer.parseInt((String) v.getTag(R.string.key_0));
+					int albumId = Integer.parseInt((String) v.getTag(R.string.key_1));
+
+					bundle.putInt("album", albumId);
+					bundle.putInt("photo", photoId);
+
+					fragment.setArguments(bundle);
+
+					FragmentManager fm = HomeLayout.this.getActivity().getSupportFragmentManager();
+					FragmentTransaction ft = fm.beginTransaction();
+
+					ft.replace(R.id.activity_main_content_fragment, fragment);
+					ft.addToBackStack("album_" + albumId);
+					ft.commit();
+				}
+			});
+
+			counter ++;
+		}
+
+		//Close db
+		cursor.close();
+		db.close();
+
+		return counter;
+	}
+
+	/**
+	 * Populates the Past Activities section of the home screen.
+	 * Makes the section visible and adds two rows with the two last activities.
+	 * Tapping them takes to the post, tapping anywhere else, to the blog section.
+	 *
+	 * @return The number of entries shown
+	 */
+	private int setUpPastActivities(View view){
+		int counter = 0;
+
+		//Get data from the database of the future activities
+		SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+		Cursor cursor = db.rawQuery("SELECT id, date, city, title_" + currLang + " AS title, text_" + currLang + " AS text, price, after_" + currLang + " AS after FROM activity WHERE date < date('now') ORDER BY date LIMIT 2;", null);
+
+		//Show section
+		LinearLayout llActivitiesPast = (LinearLayout) view.findViewById(R.id.ll_home_section_activities_past);
+		llActivitiesPast.setVisibility(View.VISIBLE);
+
+		//Set click listener
+		llActivitiesPast.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				((MainActivity) getActivity()).loadSection(GM.SECTION_ACTIVITIES, false);
+			}
+		});
+
+		LinearLayout llList = (LinearLayout) view.findViewById(R.id.ll_home_section_activities_past_content);
+		LinearLayout entry;
+
+		//An inflater
+		LayoutInflater factory = LayoutInflater.from(getActivity());
+
+		//Print rows
+		while (cursor.moveToNext()) {
+			//Create a new row
+			entry = (LinearLayout) factory.inflate(R.layout.row_home_activities, null);
+
+			//Set margins
+			LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+			layoutParams.setMargins(10, 10, 10, 25);
+			entry.setLayoutParams(layoutParams);
+
+			//Set title
+			TextView tvTitle = (TextView) entry.findViewById(R.id.tv_row_home_activity_title);
+			tvTitle.setText(cursor.getString(3));
+
+			//Set city
+			TextView tvCity = (TextView) entry.findViewById(R.id.tv_row_home_activity_city);
+			tvCity.setText(cursor.getString(2));
+
+			//Hide price
+			TextView tvPrice = (TextView) entry.findViewById(R.id.tv_row_home_activity_price);
+			tvPrice.setVisibility(View.GONE);
+			//tvPrice.setText(cursor.getString(5) + "€");
+
+			//Set text
+			String text;
+			if (cursor.getString(6).length() < 1) {
+				text = Html.fromHtml(cursor.getString(4)).toString();
+			}
+			else{
+				text = Html.fromHtml(cursor.getString(6)).toString();
+			}
+			if (text.length() > 100) {
+				text = text.substring(0, 100) + "...";
+			}
+			TextView tvText = (TextView) entry.findViewById(R.id.tv_row_home_activity_text);
+			tvText.setText(text);
+
+			//Set date
+			TextView tvDate = (TextView) entry.findViewById(R.id.tv_row_home_activity_date);
+			tvDate.setText(GM.formatDate(cursor.getString(1) + " 00:00:00", currLang, false));
+
+			//Set hidden id
+			TextView tvId = (TextView) entry.findViewById(R.id.tv_row_home_activity_hidden);
+			tvId.setText(cursor.getString(0));
+
+			//Get image
+			ImageView iv = (ImageView) entry.findViewById(R.id.iv_row_home_activity);
+			Cursor cursorImage = db.rawQuery("SELECT image FROM activity_image WHERE activity = " + cursor.getString(0) + " ORDER BY idx LIMIT 1;", null);
+			if (cursorImage.getCount() > 0) {
+				cursorImage.moveToFirst();
+				String image = cursorImage.getString(0);
+
+				//Check if image exists
+				File f;
+				f = new File(this.getContext().getFilesDir().toString() + "/img/actividades/miniature/" + image);
+				if (f.exists()) {
+					//If the image exists, set it.
+					Bitmap myBitmap = BitmapFactory.decodeFile(this.getContext().getFilesDir().toString() + "/img/actividades/miniature/" + image);
+					iv.setImageBitmap(myBitmap);
+				} else {
+					//If not, create directories and download asynchronously
+					File fpath;
+					fpath = new File(this.getContext().getFilesDir().toString() + "/img/actividades/miniature/");
+					fpath.mkdirs();
+					new DownloadImage(GM.SERVER + "/img/actividades/miniature/" + image, this.getContext().getFilesDir().toString() + "/img/actividades/miniature/" + image, iv).execute();
+				}
+			}
+
+			//Set onCLickListener
+			entry.setOnClickListener(new View.OnClickListener() {
+				@Override
+				public void onClick(View v) {
+				//Toast.makeText(getActivity(), "OPENING POST", Toast.LENGTH_LONG).show();
+				Fragment fragment = new ActivityPastLayout();
+				Bundle bundle = new Bundle();
+				//Pass post id
+				int id = Integer.parseInt(((TextView) v.findViewById(R.id.tv_row_home_activity_hidden)).getText().toString());
+				bundle.putInt("activity", id);
+				fragment.setArguments(bundle);
+
+				FragmentManager fm = HomeLayout.this.getActivity().getSupportFragmentManager();
+				FragmentTransaction ft = fm.beginTransaction();
+
+				ft.replace(R.id.activity_main_content_fragment, fragment);
+				ft.addToBackStack("activity_" + id);
+				ft.commit();
+				}
+			});
+
+			//Add to the list
+			llList.addView(entry);
+			counter++;
+		}
+
+		//Close db
+		cursor.close();
+		db.close();
+
+		return counter;
+	}
+
+	/**
+	 * Populates the Future activities section of the home screen.
+	 * If there are future activities, makes the section visible.
+	 * Adds two rows with the two next activities.
+	 * Tapping them takes to the post, tapping anywhere else, to the blog section.
+	 *
+	 * @return The number of entries shown
+	 */
+	private int setUpFutureActivities(View view){
+		int counter = 0;
+
+		LinearLayout llList = (LinearLayout) view.findViewById(R.id.ll_home_section_activities_future_content);
+		LinearLayout entry;
+
+		//An inflater
+		LayoutInflater factory = LayoutInflater.from(getActivity());
+
+		//Get data from the database of the future activities
+		SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+		Cursor cursor = db.rawQuery("SELECT id, date, city, title_" + currLang+ " AS title, text_" + currLang + " AS text, price FROM activity WHERE date >= date('now') ORDER BY date DESC LIMIT 2;", null);
+
+		//If there are future activities...
+		if (cursor.getCount() > 0) {
+
+			//Show section
+			LinearLayout llActivitiesFuture = (LinearLayout) view.findViewById(R.id.ll_home_section_activities_future);
+			llActivitiesFuture.setVisibility(View.VISIBLE);
+
+			//Set click listener
+			llActivitiesFuture.setOnClickListener(new OnClickListener(){
+				@Override
+				public void onClick(View v) {
+					((MainActivity) getActivity()).loadSection(GM.SECTION_ACTIVITIES, false);
+				}
+			});
+
+			//Print rows
+			while (cursor.moveToNext()) {
+				//Create a new row
+				entry = (LinearLayout) factory.inflate(R.layout.row_home_activities, null);
+
+				//Set margins
+				LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+				layoutParams.setMargins(10, 10, 10, 25);
+				entry.setLayoutParams(layoutParams);
+
+				//Set title
+				TextView tvTitle = (TextView) entry.findViewById(R.id.tv_row_home_activity_title);
+				tvTitle.setText(cursor.getString(3));
+
+				//Set city
+				TextView tvCity = (TextView) entry.findViewById(R.id.tv_row_home_activity_city);
+				tvCity.setText(cursor.getString(2));
+
+				//Set price
+				TextView tvPrice = (TextView) entry.findViewById(R.id.tv_row_home_activity_price);
+				tvPrice.setText(cursor.getString(5) + "€");
+
+				//Set text
+				String text = Html.fromHtml(cursor.getString(4)).toString();
+				if (text.length() > 100) {
+					text = text.substring(0, 100) + "...";
+				}
+				TextView tvText = (TextView) entry.findViewById(R.id.tv_row_home_activity_text);
+				tvText.setText(text);
+
+				//Set date
+				TextView tvDate = (TextView) entry.findViewById(R.id.tv_row_home_activity_date);
+				tvDate.setText(GM.formatDate(cursor.getString(1) + " 00:00:00", currLang, false));
+
+				//Set hidden id
+				TextView tvId = (TextView) entry.findViewById(R.id.tv_row_home_activity_hidden);
+				tvId.setText(cursor.getString(0));
+
+				//Get image
+				ImageView iv = (ImageView) entry.findViewById(R.id.iv_row_home_activity);
+				Cursor cursorImage = db.rawQuery("SELECT image FROM activity_image WHERE activity = " + cursor.getString(0) + " ORDER BY idx LIMIT 1;", null);
+				if (cursorImage.getCount() > 0) {
+					cursorImage.moveToFirst();
+					String image = cursorImage.getString(0);
+
+					//Check if image exists
+					File f;
+					f = new File(this.getContext().getFilesDir().toString() + "/img/actividades/miniature/" + image);
+					if (f.exists()) {
+						//If the image exists, set it.
+						Bitmap myBitmap = BitmapFactory.decodeFile(this.getContext().getFilesDir().toString() + "/img/actividades/miniature/" + image);
+						iv.setImageBitmap(myBitmap);
+					} else {
+						//If not, create directories and download asynchronously
+						File fpath;
+						fpath = new File(this.getContext().getFilesDir().toString() + "/img/actividades/miniature/");
+						fpath.mkdirs();
+						new DownloadImage(GM.SERVER + "/img/actividades/miniature/" + image, this.getContext().getFilesDir().toString() + "/img/actividades/miniature/" + image, iv).execute();
+					}
+				}
+
+				//Set onCLickListener
+				entry.setOnClickListener(new View.OnClickListener() {
+					@Override
+					public void onClick(View v) {
+						//Toast.makeText(getActivity(), "OPENING POST", Toast.LENGTH_LONG).show();
+						Fragment fragment = new ActivityFutureLayout();
+						Bundle bundle = new Bundle();
+						//Pass post id
+						int id = Integer.parseInt(((TextView) v.findViewById(R.id.tv_row_activity_future_hidden)).getText().toString());
+						bundle.putInt("activity", id);
+						fragment.setArguments(bundle);
+
+						FragmentManager fm = HomeLayout.this.getActivity().getSupportFragmentManager();
+						FragmentTransaction ft = fm.beginTransaction();
+
+						ft.replace(R.id.activity_main_content_fragment, fragment);
+						ft.addToBackStack("activity_" + id);
+						ft.commit();
+					}
+				});
+
+				//Add to the list
+				llList.addView(entry);
+				counter++;
+			}
+		}
+
+		//Close db
+		cursor.close();
+		db.close();
+
+		return counter;
+	}
+
+	/**
+	 * Populates the Blog section of the home screen.
+	 * Adds two rows with the two latest posts. Tapping them takes to the post, tapping anywhere else, to the blog section.
+	 *
+	 * @return The number of entries shown
+	 */
+	private int setUpBlog(View view){
+
+		int counter = 0;
+
+		LinearLayout llBlog = (LinearLayout) view.findViewById(R.id.ll_home_section_blog);
+		llBlog.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				((MainActivity) getActivity()).loadSection(GM.SECTION_BLOG, false);
+			}
+		});
+
+		//Assign elements
+		LinearLayout llList = (LinearLayout) view.findViewById(R.id.ll_home_section_blog_content);
+		LinearLayout entry;
+
+		//An inflater
+		LayoutInflater factory = LayoutInflater.from(getActivity());
+
+		SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+		final Cursor cursor;
+
+		//Get data from the database
+		cursor = db.rawQuery("SELECT id, title_" + currLang+ " AS title, text_" + currLang + " AS text, dtime FROM post ORDER BY dtime DESC LIMIT 2;", null);
+
+		//Loop
+		while (cursor.moveToNext()){
+
+			//Create a new row
+			entry = (LinearLayout) factory.inflate(R.layout.row_home_blog, null);
+
+			//Set margins
+			LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+			layoutParams.setMargins(10, 10, 10, 25);
+			entry.setLayoutParams(layoutParams);
+
+			//Set title
+			TextView tvTitle = (TextView) entry.findViewById(R.id.tv_row_home_blog_title);
+			tvTitle.setText(cursor.getString(1));
+
+			//Set text
+			String text = Html.fromHtml(cursor.getString(2)).toString();
+			if (text.length() > 100){
+				text = text.substring(0, 100) + "...";
+			}
+			TextView tvText = (TextView) entry.findViewById(R.id.tv_row_home_blog_text);
+			tvText.setText(text);
+
+			//Set date
+			TextView tvDate = (TextView) entry.findViewById(R.id.tv_row_home_blog_date);
+			tvDate.setText(GM.formatDate(cursor.getString(3), currLang, false));
+
+			//Set hidden id
+			TextView tvId = (TextView) entry.findViewById(R.id.tv_row_home_blog_hidden);
+			tvId.setText(cursor.getString(0));
+
+			//Get image
+			ImageView iv = (ImageView) entry.findViewById(R.id.iv_row_home_blog_image);
+			Cursor cursorImage = db.rawQuery("SELECT image FROM post_image WHERE post = " + cursor.getString(0) +" ORDER BY idx LIMIT 1;", null);
+			if (cursorImage.getCount() > 0){
+				cursorImage.moveToFirst();
+				String image = cursorImage.getString(0);
+
+				//Check if image exists
+				File f;
+				f = new File(this.getContext().getFilesDir().toString() + "/img/blog/miniature/" + image);
+				if (f.exists()){
+					//If the image exists, set it.
+					Bitmap myBitmap = BitmapFactory.decodeFile(this.getContext().getFilesDir().toString() + "/img/blog/miniature/" + image);
+					iv.setImageBitmap(myBitmap);
+				}
+				else {
+					//If not, create directories and download asynchronously
+					File fpath;
+					fpath = new File(this.getContext().getFilesDir().toString() + "/img/blog/miniature/");
+					fpath.mkdirs();
+					new DownloadImage(GM.SERVER + "/img/blog/miniature/" + image, this.getContext().getFilesDir().toString() + "/img/blog/miniature/" + image, iv).execute();
+				}
+			}
+
+			//Set onCLickListener
+			entry.setOnClickListener(new View.OnClickListener(){
+				@Override
+				public void onClick(View v) {
+				Fragment fragment = new PostLayout();
+				Bundle bundle = new Bundle();
+				//Pass post id
+				int id = Integer.parseInt(((TextView) v.findViewById(R.id.tv_row_home_blog_hidden)).getText().toString());
+				bundle.putInt("post", id);
+				fragment.setArguments(bundle);
+
+				FragmentManager fm = HomeLayout.this.getActivity().getSupportFragmentManager();
+				FragmentTransaction ft = fm.beginTransaction();
+
+				ft.replace(R.id.activity_main_content_fragment, fragment);
+				ft.addToBackStack("post_" + id);
+				ft.commit();
+				}
+			});
+
+			//Add to the list
+			llList.addView(entry);
+
+			counter ++;
+		}
+
+		//Close database
+		cursor.close();
+		db.close();
+
+		return counter;
+	}
+
+	/**
+	 * Calculates the total prize in the prices dialog and shows the total.
+	 * 
+	 * @param v A view to be able to get a context.
+	 * 
+	 * @return The total price
+	 */
+	private int calculatePrice(Dialog v){
+		
+		//Locate views
+		CheckBox[] cbDayName = new CheckBox[6];
+		cbDayName[0] = (CheckBox) v.findViewById(R.id.cb_dialog_prices_0);
+		cbDayName[1] = (CheckBox) v.findViewById(R.id.cb_dialog_prices_1);
+		cbDayName[2] = (CheckBox) v.findViewById(R.id.cb_dialog_prices_2);
+		cbDayName[3] = (CheckBox) v.findViewById(R.id.cb_dialog_prices_3);
+		cbDayName[4] = (CheckBox) v.findViewById(R.id.cb_dialog_prices_4);
+		cbDayName[5] = (CheckBox) v.findViewById(R.id.cb_dialog_prices_5);
+		TextView tvTotal = (TextView) v.findViewById(R.id.tv_dialog_prices_total);
+		
+		//Open database
+		SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+		Cursor cursor = db.rawQuery("SELECT price FROM day ORDER BY id;", null);
+		
+		//Loop simultaneously the db entries and the checkboxes
+		ArrayList<Integer> price = new ArrayList<Integer>();
+		int i = 0;
+		int total = 0;
+		int selected = 0;
+		while (cursor.moveToNext() && i < 6){
+			if (cbDayName[i].isChecked()){
+				price.add(cursor.getInt(0));
+				selected ++;
+				total = total + cursor.getInt(0);
+			}
+			i ++;
+		}
+		
+		//Get offers
+		cursor = db.rawQuery("SELECT price, days FROM offer ORDER BY id;", null);
+		boolean offerApplied = false;
+		while (cursor.moveToNext()){
+			
+			//If selected days equal the days in the ofer, fix the price
+			if (cursor.getInt(1) == selected){
+				total = cursor.getInt(0);
+				offerApplied = true;
+			}
+		}
+		
+		//Offer + single days
+		if (offerApplied == false){
+			Collections.sort(price);
+			Cursor closestOffer = db.rawQuery("SELECT price, days FROM offer WHERE days < " + Integer.toString(selected) + " ORDER BY days DESC LIMIT 1;", null);
+			if (closestOffer.getCount() == 1){
+				closestOffer.moveToNext();
+				total = closestOffer.getInt(0);
+				int difference = selected - closestOffer.getInt(1);
+				i = 0;
+				while (i < difference && price.size() > i){
+					total = total + price.get(i);
+					i ++;
+				}
+			}
+		}
+		
+		//Set text
+		tvTotal.setText(v.getContext().getResources().getString(R.string.prices_total) + " " + total + v.getContext().getResources().getString(R.string.eur));
+		
+		//Return the total price
+		return total;
+	}
+
+	/**
+	 * Starts the map in the dialogs.
+	 */
+	public void startMap(){
+		mapView.getMapAsync(this);
+	}
+	
+	
+	/**
+	 * Called when the map is ready to be displayed. 
+	 * Sets the map options and a marker for the map.
+	 * 
+	 * @param googleMap The map to be shown
+	 * 
+	 * @see com.google.android.gms.maps.OnMapReadyCallback#onMapReady(com.google.android.gms.maps.GoogleMap)
+	 */
+	@Override
+	public void onMapReady(GoogleMap googleMap) {
+		this.map = googleMap;
+		map.setMyLocationEnabled(true);
+		
+		map.getUiSettings().setMyLocationButtonEnabled(false);
+		map.setMyLocationEnabled(true);
+		// Needs to call MapsInitializer before doing any CameraUpdateFactory calls
+		try {
+			MapsInitializer.initialize(this.getActivity());
+			CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(location, 14);
+			map.animateCamera(cameraUpdate);
+		}
+		catch (Exception e) {
+			Log.e("Error initializing maps", e.toString());
+		}
+		//Set GM marker
+		MarkerOptions mo = new MarkerOptions();
+		mo.title(markerName);
+		mo.position(location);
+		map.addMarker(mo);
+		
+	}
+	
+	/**
+	 * Called when the user location changes. 
+	 * Recalculates the list of around events and calls updateLocation() to 
+	 * update the distance in the location section.
+	 * 
+	 * @param location The new location
+	 * 
+	 * @see android.location.LocationListener#onLocationChanged(android.location.Location)
+	 */
+	@Override
+	public void onLocationChanged(Location location) {
+		coordinates[0] = location.getLatitude();
+		coordinates[1] = location.getLongitude();
+		//updateLocation();
+		//populateAround();
+		
+	}
+
+	/**
+     * Called when the location provider changes it's state. 
+     * Recalculates the list of events in the around section.
+     * 
+     * @param provider The name of the provider
+     * @param status Status code of the provider
+     * @param extras Extras passed 
+     * 
+     * @see android.location.LocationListener#onStatusChanged(java.lang.String, int, android.os.Bundle)
+     */
+	@Override
+	public void onStatusChanged(String provider, int status, Bundle extras) {
+		//populateAround();
+	}
+
+	
+	/**
+     * Called when a location provider is enabled.
+     * Recalculates the list of events.
+     * 
+     * @param provider The name of the provider
+     * 
+     * @see android.location.LocationListener#onProviderEnabled(java.lang.String)
+     */
+	@Override
+	public void onProviderEnabled(String provider) {
+		//populateAround();
+	}
+
+	/**
+     * Called when a location provider is disabled. 
+     * Recalculates the list of events.
+     * 
+     * @param provider The name of the provider
+     * 
+     * @see android.location.LocationListener#onProviderDisabled(java.lang.String)
+     */
+	@Override
+	public void onProviderDisabled(String provider) {
+		//populateAround();
+		
+	}
+	
+	/**
+	 * Called when the fragment is paused. 
+	 * Stops the location manager
+	 * @see android.support.v4.app.Fragment#onPause()
+	 */
+	@Override
+	public void onPause(){
+		locationManager.removeUpdates(this);
+		if (map != null)
+			map.setMyLocationEnabled(false);
+		if (mapView != null){
+			mapView.onPause();
+		}
+		super.onPause();
+	}
+	
+	/**
+	 * Called when the fragment is brought back into the foreground. 
+	 * Resumes the map and the location manager.
+	 * 
+	 * @see android.support.v4.app.Fragment#onResume()
+	 */
+	@Override
+	public void onResume(){
+		if (mapView != null)
+			mapView.onResume();
+		if (map != null)
+			map.setMyLocationEnabled(true);
+		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 5, this);
+		super.onResume();
+	}
+	
+	/**
+	 * Called when the fragment is destroyed. 
+	 * Finishes the map. 
+	 * 
+	 * @see android.support.v4.app.Fragment#onDestroy()
+	 */
+	@Override
+	public void onDestroy() {
+		super.onDestroy();
+		if (map != null)
+			map.setMyLocationEnabled(false);
+		if (mapView != null){
+			mapView.onResume();
+			mapView.onDestroy();
+		}
+	}
+
+	/**
+	 * Called in a situation of low memory.
+	 * Lets the map handle this situation.
+	 * 
+	 * @see android.support.v4.app.Fragment#onLowMemory()
+	 */
+	@Override
+	public void onLowMemory() {
+		super.onLowMemory();
+		if (mapView != null){
+			mapView.onResume();
+			mapView.onLowMemory();
+		}
+	}
+}

+ 10 - 0
app/src/main/java/com/ivalentin/gm/LablancaLayout.java

@@ -0,0 +1,10 @@
+package com.ivalentin.gm;
+
+import android.support.v4.app.Fragment;
+
+/**
+ * Created by seavenois on 09/06/16.
+ */
+public class LablancaLayout extends Fragment {
+
+}

+ 293 - 0
app/src/main/java/com/ivalentin/gm/LocationLayout.java

@@ -0,0 +1,293 @@
+package com.ivalentin.gm;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+import com.google.android.gms.maps.CameraUpdate;
+import com.google.android.gms.maps.CameraUpdateFactory;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.MapView;
+import com.google.android.gms.maps.MapsInitializer;
+import com.google.android.gms.maps.OnMapReadyCallback;
+import com.google.android.gms.maps.model.BitmapDescriptorFactory;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.MarkerOptions;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+//TODO: Try to fetch a new location report when created
+
+/**
+ * Section that shows a map with the location of Gasteizko Margolariak. 
+ * If no recent report location, it will explain that and will show the 
+ * next scheduled activity. 
+ * 
+ * @author Iñigo Valentin
+ * 
+ * @see Fragment
+ * @see OnMapReadyCallback
+ *
+ */
+public class LocationLayout extends Fragment implements OnMapReadyCallback{
+	
+	//The map view
+	private MapView mapView;
+	
+	//The map
+	private GoogleMap map;
+	
+	//Locations for the user and Gasteizko Margolariak
+	private LatLng location, gmLocation;
+	
+	//The main View
+	private View v;
+
+	/**
+	 * Run when the fragment is inflated.
+	 * 
+	 * @param inflater A LayoutInflater to manage views
+	 * @param container The container View
+	 * @param savedInstanceState Bundle containing the state
+	 * 
+	 * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
+	 */
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
+		
+		//Get the view
+		v = inflater.inflate(R.layout.fragment_layout_location, container, false);
+		
+		//Set the title
+		((MainActivity) getActivity()).setSectionTitle(v.getContext().getString(R.string.menu_lablanca_location));
+		
+		//LinearLayouts to be shown or hidden
+		LinearLayout llReport = (LinearLayout) v.findViewById(R.id.ll_fragment_location_reported);
+		LinearLayout llNoReport = (LinearLayout) v.findViewById(R.id.ll_fragment_location_no_reported);
+		
+		//Get preferences
+		SharedPreferences settings = v.getContext().getSharedPreferences(GM.PREF, Context.MODE_PRIVATE);
+		
+		//Get current date and time string formatters
+		Calendar cal;
+		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
+		SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd-", Locale.US);
+		SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.US);
+		Date date = new Date();
+		
+		//Variable to indicate if there is a report
+		boolean reporting = false;
+		
+		//Button to show the GM schedule if no report
+		Button btSchedule = (Button) v.findViewById(R.id.bt_location_no_report);
+		btSchedule.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				((MainActivity) getActivity()).loadSection(GM.SECTION_LABLANCA_GM_SCHEDULE, false);
+			}
+		});
+		
+		//Try to get last location time
+		try{
+			Date locationDate = dateFormat.parse(settings.getString(GM.PREF_GM_LOCATION, "1970-01-01 00:00:00"));
+			cal = Calendar.getInstance();
+		    cal.setTime(date);
+		    cal.add(Calendar.MINUTE, -10);
+		    
+		    //If the last location report is recent
+		    if (cal.getTime().before(locationDate))
+		    	reporting = true;
+		}
+		catch (Exception ex){
+			Log.e("Error parsing d ate", ex.toString());
+		}
+		
+		//If there is a location report
+		if (reporting){
+			llNoReport.setVisibility(View.GONE);
+			//Get location passed to the app
+			Bundle bundle = this.getArguments();
+			location = new LatLng(bundle.getDouble("lat", 0), bundle.getDouble("lon", 0));
+			
+			mapView = (MapView) v.findViewById(R.id.mapview);
+			mapView.onCreate(savedInstanceState);
+	 
+			// Gets to GoogleMap from the MapView and does initialization stuff
+			mapView.getMapAsync(this);
+	    }
+		
+		//If there is no location report, try to show the next event where Margolariak will be
+	    else{
+	    	llReport.setVisibility(View.GONE);
+	    	TextView tvLocation = (TextView) v.findViewById(R.id.tv_location_schedule);
+	    	
+	    	//Initialize the database
+	    	SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);;
+			Cursor cursor = db.rawQuery("SELECT schedule, gm, event.name, event.description, place.name, address, lat, lon, start, end, host FROM event, place WHERE gm = 1 AND event.place = place.id ORDER BY start;", null);
+			Date startMinus24, startPlus30, start, end;
+			boolean found = false;
+			
+			//Loop db entries until we find the next event
+			while (cursor.moveToNext() && found == false){
+				try{
+					
+					//Set limit dates to see if the event is suitable
+					start = dateFormat.parse(cursor.getString(8));
+					cal = Calendar.getInstance();
+				    cal.setTime(dateFormat.parse(cursor.getString(8)));
+				    cal.add(Calendar.HOUR_OF_DAY, -24);
+				    startMinus24 = cal.getTime();
+				    cal = Calendar.getInstance();
+				    cal.setTime(dateFormat.parse(cursor.getString(8)));
+				    cal.add(Calendar.MINUTE, 30);
+				    startPlus30 = cal.getTime();
+				    
+				    //If end set and now between start and end
+				    if (found == false && cursor.getString(9) != null){
+				    	end = dateFormat.parse(cursor.getString(9));
+				    	if (date.after(start) && date.before(end)){
+				    		found = true;
+				    		//Set text
+				    		tvLocation.setText(String.format(v.getContext().getString(R.string.location_now), cursor.getString(4)));
+				    	}
+				    }
+				    
+				    //If end not set and now between start and start + 30 min
+				    if (found == false && cursor.getString(9) == null){
+				    	if (date.after(start) && date.before(startPlus30)){
+				    		found = true;
+				    		//Set text
+				    		tvLocation.setText(String.format(v.getContext().getString(R.string.location_now), cursor.getString(4)));
+				    	}
+				    }
+				    
+				    //If now between start -24h and start
+				    if (found == false && date.after(startMinus24) && date.before(start)){
+				    	found = true;
+				    	//Get date start
+				    	Date dateS = dateFormat.parse((cursor.getString(8)));
+				    	//Switch between today, tomorrow
+				    	if (dayFormat.format(start).equals(dayFormat.format(date)))
+				    		tvLocation.setText(String.format(v.getContext().getString(R.string.location_today), timeFormat.format(dateS), cursor.getString(4)));
+				    	else
+				    		tvLocation.setText(String.format(v.getContext().getString(R.string.location_tomorrow), timeFormat.format(dateS), cursor.getString(4)));
+				    }
+					
+				}
+				catch (Exception e){
+					Log.e("Error parsing date", e.toString());
+				}
+				
+				//If no events found, hide text.
+				if (found == false){
+					tvLocation.setVisibility(View.GONE);
+				}
+				else{
+					tvLocation.setVisibility(View.VISIBLE);
+				}
+			}
+			
+			//Close the cursor
+			cursor.close();
+	    	
+	    }
+		
+		//Return the view
+		return v;
+	}
+
+	/**
+	 * Called when the fragment is bought back to the foreground. 
+	 * Ensures that the map is displayed then.
+	 * 
+	 * @see android.support.v4.app.Fragment#onResume()
+	 */
+	@Override
+	public void onResume() {
+		if (mapView != null)
+			mapView.onResume();
+		super.onResume();
+	}
+
+	/**
+	 * Called when the fragment is destroyed. 
+	 * Ensures that the map is destroyed then.
+	 * 
+	 * @see android.support.v4.app.Fragment#onDestroy()
+	 */
+	@Override
+	public void onDestroy() {
+		super.onDestroy();
+		if (mapView != null){
+			mapView.onResume();
+			mapView.onDestroy();
+		}
+	}
+
+	/**
+	 * Called in a situation of low memory. 
+	 * It let's the mapView handle the situation.
+	 * 
+	 * @see android.support.v4.app.Fragment#onLowMemory()
+	 */
+	@Override
+	public void onLowMemory() {
+		super.onLowMemory();
+		if (mapView != null){
+			mapView.onResume();
+			mapView.onLowMemory();
+		}
+	}
+
+	/**
+	 * Called when the map is ready to be used. 
+	 * Initializes it and sets the Gasteizko Margolariak marker.
+	 * 
+	 * @param googleMap the map
+	 * 
+	 * @see com.google.android.gms.maps.OnMapReadyCallback#onMapReady(com.google.android.gms.maps.GoogleMap)
+	 */
+	@Override
+	public void onMapReady(GoogleMap googleMap) {
+		this.map = googleMap;
+		map.setMyLocationEnabled(true);
+		
+		map.getUiSettings().setMyLocationButtonEnabled(false);
+		map.setMyLocationEnabled(true);
+		// Needs to call MapsInitializer before doing any CameraUpdateFactory calls
+		try {
+			MapsInitializer.initialize(this.getActivity());
+			CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(location, 14);
+			map.animateCamera(cameraUpdate);
+		} catch (Exception e) {
+			Log.e("Error initializing maps", e.toString());
+		}
+		
+		//Set GM marker
+		SharedPreferences settings = v.getContext().getSharedPreferences(GM.PREF, Context.MODE_PRIVATE);
+		Double lat = Double.parseDouble(settings.getString(GM.PREF_GM_LATITUDE, ""));
+		Double lon = Double.parseDouble(settings.getString(GM.PREF_GM_LONGITUDE, ""));
+		gmLocation = new LatLng(lat, lon);
+		MarkerOptions moGm = new MarkerOptions();
+		moGm.title(v.getContext().getString(R.string.app_name));
+		moGm.position(gmLocation);
+		moGm.icon(BitmapDescriptorFactory.fromResource(R.drawable.pinpoint_gm));
+		map.addMarker(moGm);
+		
+	}
+
+}

+ 568 - 0
app/src/main/java/com/ivalentin/gm/MainActivity.java

@@ -0,0 +1,568 @@
+package com.ivalentin.gm;
+
+import java.io.File;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.content.res.ResourcesCompat;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.drawable.Drawable;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+/**
+ * The main Activity of the app. It's actually the only activity, and it loads other fragments.
+ * 
+ * @author Iñigo Valentin
+ *
+ */
+public class MainActivity extends AppCompatActivity implements LocationListener{
+		
+	//Set of GPS coordinates
+	private double[] coordinates = new double[2];
+	
+	//The main layout of the app
+	private MainLayout mLayout;
+	
+	//The location manager to get GPS coordinates
+	private LocationManager locationManager;
+	
+	//GPS coordinates provider
+	private String provider;
+	
+	//Alarm to get location
+	AlarmReceiver alarm;
+		
+	/**
+	 * Loads a section in the main screen.
+	 * 
+	 * @param section Section identifier {@see GM}
+	 * @param fromSliderMenu Indicates if the call has been made from the slider menu, so it can be closed.
+	 */
+	public void loadSection (byte section, boolean fromSliderMenu){
+		FragmentManager fm = MainActivity.this.getSupportFragmentManager();
+		FragmentTransaction ft = fm.beginTransaction();
+		Fragment fragment = null;
+		String title = "";
+		Bundle bundle = new Bundle();
+		switch (section){
+			case GM.SECTION_HOME:
+				fragment = new HomeLayout();
+				//Pass current GPS coordinates
+				bundle.putDouble("lat", coordinates[0]);
+				bundle.putDouble("lon", coordinates[1]);
+				fragment.setArguments(bundle);
+				title = getString(R.string.menu_home);
+				break;
+
+			case GM.SECTION_LOCATION:
+				fragment = new LocationLayout();
+				//Pass current GPS coordinates
+				bundle.putDouble("lat", coordinates[0]);
+				bundle.putDouble("lon", coordinates[1]);
+				fragment.setArguments(bundle);
+				title = getString(R.string.menu_lablanca_location);
+				break;
+
+			case GM.SECTION_LABLANCA:
+				fragment = new LablancaLayout();
+				//Pass current GPS coordinates
+				bundle.putDouble("lat", coordinates[0]);
+				bundle.putDouble("lon", coordinates[1]);
+				fragment.setArguments(bundle);
+				title = getString(R.string.menu_lablanca);
+				break;
+
+			case GM.SECTION_LABLANCA_SCHEDULE:
+				fragment = new ScheduleLayout();
+				bundle.putInt(GM.SCHEDULE, GM.SECTION_LABLANCA_SCHEDULE);
+				fragment.setArguments(bundle);
+				title = getString(R.string.menu_lablanca_schedule);
+				break;
+
+			case GM.SECTION_LABLANCA_GM_SCHEDULE:
+				fragment = new ScheduleLayout();
+				bundle.putInt(GM.SCHEDULE, GM.SECTION_LABLANCA_GM_SCHEDULE);
+				fragment.setArguments(bundle);
+				title = getString(R.string.menu_lablanca_gm_schedule);
+				break;
+
+			case GM.SECTION_LABLANCA_AROUND:
+				fragment = new AroundLayout();
+				//Pass current GPS coordinates
+				bundle.putDouble("lat", coordinates[0]);
+				bundle.putDouble("lon", coordinates[1]);
+				fragment.setArguments(bundle);
+				title = getString(R.string.menu_lablanca_around);
+				break;
+
+			case GM.SECTION_ACTIVITIES:
+				fragment = new ActivityLayout();
+				title = getString(R.string.menu_activities);
+				break;
+
+			case GM.SECTION_BLOG:
+				fragment = new BlogLayout();
+				title = getString(R.string.menu_blog);
+				break;
+
+			case GM.SECTION_GALLERY:
+				fragment = new GalleryLayout();
+				title = getString(R.string.menu_blog);
+				break;
+
+			case GM.SECTION_ABOUT:
+				fragment = new AboutLayout();
+				title = getString(R.string.menu_about);
+				break;
+
+			case GM.SECTION_SETTINGS:
+				fragment = new SettingsLayout();
+				title = getString(R.string.menu_settings);
+				break;
+		}
+		
+		//Replace the fragment.
+		ft.replace(R.id.activity_main_content_fragment, fragment);
+		ft.addToBackStack(title);
+		ft.commit();
+		setSectionTitle(title);
+		
+		//If calling from the menu, close it.
+		if (fromSliderMenu)
+			mLayout.toggleMenu();
+	}
+	
+	
+	/**
+	 * Sets the title of the current section.
+	 * 
+	 * @param title The title of the current section.
+	 */
+	public void setSectionTitle(String title){
+		TextView tvTitle = (TextView) findViewById(R.id.activity_main_content_title); 
+		tvTitle.setText(title);
+	}
+	
+	/** 
+	 * Run when the app resumes. It's extended to request
+	 * location updates when the app is resumed.
+	 * 
+	 * @see android.support.v4.app.FragmentActivity#onResume()
+	 */
+	@Override
+	protected void onResume() {
+		super.onResume();
+		alarm.onReceive(this, this.getIntent());
+		locationManager.requestLocationUpdates(provider, GM.LOCATION_ACCURACY, 1, this);
+	}
+
+	/**
+	 * Run when the app is paused.Extended to remove the location
+	 * listener updates when the Activity is paused.
+	 *  
+	 * @see android.support.v4.app.FragmentActivity#onPause()
+	 */
+	@Override
+	protected void onPause() {
+		super.onPause();
+		locationManager.removeUpdates(this);
+	}
+
+	/**
+	 * Called when the location is updated.
+	 * 
+	 * @param location The updated location.
+	 * 
+	 * @see android.location.LocationListener#onLocationChanged(android.location.Location)
+	 * 
+	 */
+	@Override
+	public void onLocationChanged(Location location) {
+		coordinates[0] = location.getLatitude();
+		coordinates[1] = location.getLongitude();
+	}
+
+	/**
+	 * Extended for nothing. Needed because the class implements LocationListener.
+	 * 
+	 * @see android.location.LocationListener#onStatusChanged(java.lang.String, int, android.os.Bundle)
+	 */
+	@Override
+	public void onStatusChanged(String provider, int status, Bundle extras) {}
+	
+	/**
+	 * Extended for nothing. Needed because the class implements LocationListener.
+	 * 
+	 * @see android.location.LocationListener#onProviderEnabled(java.lang.String)
+	 */
+	@Override
+	public void onProviderEnabled(String provider) {}
+
+	/**
+	 * Extended for nothing. Needed because the class implements LocationListener.
+	 * 
+	 * @see android.location.LocationListener#onProviderDisabled(java.lang.String)
+	 */
+	@Override
+	public void onProviderDisabled(String provider) {}
+	  
+	  
+	/**
+	 * Runs when the activity is created. 
+	 * 
+	 * @param savedInstanceState Saved state of the activity.
+	 * 
+	 * @see android.support.v7.app.AppCompatActivity#onCreate(android.os.Bundle)
+	 */
+	//@SuppressLint("TrulyRandom") //I don't care about getting "potentially unsecured numbers" here
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		
+		//Set the location manager.
+	    locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
+	   	locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 5, this);
+	    
+	    //Define the criteria how to select the location provider: use default.
+	    Criteria criteria = new Criteria();
+	    provider = locationManager.getBestProvider(criteria, false);
+	    Location location = locationManager.getLastKnownLocation(provider);
+
+	    //Get intent extras
+	    String action = getIntent().getStringExtra(GM.EXTRA_ACTION);
+	    String actionText = getIntent().getStringExtra(GM.EXTRA_TEXT);
+	    String actionTitle = getIntent().getStringExtra(GM.EXTRA_TITLE);
+	    
+	    // Initialize the location fields.
+	    if (location != null){
+	    	//System.out.println("Provider " + provider + " has been selected.");
+	    	onLocationChanged(location);
+	    }
+	    else{
+	    	Log.e("Location", "Location not available");
+	    }
+
+		//Set an alarm for notifications..
+	    alarm = new AlarmReceiver();
+		alarm.setAlarm(this);
+		alarm.onReceive(this, this.getIntent());
+		
+		//Remove title bar.
+	    this.supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
+	    super.onCreate(savedInstanceState);
+	    
+	    //Set layout.
+		setContentView(R.layout.activity_main);
+		mLayout = (MainLayout) findViewById(R.id.main_layout);
+		
+		//Assign menu button
+		ImageButton btMenu = (ImageButton) findViewById(R.id.bt_menu); 
+		btMenu.setOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View v) { mLayout.toggleMenu(); }
+		});
+		
+		//Assign menu items and icons
+		TextView menuItem[] = new TextView[8];
+		menuItem[0] = (TextView) findViewById(R.id.menu_home);
+		menuItem[1] = (TextView) findViewById(R.id.menu_location);
+		menuItem[2] = (TextView) findViewById(R.id.menu_lablanca);
+		menuItem[3] = (TextView) findViewById(R.id.menu_activities);
+		menuItem[4] = (TextView) findViewById(R.id.menu_blog);
+		menuItem[5] = (TextView) findViewById(R.id.menu_gallery);
+		menuItem[6] = (TextView) findViewById(R.id.menu_about);
+		menuItem[7] = (TextView) findViewById(R.id.menu_settings);
+
+		//Assign buttons for la blanca submenu
+		TextView menuLablancaItem[] = new TextView[3];
+		menuLablancaItem[0] = (TextView) findViewById(R.id.menu_lablanca_schedule);
+		menuLablancaItem[1] = (TextView) findViewById(R.id.menu_lablanca_gm_schedule);
+		menuLablancaItem[2] = (TextView) findViewById(R.id.menu_lablanca_around);
+
+		//Set click listers for menu items
+		menuItem[0].setOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View v) { loadSection(GM.SECTION_HOME, true); }
+		});
+		menuItem[1].setOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View v) { loadSection(GM.SECTION_LOCATION, true); }
+		});
+		menuItem[2].setOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View v) { loadSection(GM.SECTION_LABLANCA, true); }
+		});
+		menuItem[3].setOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View v) { loadSection(GM.SECTION_ACTIVITIES, true); }
+		});
+		menuItem[4].setOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View v) { loadSection(GM.SECTION_BLOG, true); }
+		});
+		menuItem[5].setOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View v) { loadSection(GM.SECTION_GALLERY, true); }
+		});
+		menuItem[6].setOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View v) { loadSection(GM.SECTION_ABOUT, true); }
+		});
+		menuItem[7].setOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View v) { loadSection(GM.SECTION_SETTINGS, true); }
+		});
+		menuLablancaItem[0].setOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View v) { loadSection(GM.SECTION_LABLANCA_SCHEDULE, true); }
+		});
+		menuLablancaItem[1].setOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View v) { loadSection(GM.SECTION_LABLANCA_GM_SCHEDULE, true); }
+		});
+		menuLablancaItem[2].setOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View v) { loadSection(GM.SECTION_LABLANCA_AROUND, true); }
+		});
+
+		//If the user code is not set, generate one
+		SharedPreferences preferences = getSharedPreferences(GM.PREF, Context.MODE_PRIVATE);
+		if (preferences.getString(GM.USER_CODE, "").length() == 0){
+			SecureRandom random = new SecureRandom();
+			String newCode = new BigInteger(130, random).toString(32).substring(0, 8);
+			SharedPreferences.Editor editor = preferences.edit();
+			editor.putString(GM.USER_CODE, newCode);
+			editor.apply();
+		}
+		
+		//If the database doesn't exist, create it.
+		if (!databaseExists()){
+        	Log.i("DB status", "Database not found. Creating it...");
+        	createDatabase();
+        }
+		
+		//If its the first time
+		if (preferences.getInt(GM.PREF_DB_VERSION, GM.DEFAULT_PREF_DB_VERSION) == GM.DEFAULT_PREF_DB_VERSION){
+			initialSync();
+		}
+		//If t's not the first time
+		else{
+			//Sync db
+			sync();
+			
+			//Load initial section
+			loadSection(GM.SECTION_HOME, false);
+			
+			//If the intent had extras (from notifications), do something
+			if (actionText != null){
+				TextView tvDialogTitle, tvDialogText;
+				Button btDialogClose, btDialogAction;
+				Drawable dialogIcon;
+				if (actionTitle != null){
+					
+					//Create a dialog
+					final Dialog dialog = new Dialog(this);
+					
+					//Set up dialog window
+					dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+					dialog.setContentView(R.layout.dialog_notification);
+					
+					//Set title
+					tvDialogTitle = (TextView) dialog.findViewById(R.id.tv_dialog_notification_title);
+					tvDialogTitle.setText(actionTitle);
+					
+					//Set text
+					tvDialogText = (TextView) dialog.findViewById(R.id.tv_dialog_notification_text);
+					tvDialogText.setText(actionText);
+					
+					//Set close button
+					btDialogClose = (Button) dialog.findViewById(R.id.bt_dialog_notification_close);
+					btDialogClose.setOnClickListener(new OnClickListener() {
+		    			@Override
+		    			public void onClick(View v) {
+		    				dialog.dismiss();
+		    			}
+		    		});
+					
+					//Set the action button
+					btDialogAction = (Button) dialog.findViewById(R.id.bt_dialog_notification_action);
+					if (action != null){
+						switch (action) {
+							//If the notification action opens the GM schedule
+							case GM.EXTRA_ACTION_GM:
+								//Set the icon
+								dialogIcon = ResourcesCompat.getDrawable(getResources(), R.drawable.icon_gm, null);
+								dialogIcon.setBounds(0, 0, (int) (tvDialogTitle.getTextSize() * 1.4), (int) (tvDialogTitle.getTextSize() * 1.4));
+								tvDialogTitle.setCompoundDrawables(dialogIcon, null, null, null);
+								tvDialogTitle.setCompoundDrawablePadding(20);
+
+								//Set up the action button
+								btDialogAction.setVisibility(View.VISIBLE);
+								btDialogAction.setText(this.getApplicationContext().getString(R.string.notification_action_gm));
+								btDialogAction.setOnClickListener(new OnClickListener() {
+									@Override
+									public void onClick(View v) {
+										dialog.dismiss();
+										loadSection(GM.SECTION_LABLANCA_GM_SCHEDULE, false);
+									}
+								});
+								//}
+								break;
+
+							//If the notification action opens the city schedule
+							case GM.EXTRA_ACTION_SCHEDULE:
+								//Set the icon
+								dialogIcon = ResourcesCompat.getDrawable(getResources(), R.drawable.icon_program, null);
+								dialogIcon.setBounds(0, 0, (int) (tvDialogTitle.getTextSize() * 1.4), (int) (tvDialogTitle.getTextSize() * 1.4));
+								tvDialogTitle.setCompoundDrawables(dialogIcon, null, null, null);
+								tvDialogTitle.setCompoundDrawablePadding(20);
+
+								//Set up the action button
+								btDialogAction.setVisibility(View.VISIBLE);
+								btDialogAction.setText(this.getApplicationContext().getString(R.string.notification_action_schedule));
+								btDialogAction.setOnClickListener(new OnClickListener() {
+									@Override
+									public void onClick(View v) {
+										dialog.dismiss();
+										loadSection(GM.SECTION_LABLANCA_SCHEDULE, false);
+									}
+								});
+								//}
+								break;
+
+							//If the notification is just text
+							default:
+								//Set the icon
+								dialogIcon = ResourcesCompat.getDrawable(getResources(), R.drawable.icon_about, null);
+								dialogIcon.setBounds(0, 0, (int) (tvDialogTitle.getTextSize() * 1.4), (int) (tvDialogTitle.getTextSize() * 1.4));
+								tvDialogTitle.setCompoundDrawables(dialogIcon, null, null, null);
+								tvDialogTitle.setCompoundDrawablePadding(20);
+
+								//Hide action button
+								btDialogAction.setVisibility(View.GONE);
+						}
+					}
+					else{
+						btDialogAction.setVisibility(View.GONE);
+					}
+	
+					//Show the dialog
+					dialog.show();
+				}
+			}
+		}
+	}
+	
+	/**
+	 * Checks if the app database exists.
+	 * 
+	 * @return True if the database exists, false otherwise.
+	 */
+	private boolean databaseExists(){
+    	File database = getApplicationContext().getDatabasePath(GM.DB_NAME);
+		return database.exists();
+    }
+    
+    /**
+     * Creates the app database and fills it with the hard coded, default data.
+     */
+    private void createDatabase(){
+    	SQLiteDatabase db;
+    	try {
+    		//Create database
+    		db = this.openOrCreateDatabase(GM.DB_NAME, MODE_PRIVATE, null);
+
+			db.execSQL("CREATE TABLE IF NOT EXISTS activity (id INT, permalink VARCHAR, date DATETIME, city VARCHAR, title_es VARCHAR, title_en VARCHAR, title_eu VARCHAR, text_es VARCHAR, text_en VARCHAR, text_eu VARCHAR, after_es VARCHAR, after_en VARCHAR, after_eu VARCHAR, price INT, inscription INT, max_people INT, album INT, dtime DATETIME, comments INT);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS activity_comment (id INT, activity INT, text VARCHAR, dtime DATETIME, username VARCHAR, lang VARCHAR);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS activity_image (id INT, activity INT, image VARCHAR, idx INT);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS activity_itinerary (id INT, activity INT, name_es VARCHAR, name_en VARCHAR, name_eu VARCHAR, description_es VARCHAR, description_en VARCHAR, description_eu VARCHAR, start DATETIME, end DATETIME, place INT);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS activity_tag (activity INT, tag VARCHAR);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS album (id INT, permalink VARCHAR, name_es VARCHAR, name_en VARCHAR, name_eu VARCHAR, description_es VARCHAR, description_en VARCHAR, description_eu VARCHAR, open INT, time DATETIME);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS festival (id INT, year INT, text_es VARCHAR, text_en VARCHAR, text_eu VARCHAR, img VARCHAR);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS festival_day (id INT, date DATETIME, name_es VARCHAR, name_en VARCHAR, name_eu VARCHAR, price INT);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS festival_event (id INT, gm INT, title_es VARCHAR, title_en VARCHAR, title_eu VARCHAR, description_es VARCHAR, description_en VARCHAR, description_eu VARCHAR, host INT, place INT, start DATETIME, end DATETIME);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS festival_event_image (id INT, event INT, image VARCHAR, idx INT);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS festival_offer (id INT, year INT, name_es VARCHAR, name_en VARCHAR, name_eu VARCHAR, description_es VARCHAR, description_en VARCHAR, description_eu VARCHAR, days INT, price INT);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS location (id INT, dtime DATETIME, lat FLOAT, lon FLOAT, manual INT);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS notification (id INT, dtime DATETIME, duration INT, action VARCHAR, title_es VARCHAR, title_en VARCHAR, title_eu VARCHAR, text_es VARCHAR, text_en VARCHAR, text_eu VARCHAR, internal INT);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS people (id INT, name_es VARCHAR, name_en VARCHAR, name_eu VARCHAR, link VARCHAR);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS photo (id INT, file VARCHAR, permalink VARCHAR, title_es VARCHAR, title_en VARCHAR, title_eu VARCHAR, description_es VARCHAR, description_en VARCHAR, description_eu VARCHAR, dtime DATETIME, uploaded DATETIME, place INT, width INT, height INT, size INT, username VARCHAR);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS photo_album (photo INT, album INT);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS photo_comment (id INT, photo INT, text VARCHAR, dtime DATETIME, username VARCHAR, lang VARCHAR);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS place (id INT, name_es VARCHAR, name_en VARCHAR, name_eu VARCHAR, address_es VARCHAR, address_en VARCHAR, address_eu VARCHAR, cp VARCHAR, lat FLOAT, lon FLOAT);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS post (id INT, permalink VARCHAR, title_es VARCHAR, title_en VARCHAR, title_eu VARCHAR, text_es VARCHAR, text_en VARCHAR, text_eu VARCHAR, dtime DATETIME, comments INT);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS post_comment (id INT, post INT, text VARCHAR, dtime DATETIME, username VARCHAR, lang VARCHAR);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS post_image (id INT, post INT, image VARCHAR, idx INT);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS post_tag (post INT, tag VARCHAR);");
+			db.execSQL("CREATE TABLE IF NOT EXISTS settings (name VARCHAR, value VARCHAR);");
+			db.close();
+    	}
+    	catch (Exception ex){
+    		Log.e("Error creating database", ex.toString());
+    	}
+    }
+
+	/**
+	 * Performs a full sync against the remote database.
+	 */
+	public void sync(){
+		ProgressBar pbSync = (ProgressBar) findViewById(R.id.pb_sync);
+		new Sync(this, pbSync).execute();
+	}
+	
+	/**
+	 * Perform an initial sync before the app can be used. 
+	 * A dialog will block the UI. 
+	 * It is intended to be used only when the database is empty.
+	 */
+	private void initialSync(){
+		//Create a dialog
+		Dialog dialog = new Dialog(this);
+		dialog.setCancelable(false);
+		
+		//Set up the window
+		dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+		dialog.setContentView(R.layout.dialog_sync);
+		
+		//Sync
+		ProgressBar pbSync = (ProgressBar) findViewById(R.id.pb_sync);
+		new Sync(this, pbSync, dialog, this).execute();
+	}
+	
+	/**
+	 * Overrides onBackPressed(). 
+	 * Used to show the previous fragment instead of finishing the app.
+	 * 
+	 * @see android.support.v7.app.AppCompatActivity#onBackPressed()
+	 */
+	@Override
+	public void onBackPressed(){
+		FragmentManager fm = getSupportFragmentManager();
+		if (fm.getBackStackEntryCount() > 1){
+			fm.popBackStack();
+		}
+		else{
+			super.onBackPressed();
+		}
+		
+	}
+	
+}

+ 284 - 0
app/src/main/java/com/ivalentin/gm/MainLayout.java

@@ -0,0 +1,284 @@
+package com.ivalentin.gm;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.Interpolator;
+import android.widget.LinearLayout;
+import android.widget.Scroller;
+
+/**
+ * Extension of LinearLayout to be used in the app. Contains the slider menu.
+ * 
+ * @author Iñigo Valentin
+ *
+ */
+public class MainLayout extends LinearLayout {
+
+	//The width of the view
+	private int mainLayoutWidth;
+	
+	//The menu view
+	private View menu;
+	
+	//The content view
+	private View content;
+	
+	//The margin of the menu
+	private static int menuRightMargin = 25;
+
+	/**
+	 * Gets the menu's view.
+	 * @return The menu view
+	 */
+	public View getMenuView(){
+		return menu;
+	}
+	
+	/**
+	 * Possible states of the menu
+	 */
+	private enum MenuState {
+		HIDING, HIDDEN, SHOWING, SHOWN,
+	};
+
+	private int contentXOffset;
+	private MenuState currentMenuState = MenuState.HIDDEN;
+	private Scroller menuScroller = new Scroller(this.getContext(), new EaseInInterpolator());
+	private Runnable menuRunnable = new MenuRunnable();
+	private Handler menuHandler = new Handler();
+	private int prevX = 0;
+	private boolean isDragging = false;
+	private int lastDiffX = 0;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param context Context of the app.
+	 * @param attrs Atributes.
+	 */
+	public MainLayout(Context context, AttributeSet attrs) {
+		super(context, attrs);
+	}
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param context Context of the app.
+	 */
+	public MainLayout(Context context) {
+		super(context);
+	}
+
+	@Override
+	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+		mainLayoutWidth = MeasureSpec.getSize(widthMeasureSpec);
+		menuRightMargin = mainLayoutWidth * 25 / 100;
+	}
+	
+	@SuppressLint("ClickableViewAccessibility") //I don't need it.
+	@Override
+	protected void onAttachedToWindow() {
+		super.onAttachedToWindow();
+
+		menu = this.getChildAt(0);
+		content = this.getChildAt(1);
+		content.setOnTouchListener(new OnTouchListener() {
+			@Override
+			public boolean onTouch(View v, MotionEvent event) {
+				return MainLayout.this.onContentTouch(v, event);
+			}
+		});
+		menu.setVisibility(View.GONE);
+	}
+
+	@Override
+	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+		if (changed) {
+			LayoutParams contentLayoutParams = (LayoutParams) content.getLayoutParams();
+			contentLayoutParams.height = this.getHeight();
+			contentLayoutParams.width = this.getWidth();
+			LayoutParams menuLayoutParams = (LayoutParams) menu.getLayoutParams();
+			menuLayoutParams.height = this.getHeight();
+			menuLayoutParams.width = this.getWidth() - menuRightMargin;
+		}
+		this.requestDisallowInterceptTouchEvent(true);
+		menu.layout(left, top, right - menuRightMargin, bottom);
+		content.layout(left + contentXOffset, top, right + contentXOffset, bottom);
+
+	}
+
+	/**
+	 * Changes the menu state. 
+	 * Closes it if it's open. Opens it if it's closed.
+	 */
+	public void toggleMenu() {
+		if (currentMenuState == MenuState.HIDING || currentMenuState == MenuState.SHOWING)
+			return;
+		
+		switch (currentMenuState) {
+			case HIDDEN:
+				currentMenuState = MenuState.SHOWING;
+				menu.setVisibility(View.VISIBLE);
+				menuScroller.startScroll(0, 0, menu.getLayoutParams().width, 0, GM.MENU_SLIDING_DURATION);
+				break;
+			case SHOWN:
+				currentMenuState = MenuState.HIDING;
+				menuScroller.startScroll(contentXOffset, 0, -contentXOffset, 0, GM.MENU_SLIDING_DURATION);
+				break;
+			default:
+				break;
+		}
+		menuHandler.postDelayed(menuRunnable, GM.MENU_QUERY_INTERVAL);
+		this.invalidate();
+	}
+	
+	/**
+	 * Handles the animation of the sliding menu.
+	 * 
+	 * @author seavenois
+	 * 
+	 * @see Runnable
+	 *
+	 */
+	protected class MenuRunnable implements Runnable {
+		@Override
+		public void run() {
+			boolean isScrolling = menuScroller.computeScrollOffset();
+			adjustContentPosition(isScrolling);
+		}
+	}
+		
+	/**
+	 * Moves the content view when the menu is slided. 
+	 * 
+	 * @param isScrolling Indicates if the menu is being slided.
+	 */
+	private void adjustContentPosition(boolean isScrolling) {
+		int scrollerXOffset = menuScroller.getCurrX();
+		
+		content.offsetLeftAndRight(scrollerXOffset - contentXOffset);
+		
+		contentXOffset = scrollerXOffset;
+		this.invalidate();
+		if (isScrolling)
+			menuHandler.postDelayed(menuRunnable, GM.MENU_QUERY_INTERVAL);
+		else
+			this.onMenuSlidingComplete();
+	}
+	
+	/**
+	 * Called when the menu has been slided completely. 
+	 * Fixes the position.
+	 */
+	private void onMenuSlidingComplete() {
+		switch (currentMenuState) {
+			case SHOWING:
+				currentMenuState = MenuState.SHOWN;
+				break;
+			case HIDING:
+				currentMenuState = MenuState.HIDDEN;
+				menu.setVisibility(View.GONE);
+				break;
+			default:
+				return;
+		}
+	}
+	
+	/**
+	 * Defines the menu animation frame rate.
+	 * 
+	 * @author Iñigo Valentin
+	 *
+	 */
+	protected class EaseInInterpolator implements Interpolator {
+		@Override
+		public float getInterpolation(float t) {
+			return (float) Math.pow(t - 1, 5) + 1;
+		}
+	
+	}
+	
+	/**
+	 * Indicates if the menu is currently shown.
+	 * 
+	 * @return true if the menu is shown, false otherwise.
+	 */
+	public boolean isMenuShown() {
+		return currentMenuState == MenuState.SHOWN;
+	}
+	
+	/**
+	 * Register touch events. 
+	 * Used to show and hide the menu.
+	 * 
+	 * @param v The touched view.
+	 * @param event The MotionEvent triggering it.
+	 * @return
+	 */
+	public boolean onContentTouch(View v, MotionEvent event) {
+		if (currentMenuState == MenuState.HIDING || currentMenuState == MenuState.SHOWING)
+			return false;
+		int curX = (int) event.getRawX();
+		int diffX = 0;
+		
+		switch (event.getAction()) {
+			case MotionEvent.ACTION_DOWN:
+				prevX = curX;
+				return true;
+			
+			case MotionEvent.ACTION_MOVE:
+				//int width = this.getWidth();
+				//if (event.getX() <  (float) width / 4){
+					
+					if (!isDragging) {
+						
+						isDragging = true;
+						menu.setVisibility(View.VISIBLE);
+					}
+					diffX = curX - prevX;
+					if (contentXOffset + diffX <= 0) {
+						diffX = -contentXOffset;
+					}
+					else if (contentXOffset + diffX > mainLayoutWidth - menuRightMargin) {
+						diffX = mainLayoutWidth - menuRightMargin - contentXOffset;
+					}
+					content.offsetLeftAndRight(diffX);
+					contentXOffset += diffX;
+					this.invalidate();
+					
+					prevX = curX;
+					lastDiffX = diffX;
+				//}
+				return true;
+			
+			case MotionEvent.ACTION_UP:
+				
+				if (lastDiffX > 0) {
+					currentMenuState = MenuState.SHOWING;
+					menuScroller.startScroll(contentXOffset, 0,	menu.getLayoutParams().width - contentXOffset, 0, GM.MENU_SLIDING_DURATION);
+				}
+				else if (lastDiffX < 0) {
+					currentMenuState = MenuState.HIDING;
+					menuScroller.startScroll(contentXOffset, 0, -contentXOffset, 0, GM.MENU_SLIDING_DURATION);
+				}
+				menuHandler.postDelayed(menuRunnable, GM.MENU_QUERY_INTERVAL);
+				this.invalidate();
+				isDragging = false;
+				prevX = 0;
+				lastDiffX = 0;
+				return true;
+				
+			default:
+				break;
+		}
+		
+		return false;
+	}
+}
+

+ 203 - 0
app/src/main/java/com/ivalentin/gm/PostComment.java

@@ -0,0 +1,203 @@
+package com.ivalentin.gm;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.AsyncTask;
+import android.text.format.DateFormat;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import java.io.DataOutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+
+class PostComment extends AsyncTask<String, String, Integer> {
+
+    //Elements passed from fragments
+    String type, user, text, language;
+    LinearLayout list, form;
+    TextView counter;
+    int id, currentCounter;
+    Context context;
+
+    //Elements calculated here
+    Button btSend;
+    ProgressBar pb;
+
+    int code = 404;
+
+    public PostComment(String type, String user, String text, String language, int id, LinearLayout form, LinearLayout list, int currentCounter, TextView counter, Context context) {
+        super();
+        this.type = type;
+        this.user = user;
+        this.text = text;
+        this.form = form;
+        this.list = list;
+        this.language = language;
+        this.counter = counter;
+        this.id = id;
+        this.currentCounter = currentCounter;
+        this.context = context;
+    }
+
+    /**
+     * Before starting background thread
+     * */
+    @Override
+    protected void onPreExecute() {
+        Log.e("PRE", "START");
+        super.onPreExecute();
+        btSend = (Button) form.findViewById(R.id.bt_post_comment_send);
+        pb = (ProgressBar) form.findViewById(R.id.pb_comment);
+        btSend.setVisibility(View.GONE);
+        pb.setVisibility(View.VISIBLE);
+        Log.e("PRE", "END");
+    }
+
+    /**
+     * Downloading file in background thread
+     * */
+    @Override
+    protected Integer doInBackground(String... f_url) {
+        Log.e("DIB", "START");
+        int count;
+        URL url;
+        String urlString, urlParams;
+        try {
+
+            //url = new URL(GM.SERVER + "/" + type + "/comment.php?user=" + user + "&text=" + text);
+            urlString = GM.SERVER + "/" + type + "/comment.php?user=" + URLEncoder.encode(user) + "&text=" + URLEncoder.encode(text);
+            urlParams = "user=" + URLEncoder.encode(user) + "&text=" + URLEncoder.encode(text);
+            Log.e("TYPE", type);
+            switch (type){
+                case "blog":
+                    urlParams = urlParams + "&post=" + id;
+                    break;
+                case "galeria":
+                    urlParams = urlParams + "&photo=" + id;
+                    break;
+                case "actividades":
+                    urlParams = urlParams + "&activity=" + id;
+                    break;
+                default:
+                    //TODO, error, stop
+            }
+            switch (language){
+                case "es":
+                    urlParams = urlParams + "&lang=es";
+                    break;
+                case "eu":
+                    urlParams = urlParams + "&lang=eu";
+                    break;
+                default:
+                    this.language = "en";
+                    urlParams = urlParams + "&lang=en";
+            }
+
+            byte[] postData       = urlParams.getBytes("UTF-8");
+            int    postDataLength = postData.length;
+            String request        = GM.SERVER + "/" + type + "/comment.php";
+            url            = new URL( request );
+            HttpURLConnection conn= (HttpURLConnection) url.openConnection();
+            conn.setDoOutput( true );
+            conn.setInstanceFollowRedirects( false );
+            conn.setRequestMethod( "POST" );
+            conn.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded");
+            conn.setRequestProperty( "charset", "utf-8");
+            conn.setRequestProperty( "Content-Length", Integer.toString( postDataLength ));
+            conn.setUseCaches( false );
+            DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
+            wr.write(postData);
+            conn.connect();
+
+
+            Log.e("URL", urlString);
+            //url = new URL(urlString);
+            //HttpURLConnection connection = (HttpURLConnection)url.openConnection();
+            //connection.setRequestMethod("GET");
+            //connection.connect();
+
+            code = conn.getResponseCode();
+            Log.d("Comment status", "" + code);
+
+            if (code == 200){
+                //TODO: Insert into local db
+                SQLiteDatabase db = context.openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+                String table = "";
+                switch (type){
+                    case "blog":
+                        table = "post_comment";
+                        break;
+                    case "galeria":
+                        table = "photo_comment";
+                        break;
+                    case "actividades":
+                        table = "activity_comment";
+                        break;
+                }
+                db.rawQuery("INSERT INTO " + table + " (post, text, username, lang) VALUES (" + id + ", '" + text + "', '" + user + "', '" + language + "');", null);
+                db.close();
+            }
+
+        } catch (Exception e) {
+            Log.e("Error posting: ", e.getMessage());
+        }
+        Log.e("DIB", "END");
+        return code;
+    }
+
+
+
+    /**
+     * After completing background task
+     * **/
+    @Override
+    protected void onPostExecute(Integer a) {
+        Log.e("POS", "START");
+        //Log.d("Comment posted", type);
+
+        if (code == 200) {
+            //Clear form
+            EditText formText = (EditText) form.findViewById(R.id.et_post_comment_text);
+            EditText formUser = (EditText) form.findViewById(R.id.et_post_comment_name);
+            formUser.setText("");
+            formText.setText("");
+
+            //TODO: Update counter
+
+            //TODO: Insert comment in list
+            LayoutInflater factory = LayoutInflater.from(context);
+            LinearLayout entry = (LinearLayout) factory.inflate(R.layout.row_comment, null);
+
+            //Set user
+            TextView tvUser = (TextView) entry.findViewById(R.id.tv_row_comment_user);
+            tvUser.setText(user);
+            Date d = new Date();
+            String date = DateFormat.format("yyyy-MM-dd hh:mm:ss", d.getTime()).toString();
+            TextView tvCDate = (TextView) entry.findViewById(R.id.tv_row_comment_date);
+            tvCDate.setText(GM.formatDate(date, language, true));
+            TextView tvText = (TextView) entry.findViewById(R.id.tv_row_comment_text);
+            tvText.setText(text);
+
+            //Add to the list
+            list.addView(entry);
+        }
+
+        //Show button again
+        btSend.setVisibility(View.VISIBLE);
+        pb.setVisibility(View.GONE);
+
+        //ImageView myImage = (ImageView) findViewById(R.id.imageviewTest);
+        Log.e("POS", "END");
+    }
+}

+ 171 - 0
app/src/main/java/com/ivalentin/gm/PostLayout.java

@@ -0,0 +1,171 @@
+package com.ivalentin.gm;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebView;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.File;
+import java.util.Locale;
+
+/**
+ * Created by seavenois on 12/06/16.
+ */
+public class PostLayout extends Fragment {
+
+    //Main View
+    private View view;
+
+    String currLang;
+
+    Context context;
+
+    @SuppressLint("InflateParams") //Throws unknown error when done properly.
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+        //Load the layout
+        view = inflater.inflate(R.layout.fragment_layout_post, null);
+        context = view.getContext();
+
+        //Get bundled id
+        Bundle bundle = this.getArguments();
+        int id = bundle.getInt("post", -1);
+        if (id == -1){
+            //TODO: Error, do something
+        }
+
+        //Get data from database
+        SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+        final Cursor cursor;
+        currLang = Locale.getDefault().getDisplayLanguage();
+        if (!currLang.equals("es") && !currLang.equals("eu")){
+            currLang = "en";
+        }
+        cursor = db.rawQuery("SELECT id, title_" + currLang+ " AS title, text_" + currLang + " AS text, dtime FROM post WHERE id = " + id + ";", null);
+        cursor.moveToFirst();
+
+        //Get display elements
+        ImageView images[] = new ImageView[5];
+        images[0] = (ImageView) view.findViewById(R.id.iv_post_0);
+        images[1] = (ImageView) view.findViewById(R.id.iv_post_1);
+        images[2] = (ImageView) view.findViewById(R.id.iv_post_2);
+        images[3] = (ImageView) view.findViewById(R.id.iv_post_3);
+        images[4] = (ImageView) view.findViewById(R.id.iv_post_4);
+
+        TextView tvTitle = (TextView) view.findViewById(R.id.tv_post_title);
+        TextView tvDate = (TextView) view.findViewById(R.id.tv_post_date);
+        final TextView tvComments = (TextView) view.findViewById(R.id.tv_post_comments);
+        WebView wvText = (WebView) view.findViewById(R.id.wv_post_text);
+        LinearLayout llCommentList = (LinearLayout) view.findViewById(R.id.ll_post_comment_list);
+
+        //Set fields
+        tvTitle.setText(cursor.getString(1));
+        ((MainActivity) getActivity()).setSectionTitle(cursor.getString(1));
+        wvText.loadDataWithBaseURL(null, cursor.getString(2), "text/html", "utf-8", null);
+        tvDate.setText(GM.formatDate(cursor.getString(3), currLang, true));
+
+        //Close the cursor
+        //cursor.close();
+
+        //Get images
+        Cursor imageCursor = db.rawQuery("SELECT image, idx FROM post_image WHERE post = " + id + " ORDER BY idx LIMIT 5;", null);
+        //imageCursor.moveToFirst();
+        //Log.e("IMGCOUNT", "" + cursor.getCount());
+        int i = 0;
+        while (imageCursor.moveToNext()) {
+            //Log.e("IMG", "" + i);
+            String image = imageCursor.getString(0);
+
+            //Check if image exists
+            File f;
+            f = new File(this.getContext().getFilesDir().toString() + "/img/blog/preview/" + image);
+            if (f.exists()){
+                //If the image exists, set it.
+                Bitmap myBitmap = BitmapFactory.decodeFile(this.getContext().getFilesDir().toString() + "/img/blog/preview/" + image);
+                images[i].setImageBitmap(myBitmap);
+            }
+            else {
+                //If not, create directories and download asynchronously
+                File fpath;
+                fpath = new File(this.getContext().getFilesDir().toString() + "/img/blog/preview/");
+                fpath.mkdirs();
+                new DownloadImage(GM.SERVER + "/img/blog/preview/" + image, this.getContext().getFilesDir().toString() + "/img/blog/preview/" + image, images[i]).execute();
+            }
+            images[i].setVisibility(View.VISIBLE);
+            i ++;
+        }
+        imageCursor.close();
+
+        //Get comments
+        Cursor commentCursor = db.rawQuery("SELECT text, dtime, username FROM post_comment WHERE post = " + id + ";", null);
+        tvComments.setText(String.format(getResources().getQuantityString(R.plurals.comment_comments, commentCursor.getCount()), commentCursor.getCount()));
+        final int commentCount = commentCursor.getCount();
+        cursor.moveToFirst();
+        LinearLayout entry;
+        LinearLayout commentList = (LinearLayout) view.findViewById(R.id.ll_post_comment_list);
+        LayoutInflater factory = LayoutInflater.from(getActivity());
+        while (commentCursor.moveToNext()) {
+            entry = (LinearLayout) factory.inflate(R.layout.row_comment, null);
+
+            //Set user
+            TextView tvUser = (TextView) entry.findViewById(R.id.tv_row_comment_user);
+            tvUser.setText(commentCursor.getString(2));
+            TextView tvCDate = (TextView) entry.findViewById(R.id.tv_row_comment_date);
+            tvCDate.setText(GM.formatDate(commentCursor.getString(1), currLang, true));
+            TextView tvText = (TextView) entry.findViewById(R.id.tv_row_comment_text);
+            tvText.setText(commentCursor.getString(0));
+
+            //Add to the list
+            llCommentList.addView(entry);
+        }
+        commentCursor.close();
+
+        //Set up comment form
+        final EditText etCommentText = (EditText) view.findViewById(R.id.et_post_comment_text);
+        final EditText etCommentName = (EditText) view.findViewById(R.id.et_post_comment_name);
+        Button btSendComment = (Button) view.findViewById(R.id.bt_post_comment_send);
+
+        btSendComment.setOnClickListener(new View.OnClickListener(){
+            @Override
+            public void onClick(View v) {
+                String user = etCommentName.getText().toString();
+                String text = etCommentText.getText().toString();
+                if (user.length() < 1){
+                    Toast.makeText(getActivity(), getString(R.string.comment_toast_user), Toast.LENGTH_LONG).show();
+                    etCommentName.requestFocus();
+                    return;
+                }
+                if (text.length() < 1){
+                    Toast.makeText(getActivity(), getString(R.string.comment_toast_text), Toast.LENGTH_LONG).show();
+                    etCommentText.requestFocus();
+                    return;
+                }
+
+                //Start async task
+                LinearLayout form = (LinearLayout) view.findViewById(R.id.ll_post_new_comment);
+                LinearLayout list = (LinearLayout) view.findViewById(R.id.ll_post_comment_list);
+                new PostComment("blog", user, text, currLang, cursor.getInt(0), form, list, commentCount, tvComments, context).execute();
+
+            }
+        });
+
+        db.close();
+        return view;
+    }
+}

+ 607 - 0
app/src/main/java/com/ivalentin/gm/ScheduleLayout.java

@@ -0,0 +1,607 @@
+package com.ivalentin.gm;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+import com.google.android.gms.maps.CameraUpdate;
+import com.google.android.gms.maps.CameraUpdateFactory;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.MapView;
+import com.google.android.gms.maps.MapsInitializer;
+import com.google.android.gms.maps.OnMapReadyCallback;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.MarkerOptions;
+
+import android.annotation.SuppressLint;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
+import android.content.DialogInterface.OnShowListener;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.content.res.ResourcesCompat;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * Fragment to be inflated showing the festivals schedule.
+ * Contains a date selector and a ScrollView with all the activities for the day.
+ * 
+ * @author Inigo Valentin
+ *
+ */
+public class ScheduleLayout extends Fragment implements OnMapReadyCallback{
+
+	
+	//Array with data about the days of the festival
+	private String[][] days = new String[GM.TOTAL_DAYS][4];
+	
+	//Currently selected day
+	private int selected;
+	
+	//Indicates official schedule
+	private int schedule;
+	
+	//Arrow buttons
+	private Button btL, btR;
+	
+	//TextViews in the date selector
+	private TextView tvDayNumber, tvDayTitle, tvDayMonth;
+	
+	//Map stuff for the dialog
+	private MapView mapView;
+	private Bundle bund;
+	private GoogleMap map;
+	private LatLng location;
+	private View view;
+	private String markerName = "";
+	
+	/**
+	 * Run when the fragment is inflated.
+	 * Assigns views, gets the date and does the first call to the populateSchedule function.
+	 * 
+	 * @param inflater A LayoutInflater to manage views
+	 * @param container The container View
+	 * @param savedInstanceState Bundle containing the state
+	 * 
+	 * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
+	 */
+	@SuppressLint("InflateParams") //Throws unknown error when done properly.
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+		
+		//Set bundle for the map
+		bund = savedInstanceState;
+		
+		//Load the layout
+		view = inflater.inflate(R.layout.fragment_layout_schedule, null);		
+		
+		//Get schedule type
+		Bundle bundle = this.getArguments();
+		schedule = bundle.getInt(GM.SCHEDULE, GM.SECTION_LABLANCA_SCHEDULE);
+		
+		//Set the title
+		if (schedule == GM.SECTION_LABLANCA_SCHEDULE)
+			((MainActivity) getActivity()).setSectionTitle(view.getContext().getString(R.string.menu_lablanca_schedule));
+		else
+			((MainActivity) getActivity()).setSectionTitle(view.getContext().getString(R.string.menu_lablanca_gm_schedule));
+		
+		
+		//Populate days array
+		days[GM.DAY_25] = new String[] {"2015-07-25", "25", getString(R.string.month_07), getString(R.string.day_title_25)};
+		days[GM.DAY_4] = new String[] {"2015-08-04", "4", getString(R.string.month_08), getString(R.string.day_title_4)};
+		days[GM.DAY_5] = new String[] {"2015-08-05", "5", getString(R.string.month_08), getString(R.string.day_title_5)};
+		days[GM.DAY_6] = new String[] {"2015-08-06", "6", getString(R.string.month_08), getString(R.string.day_title_6)};
+		days[GM.DAY_7] = new String[] {"2015-08-07", "7", getString(R.string.month_08), getString(R.string.day_title_7)};
+		days[GM.DAY_8] = new String[] {"2015-08-08", "8", getString(R.string.month_08), getString(R.string.day_title_8)};
+		days[GM.DAY_9] = new String[] {"2015-08-09", "9", getString(R.string.month_08), getString(R.string.day_title_9)};
+		
+		//Assign parent layout
+		final LinearLayout list = (LinearLayout) view.findViewById(R.id.ll_schedule_list);
+		
+		//Assign textViews
+		tvDayNumber = (TextView) view.findViewById(R.id.tv_schedule_day_number);
+		tvDayMonth = (TextView) view.findViewById(R.id.tv_schedule_day_month);
+		tvDayTitle = (TextView) view.findViewById(R.id.tv_schedule_day_title);
+		
+		//Assign buttons
+		btL = (Button) view.findViewById(R.id.bt_schedule_l);
+		btR = (Button) view.findViewById(R.id.bt_schedule_r);
+		btL.setOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View v) {
+				if (selected > GM.DAY_25){
+					selected --;
+					
+					//If August 4 selected and GM schedule, skip
+					if (selected == GM.DAY_4 && schedule != GM.SECTION_LABLANCA_SCHEDULE)
+						selected --;
+					
+					String filter = ((EditText) view.findViewById(R.id.et_schedule_filter)).getText().toString();
+					populateSchedule(selected, list, schedule, filter);
+				}
+			}
+		});
+		btR.setOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View v) {
+				if (selected < GM.DAY_9){
+					selected ++;
+					
+					//If August 4 selected and GM schedule, skip
+					if (selected == GM.DAY_4 && schedule != GM.SECTION_LABLANCA_SCHEDULE)
+						selected ++;
+					
+					String filter = ((EditText) view.findViewById(R.id.et_schedule_filter)).getText().toString();
+					populateSchedule(selected, list, schedule, filter);
+				}
+			}
+		});
+		
+		//Assign the filter text
+		EditText etFilter = (EditText) view.findViewById(R.id.et_schedule_filter);
+		etFilter.addTextChangedListener(new TextWatcher() {
+
+	        @Override
+	        public void afterTextChanged(Editable s) { }
+
+	        @Override
+	        public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
+
+	        @Override
+	        public void onTextChanged(CharSequence s, int start, int before, int count) {
+	        	//Repopulate when the text is changed
+	        	populateSchedule(selected, list, schedule, s.toString());
+	          
+	        }
+		});
+		
+		//Get the date
+		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
+		Date date = new Date();
+		String curDate = dateFormat.format(date);
+		
+		//Try to find out if the current date is before, after, or in the middle of the festivals.
+		try {
+			if (dateFormat.parse(curDate).before(dateFormat.parse(days[GM.DAY_25][0]))){
+				selected = GM.DAY_25;
+			}
+			else if (dateFormat.parse(curDate).after(dateFormat.parse(days[GM.DAY_9][0]))){
+				selected = GM.DAY_9;
+			}
+			else{
+				for (int i = 0; i < GM.TOTAL_DAYS; i++){
+					if (curDate.equals(days[i][0])){
+						selected = i;
+					}
+				}
+			}
+			//If August 4 and Margolari schedule, move one day forward
+			if (selected == GM.DAY_4 && schedule != GM.SECTION_LABLANCA_SCHEDULE){
+				selected ++;
+			}
+		}
+		catch (ParseException e) {
+			selected = GM.DAY_25;
+			Log.e("Error selecting date", e.toString());
+		}
+		
+		//Populate the activity list
+		populateSchedule(selected, list, schedule, "");
+		
+		//Return the fragment view
+		return view;
+	}
+	
+	/**
+	 * Populates the list of activities with the ones n the selected day.
+	 * 
+	 * @param selected The day to show activities from
+	 * @param list The layout where the items will be added
+	 * @param schedule GM.SECTION_SCHEDULE if city schedule, GM.SECTION_GM_SCHEDULE if gm schedule
+	 * @param f Search filter texts
+	 */
+	@SuppressLint("InflateParams") //Views are added from a loop: I can't specify the parent when inflating.
+	private void populateSchedule(int selected, LinearLayout list, int schedule, String f){
+		
+		//A layout to be populated with one activity
+		LinearLayout entry, content;
+		
+		//The filter
+		String filter = f.toLowerCase(Locale.US);
+		
+		//An inflater
+        LayoutInflater factory = LayoutInflater.from(getActivity());
+        
+        //Views in each row
+        TextView tvRowTitle, tvRowTime, tvRowDesc, tvRowPlace, tvRowId;
+        
+        //Icon next to the location text
+        Drawable icon = ResourcesCompat.getDrawable(getResources(), R.drawable.pinpoint, null);
+        //icon.setBounds(0, 0, 80, 80);
+		
+		//Set date selector texts
+		tvDayNumber.setText(days[selected][1]);
+		tvDayMonth.setText(days[selected][2]);
+		tvDayTitle.setText(days[selected][3]);
+		
+		//Show or hide the arrow buttons
+		switch (selected){
+			case GM.DAY_25:
+				btL.setVisibility(View.INVISIBLE);
+				btR.setVisibility(View.VISIBLE);
+				break;
+			case GM.DAY_9:
+				btL.setVisibility(View.VISIBLE);
+				btR.setVisibility(View.INVISIBLE);
+				break;
+			default:
+				btL.setVisibility(View.VISIBLE);
+				btR.setVisibility(View.VISIBLE);				
+		}
+		
+		//Read from database
+		SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+		Cursor cursor;
+		
+		//Elements to parse, format and operate with dates
+		Calendar cal;
+		Date maxDate, minDate;
+		String maxDateStr, minDateStr;
+		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
+		SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
+		cal = Calendar.getInstance();
+		
+		//Get date of the selected daye
+	    try {
+			cal.setTime(dayFormat.parse(days[selected][0]));
+		} catch (ParseException e) {
+			Log.e("Error parsing date", e.toString());
+		}
+	    
+	    //Set margins so the days goes from 6:00 in the morning to 5:59 the next day, instead of from 00:00 to 23:59
+	    cal.add(Calendar.HOUR_OF_DAY, 6); 
+	    minDate = cal.getTime();
+	    
+	    //If its the last day, include events of the next one
+	    if (selected == GM.DAY_9)
+	    	cal.add(Calendar.HOUR_OF_DAY, 36);
+	    else
+	    	cal.add(Calendar.HOUR_OF_DAY, 24);
+	    maxDate = cal.getTime();
+	    maxDateStr = dateFormat.format(maxDate);
+	    minDateStr = dateFormat.format(minDate);
+	    
+	    //Get data from database
+	    if (schedule == GM.SECTION_LABLANCA_GM_SCHEDULE)
+	    	cursor = db.rawQuery("SELECT event.id, event.name, event.description, event.place, place.id, place.name, event.start FROM " + GM.DB_EVENT + ", " + GM.DB_PLACE + " WHERE " + GM.DB_EVENT_GM + " = 1 AND place.id = event.place AND start BETWEEN '" + minDateStr + "' AND '" + maxDateStr + "' AND (lower(event.name) LIKE '%" + filter + "%' OR lower(event.description) LIKE '%" + filter + "%' OR lower(place.name) LIKE '%" + filter + "%') ORDER BY " + GM.DB_EVENT_START + ";", null);
+	    else
+	    	cursor = db.rawQuery("SELECT event.id, event.name, event.description, event.place, place.id, place.name, event.start FROM " + GM.DB_EVENT + ", " + GM.DB_PLACE + " WHERE " + GM.DB_EVENT_SCHEDULE + " = 1 AND place.id = event.place AND start BETWEEN '" + minDateStr + "' AND '" + maxDateStr + "' AND (lower(event.name) LIKE '%" + filter + "%' OR lower(event.description) LIKE '%" + filter + "%' OR lower(place.name) LIKE '%" + filter + "%') ORDER BY " + GM.DB_EVENT_START + ";", null);
+		
+	    //Clear the list
+		list.removeAllViews();
+		
+        //Loop
+        while (cursor.moveToNext()){
+        	
+        	
+        	//Create a new row
+        	entry = (LinearLayout) factory.inflate(R.layout.row_schedule, null);
+        	
+        	//Set id        	
+        	tvRowId = (TextView) entry.findViewById(R.id.tv_row_schedule_id);
+        	tvRowId.setText(cursor.getString(0));
+        	
+        	//Set title
+        	tvRowTitle = (TextView) entry.findViewById(R.id.tv_row_schedule_title);
+        	tvRowTitle.setText(cursor.getString(1));
+        	
+        	//Set description
+        	tvRowDesc = (TextView) entry.findViewById(R.id.tv_row_schedule_description);
+        	tvRowDesc.setText(cursor.getString(2));
+        	
+        	//Set place
+        	tvRowPlace = (TextView) entry.findViewById(R.id.tv_row_schedule_place);
+        	tvRowPlace.setText(cursor.getString(5));
+        	icon.setBounds(0, 0, (int) (tvRowPlace.getTextSize() * 1.5), (int) (tvRowPlace.getTextSize() * 1.5));
+        	tvRowPlace.setCompoundDrawables(icon, null, null, null);
+        	
+        	//Set time
+        	tvRowTime = (TextView) entry.findViewById(R.id.tv_row_schedule_time);
+        	String tm = cursor.getString(6).substring(cursor.getString(6).length() - 8, cursor.getString(6).length() - 3);
+        	tvRowTime.setText(tm);
+        	
+        	//Set onClick event
+        	content = (LinearLayout) entry.findViewById(R.id.ll_row_schedule_content);
+        	content.setOnClickListener(new OnClickListener(){
+				@Override
+				public void onClick(View v) {
+	            	TextView tvName = (TextView) v.findViewById(R.id.tv_row_schedule_id);
+	            	int id = Integer.parseInt(tvName.getText().toString());
+					showDialog(id);
+				}
+        	});
+        	
+        	//Add to the list
+        	list.addView(entry);
+        }
+        
+        //Invalidate the list so it is redrawn
+        list.invalidate();
+        
+        //Close cursor and database
+        cursor.close();
+        db.close();
+	}
+	
+	
+	/**
+	 * Shows a dialog with info about the selected event.
+	 * 
+	 * @param id The event id
+	 */
+	private void showDialog(final int id){
+		
+		//Create the dialog
+		final Dialog dialog = new Dialog(getActivity());
+		
+		//Set up dialog window
+		dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+		dialog.setContentView(R.layout.dialog_schedule);
+		
+		//Date formatters
+		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
+		SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd-", Locale.US);
+		SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.US);
+ 
+		//Set the custom dialog components - text, image and button
+		TextView tvTitle = (TextView) dialog.findViewById(R.id.tv_dialog_schedule_title);
+		TextView tvDescription = (TextView) dialog.findViewById(R.id.tv_dialog_schedule_description);
+		TextView tvHost = (TextView) dialog.findViewById(R.id.tv_dialog_schedule_host);
+		TextView tvDate = (TextView) dialog.findViewById(R.id.tv_dialog_schedule_date);
+		TextView tvTime = (TextView) dialog.findViewById(R.id.tv_dialog_schedule_time);
+		TextView tvPlace = (TextView) dialog.findViewById(R.id.tv_dialog_schedule_place);
+		TextView tvAddress = (TextView) dialog.findViewById(R.id.tv_dialog_schedule_address);
+		Button btClose = (Button) dialog.findViewById(R.id.bt_schedule_close);
+		
+		//Get info about the event
+		SQLiteDatabase db = getActivity().openOrCreateDatabase(GM.DB_NAME, Context.MODE_PRIVATE, null);
+		Cursor cursor = db.rawQuery("SELECT event.id, event.name, description, start, end, place.name, address, lat, lon, host FROM event, place WHERE place.id = event.place AND event.id = " + id + ";", null);
+		if (cursor.getCount() > 0){
+			cursor.moveToNext();
+		
+			//Set title
+			tvTitle.setText(cursor.getString(1));
+			markerName = cursor.getString(1);
+			
+			//Set description
+			tvDescription.setText(cursor.getString(2));
+			
+			//Set host
+			if (cursor.getString(9) != null){
+				Cursor hostCursor = db.rawQuery("SELECT name FROM people WHERE id = " + cursor.getString(9) + ";", null);
+				if (hostCursor.moveToNext()){
+					tvHost.setVisibility(View.VISIBLE);
+					tvHost.setText(String.format(getString(R.string.schedule_host), hostCursor.getString(0)));
+				}
+			}
+			else{
+				tvHost.setVisibility(View.GONE);
+			}				
+			
+			//Set date
+			try{
+				Date day = dateFormat.parse(cursor.getString(3));
+				Date date = new Date();
+				//If the event is today, show "Today" instead of the date
+				if (dayFormat.format(day).equals(dayFormat.format(date)))
+					tvDate.setText(dialog.getContext().getString(R.string.today));
+				
+				else{
+					Calendar cal = Calendar.getInstance();
+				    cal.setTime(date);
+				    cal.add(Calendar.HOUR_OF_DAY, 24);
+				    
+				    //If the event is tomorrow, show "Tomorrow" instead of the date
+				    if (dayFormat.format(cal.getTime()).equals(dayFormat.format(date))){
+				    	tvDate.setText(dialog.getContext().getString(R.string.tomorrow));
+				    }
+					
+				    //Else, show the date
+				    else{
+				    	SimpleDateFormat printFormat = new SimpleDateFormat("dd MMMM", Locale.US);
+				    	tvDate.setText(printFormat.format(day));
+				    }
+				}
+			}
+			catch (Exception ex){
+				Log.e("Error parsing date", ex.toString());
+			}
+			
+			//Set time
+			try{
+				if (cursor.getString(4) == null)
+					tvTime.setText(timeFormat.format(dateFormat.parse(cursor.getString(3))));
+				else
+					tvTime.setText(timeFormat.format(dateFormat.parse(cursor.getString(3))) + " - " + timeFormat.format(dateFormat.parse(cursor.getString(4))));
+			}
+			catch (ParseException ex){
+				Log.e("Error parsing time", ex.toString());
+			}
+			
+			//Set the place
+			tvPlace.setText(cursor.getString(5));
+			tvAddress.setText(cursor.getString(6));
+			
+			//Set up map
+			location = new LatLng(Double.parseDouble(cursor.getString(7)), Double.parseDouble(cursor.getString(8)));
+			mapView = (MapView) dialog.findViewById(R.id.mv_dialog_schedule_map);
+			mapView.onCreate(bund);
+			
+			//Close the db connection
+			cursor.close();
+			db.close();
+			
+			//Set close button			
+        	btClose.setOnClickListener(new OnClickListener() {
+    			@Override
+    			public void onClick(View v) {
+    				dialog.dismiss();
+    			}
+    		});
+			
+			//Actions to take when the dialog is cancelled
+			dialog.setOnCancelListener(new OnCancelListener(){
+				@Override
+				public void onCancel(DialogInterface dialog) {
+					if (map != null)
+						map.setMyLocationEnabled(false);
+					if (mapView != null){
+    					mapView.onResume();
+    					mapView.onDestroy();
+    				}					
+				}
+			});
+			
+			//Show the dialog
+			WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();
+			lp.dimAmount = 0.0f;
+			dialog.show();
+			
+			//Start the map
+			startMap();
+			mapView.onResume();
+			dialog.setOnShowListener(new OnShowListener(){
+
+				@Override
+				public void onShow(DialogInterface dialog) {
+					// Gets to GoogleMap from the MapView and does initialization stuff
+					startMap();
+					
+				}
+			});		
+			
+		}
+	}
+	
+	/**
+	 * Starts the map in the dialog.
+	 */
+	private void startMap(){
+		mapView.getMapAsync(this);
+	}
+	
+	/**
+	 * Called when the fragment is brought back into the foreground. 
+	 * Resumes the map and the location manager.
+	 * 
+	 * @see android.support.v4.app.Fragment#onResume()
+	 */
+	@Override
+	public void onResume() {
+		if (mapView != null)
+			mapView.onResume();
+		if (map != null)
+			map.setMyLocationEnabled(true);
+		super.onResume();
+	}
+
+	/**
+	 * Called when the fragment is destroyed. 
+	 * Finishes the map. 
+	 * 
+	 * @see android.support.v4.app.Fragment#onDestroy()
+	 */
+	@Override
+	public void onDestroy() {
+		super.onDestroy();
+		if (map != null)
+			map.setMyLocationEnabled(false);
+		if (mapView != null){
+			mapView.onResume();
+			mapView.onDestroy();
+		}
+	}
+	
+	/**
+	 * Called when the fragment is paused. 
+	 * Finishes the map. 
+	 * 
+	 * @see android.support.v4.app.Fragment#onPause()
+	 */
+	@Override
+	public void onPause() {
+		super.onDestroy();
+		if (map != null)
+			map.setMyLocationEnabled(false);
+		if (mapView != null){
+			mapView.onPause();
+		}
+	}
+
+	/**
+	 * Called in a situation of low memory.
+	 * Lets the map handle this situation.
+	 * 
+	 * @see android.support.v4.app.Fragment#onLowMemory()
+	 */
+	@Override
+	public void onLowMemory() {
+		super.onLowMemory();
+		if (mapView != null){
+			mapView.onResume();
+			mapView.onLowMemory();
+		}
+	}
+
+	/**
+	 * Called when the map is ready to be displayed. 
+	 * Sets the map options and a marker for the map.
+	 * 
+	 * @param googleMap The map to be shown
+	 * 
+	 * @see com.google.android.gms.maps.OnMapReadyCallback#onMapReady(com.google.android.gms.maps.GoogleMap)
+	 */
+	@Override
+	public void onMapReady(GoogleMap googleMap) {
+		this.map = googleMap;
+		map.setMyLocationEnabled(true);
+		
+		map.getUiSettings().setMyLocationButtonEnabled(false);
+		map.setMyLocationEnabled(true);
+		// Needs to call MapsInitializer before doing any CameraUpdateFactory calls
+		try {
+			MapsInitializer.initialize(this.getActivity());
+			CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(location, 14);
+			map.animateCamera(cameraUpdate);
+		} catch (Exception e) {
+			Log.e("Error initializing maps", e.toString());
+		}
+		//Set GM marker
+		MarkerOptions mo = new MarkerOptions();
+		mo.title(markerName);
+		mo.position(location);
+		map.addMarker(mo);
+		
+	}
+		
+}

+ 231 - 0
app/src/main/java/com/ivalentin/gm/SettingsLayout.java

@@ -0,0 +1,231 @@
+package com.ivalentin.gm;
+
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.content.res.ColorStateList;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+/**
+ * Section that allow the user to change the app settings.
+ * 
+ * @author Inigo Valentin
+ *
+ */
+public class SettingsLayout extends Fragment{
+
+	//The user name
+	private String userName;
+	
+	//Color to store default text color before change them
+	private ColorStateList defaultColorTitle, defaultColorSummary;
+	
+	/**
+	 * Run when the fragment is inflated.
+	 * Assigns the view and the click listeners. 
+	 * 
+	 * @param inflater A LayoutInflater to manage views
+	 * @param container The container View
+	 * @param savedInstanceState Bundle containing the state
+	 * 
+	 * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
+	 */
+	@SuppressLint("InflateParams") //Throws unknown error when done properly.
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+		
+		//Load the layout
+		final View view = inflater.inflate(R.layout.fragment_layout_settings, null);
+		
+		//Set the title
+		((MainActivity) getActivity()).setSectionTitle(view.getContext().getString(R.string.menu_settings));
+		
+		//Get views.
+		RelativeLayout rlNotification = (RelativeLayout) view.findViewById(R.id.rl_settings_notifications);
+		RelativeLayout rlNotificationGm = (RelativeLayout) view.findViewById(R.id.rl_settings_notifications_gm);
+		RelativeLayout rlAccountGm = (RelativeLayout) view.findViewById(R.id.rl_settings_gm);
+		RelativeLayout rlAccountName = (RelativeLayout) view.findViewById(R.id.rl_settings_account_name);
+		final CheckBox cbNotification = (CheckBox) view.findViewById(R.id.cb_settings_notifications);
+		final CheckBox cbNotificationGm = (CheckBox) view.findViewById(R.id.cb_settings_notifications_gm);
+		final CheckBox cbAccountGm = (CheckBox) view.findViewById(R.id.cb_settings_gm);
+		final TextView tvNotification = (TextView) view.findViewById(R.id.tv_settings_notifications_summary);
+		final TextView tvNotificationGmTitle = (TextView) view.findViewById(R.id.tv_settings_notifications_gm);
+		final TextView tvNotificationGm = (TextView) view.findViewById(R.id.tv_settings_notifications_gm_summary);
+		final TextView tvAccountGm = (TextView) view.findViewById(R.id.tv_settings_gm_summary);
+		final TextView tvAccountName = (TextView) view.findViewById(R.id.tv_settings_account_name_summary);
+		
+		//Get TextView defaultColors
+		defaultColorTitle = tvNotificationGmTitle.getTextColors();
+		defaultColorSummary = tvNotificationGm.getTextColors();
+		
+		//Set initial state of the settings
+		SharedPreferences settings = view.getContext().getSharedPreferences(GM.PREF, Context.MODE_PRIVATE);
+		if (settings.getInt(GM.PREF_NOTIFICATION, GM.DEFAULT_PREF_NOTIFICATION) == 1){
+			cbNotification.setChecked(true);
+			tvNotification.setText(view.getContext().getString(R.string.settings_notification_on));
+			cbNotificationGm.setEnabled(true);
+		}
+		else{
+			cbNotification.setChecked(false);
+			tvNotification.setText(view.getContext().getString(R.string.settings_notification_off));
+			cbNotificationGm.setEnabled(false);
+			tvNotificationGm.setTextColor(view.getResources().getColor(R.color.settings_disabled));
+			tvNotificationGmTitle.setTextColor(view.getResources().getColor(R.color.settings_disabled));
+		}
+		
+		if (settings.getInt(GM.PREF_NOTIFICATION_GM, GM.DEFAULT_PREF_NOTIFICATION_GM) == 1){
+			cbNotificationGm.setChecked(true);
+			tvNotificationGm.setText(view.getContext().getString(R.string.settings_notification_gm_on));
+		}
+		else{
+			cbNotificationGm.setChecked(false);
+			tvNotificationGm.setText(view.getContext().getString(R.string.settings_notification_gm_off));
+		}
+		
+		if (settings.getInt(GM.PREF_GM, GM.DEFAULT_PREF_GM) == 1){
+			cbAccountGm.setChecked(true);
+			tvAccountGm.setText(view.getContext().getString(R.string.settings_account_gm_on));
+		}
+		else{
+			cbAccountGm.setChecked(false);
+			tvAccountGm.setText(view.getContext().getString(R.string.settings_account_gm_off));
+		}
+		
+		String username = settings.getString(GM.USER_NAME, GM.DEFAULT_PREF_USERNAME);
+		if (username.length() > 0){
+			tvAccountName.setText(username);
+		}
+		else{
+			tvAccountName.setText(view.getContext().getString(R.string.settings_account_unset));
+		}
+		
+		//Set click listener for "Notification" preference
+		rlNotification.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				if (cbNotification.isChecked()){
+					cbNotification.setChecked(false);
+					tvNotification.setText(view.getContext().getString(R.string.settings_notification_off));
+					cbNotificationGm.setEnabled(false);
+					SharedPreferences preferences = view.getContext().getSharedPreferences(GM.PREF, Context.MODE_PRIVATE);
+					SharedPreferences.Editor editor = preferences.edit();
+					editor.putInt(GM.PREF_NOTIFICATION, 0);
+					editor.commit();
+					//Change color of disabled preference
+					tvNotificationGm.setTextColor(view.getResources().getColor(R.color.settings_disabled));
+					tvNotificationGmTitle.setTextColor(view.getResources().getColor(R.color.settings_disabled));
+				}
+				else{
+					cbNotification.setChecked(true);
+					tvNotification.setText(view.getContext().getString(R.string.settings_notification_on));
+					cbNotificationGm.setEnabled(true);
+					SharedPreferences preferences = view.getContext().getSharedPreferences(GM.PREF, Context.MODE_PRIVATE);
+					SharedPreferences.Editor editor = preferences.edit();
+					editor.putInt(GM.PREF_NOTIFICATION, 1);
+					editor.commit();
+					//Change color of disabled preferences
+					tvNotificationGmTitle.setTextColor(defaultColorTitle);
+					tvNotificationGm.setTextColor(defaultColorSummary);
+				}
+			}
+			
+		});
+		
+		//Set click listener for the "GM notifications" preference
+		rlNotificationGm.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				if (cbNotificationGm.isEnabled()){
+					if (cbNotificationGm.isChecked()){
+						cbNotificationGm.setChecked(false);
+						tvNotificationGm.setText(view.getContext().getString(R.string.settings_notification_gm_off));
+						SharedPreferences preferences = view.getContext().getSharedPreferences(GM.PREF, Context.MODE_PRIVATE);
+						SharedPreferences.Editor editor = preferences.edit();
+						editor.putInt(GM.PREF_NOTIFICATION_GM, 0);
+						editor.commit();
+					}
+					else{
+						cbNotificationGm.setChecked(true);
+						tvNotificationGm.setText(view.getContext().getString(R.string.settings_notification_gm_on));
+						SharedPreferences preferences = view.getContext().getSharedPreferences(GM.PREF, Context.MODE_PRIVATE);
+						SharedPreferences.Editor editor = preferences.edit();
+						editor.putInt(GM.PREF_NOTIFICATION_GM, 1);
+						editor.commit();
+					}
+				}
+			}			
+		});
+		
+		//Set click listener for the "I am margolari" preference
+		rlAccountGm.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				if (cbAccountGm.isChecked()){
+					cbAccountGm.setChecked(false);
+					tvAccountGm.setText(view.getContext().getString(R.string.settings_account_gm_off));
+					SharedPreferences preferences = view.getContext().getSharedPreferences(GM.PREF, Context.MODE_PRIVATE);
+					SharedPreferences.Editor editor = preferences.edit();
+					editor.putInt(GM.PREF_GM, 0);
+					editor.commit();
+				}
+				else{
+					cbAccountGm.setChecked(true);
+					tvAccountGm.setText(view.getContext().getString(R.string.settings_account_gm_on));
+					SharedPreferences preferences = view.getContext().getSharedPreferences(GM.PREF, Context.MODE_PRIVATE);
+					SharedPreferences.Editor editor = preferences.edit();
+					editor.putInt(GM.PREF_GM, 1);
+					editor.commit();
+				}
+			}	
+		});
+		
+		//Set click listener for the "Name" preference
+		rlAccountName.setOnClickListener(new OnClickListener(){
+			@Override
+			public void onClick(View v) {
+				LayoutInflater inflater = (LayoutInflater) view.getContext().getSystemService( Context.LAYOUT_INFLATER_SERVICE );
+				View dialogLayout = inflater.inflate(R.layout.dialog_change_username, null);
+				AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
+				builder.setTitle(view.getContext().getString(R.string.settings_account_message_title));
+				// Set up the input
+				final EditText input = (EditText) dialogLayout.findViewById(R.id.et_change_username);
+				builder.setView(dialogLayout);
+
+				// Set up the buttons
+				builder.setPositiveButton(view.getContext().getString(R.string.settings_account_message_save), new DialogInterface.OnClickListener() { 
+				    @Override
+				    public void onClick(DialogInterface dialog, int which) {
+				        userName = input.getText().toString();
+				        tvAccountName.setText(userName);
+				        SharedPreferences preferences = view.getContext().getSharedPreferences(GM.PREF, Context.MODE_PRIVATE);
+						SharedPreferences.Editor editor = preferences.edit();
+						editor.putString(GM.USER_NAME, userName);
+						editor.commit();
+				    }
+				});
+				builder.setNegativeButton(view.getContext().getString(R.string.settings_account_message_cancel), new DialogInterface.OnClickListener() {
+				    @Override
+				    public void onClick(DialogInterface dialog, int which) {
+				        dialog.cancel();
+				    }
+				});
+
+				builder.show();
+			}
+		});
+		
+		
+		return view;
+	}
+}

+ 306 - 0
app/src/main/java/com/ivalentin/gm/Sync.java

@@ -0,0 +1,306 @@
+package com.ivalentin.gm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.AsyncTask;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ProgressBar;
+
+/**
+ * AsyncTask that synchronizes the online database to the device.
+ * Is run every time the app is started, and periodically in the background.
+ * 
+ * @author Inigo Valentin
+ *
+ */
+public class Sync extends AsyncTask<Void, Void, Void> {
+	
+	private Context myContextRef;
+	private ProgressBar pbSync;
+	private Dialog dialog;
+	private MainActivity activity;
+	private boolean fg;
+	private int newVersion;
+	
+	
+	/**
+	 * Things to do before sync. Namely, displaying a spinning progress bar.
+	 * @see android.os.AsyncTask#onPreExecute()
+	 */
+	@Override
+	protected void onPreExecute(){
+		if (pbSync != null)
+			pbSync.setVisibility(View.VISIBLE);
+		if (dialog != null){
+			dialog.show();
+		}
+		Log.d("Sync", "Starting full sync");
+	}
+	
+	/**
+	 * Things to do after sync. Namely, hiddng the spinning progress bar.
+	 * @see android.os.AsyncTask#onPreExecute()
+	 */
+	@Override
+	protected void onPostExecute(Void v){
+		if (pbSync != null)
+			pbSync.setVisibility(View.INVISIBLE);
+		if (dialog != null){
+			dialog.dismiss();
+			//Check db version agan
+			SharedPreferences preferences = myContextRef.getSharedPreferences(GM.PREF, Context.MODE_PRIVATE);
+			if (preferences.getInt(GM.PREF_DB_VERSION, GM.DEFAULT_PREF_DB_VERSION) == GM.DEFAULT_PREF_DB_VERSION){
+				//Create a dialog
+				final Dialog dial = new Dialog(activity);
+				dial.setCancelable(false);
+				
+				//Set up the window
+				dial.requestWindowFeature(Window.FEATURE_NO_TITLE);
+				dial.setContentView(R.layout.dialog_sync_failed);
+				
+				//Set button
+				Button btClose = (Button) dial.findViewById(R.id.bt_dialog_sync_failed_close);
+				btClose.setOnClickListener(new OnClickListener(){
+					@Override
+					public void onClick(View v) {
+					dial.dismiss();
+					activity.finish();
+					}
+				});
+				
+				//Show the dialog
+				dial.show();
+			}
+			else{
+				activity.loadSection(GM.SECTION_HOME, false);
+			}
+		}
+		Log.d("Sync", "Full sync finished");
+	}
+	
+    /**
+     * Called when the AsyncTask is created.
+     * 
+     * @param myContextRef The Context of the calling activity.
+     * @param pb The progress bar that will be shown while the sync goes on.
+     */
+    public Sync(Activity myContextRef, ProgressBar pb) {
+        this.myContextRef = myContextRef;
+        dialog = null;
+        pbSync = pb;
+        fg = true;
+    }
+    
+    /**
+     * Called when the AsyncTask is created. 
+     * This constructor is intended to use only in the first sync, 
+     * because a dialog will block the UI.
+     * 
+     * @param myContextRef The Context of the calling activity.
+     * @param d Dialog of the initial sync
+     * @param pb The progress bar that will be shown while the sync goes on.
+     * @param activity The calling MainActvity
+     */
+    public Sync(Activity myContextRef, ProgressBar pb, Dialog d, MainActivity activity) {
+    	this.dialog = d;
+    	this.activity = activity;
+        this.myContextRef = myContextRef;
+        pbSync = pb;
+        fg = true;
+    }
+    
+    /**
+     * Called when the AsyncTask is created.
+     * 
+     * @param context The Context of the calling activity.
+     */
+    public Sync(Context context) {
+        this.myContextRef = context;
+        pbSync = null;
+        fg = false;
+    }
+	
+	/**
+	 * The sweet stuff. Actually performs the sync. 
+	 * 
+	 * //@see android.os.AsyncTask#doInBackground(Params[])
+	 */
+	@Override
+	protected Void doInBackground(Void... params) {
+
+		//Gets the remote page.
+    	FetchURL fu;
+
+		//The lines of the received web page.
+		String o = null;
+		
+		//List of SQL queries to be performed, as received from the web page.
+		List<String> queryList = new ArrayList<>();
+		
+		//Preferences.
+		SharedPreferences preferences = myContextRef.getSharedPreferences(GM.PREF, Context.MODE_PRIVATE);
+		SharedPreferences.Editor prefEditor;
+		prefEditor = preferences.edit();
+
+		//Boolean that will prevent the process to go on if something goes wrong.
+		boolean success = true;
+		
+		//Get the file
+		try{
+			String user = preferences.getString(GM.USER_NAME, "");
+			String code = preferences.getString(GM.USER_CODE, "");
+			int dbVersion = preferences.getInt(GM.PREF_DB_VERSION, GM.DEFAULT_PREF_DB_VERSION);
+			fu = new FetchURL();
+			fu.Run(GM.SERVER + "/app/sync.php?user=" + user + "&code=" + code + "&fg=" + fg + "&v=" + dbVersion);
+			//All the info
+			o = fu.getOutput().toString();
+		}
+		catch(Exception ex){
+			Log.e("Sync error", "Error fetching remote file: " + ex.toString());
+			success = false;
+		}
+
+		int errorCount = 0;
+
+		if (success){
+
+			//Parse the contents of the page
+			//Check if the database is synced
+			if (o.contains("<synced>1</synced>")){
+				Log.i("SYNC", "Database is already at the latest version");
+				return null;
+			}
+
+			//Try to separate the file by tables (<table></table>)
+			try{
+				String table, tableName, row, fieldName, fieldValue, line, query, queryFields, queryValues;
+
+				//Get db version
+				newVersion = Integer.parseInt(o.substring(o.indexOf("<version>") + 9, o.indexOf("</version>")));
+
+				//Get other preferences and store them
+				int prefPhotos = Integer.parseInt(o.substring(o.indexOf("<photos>") + 8, o.indexOf("</photos>")));
+				int prefFestivals = Integer.parseInt(o.substring(o.indexOf("<festivals>") + 11, o.indexOf("</festivals>")));
+				prefEditor.putInt(GM.PREF_DB_PHOTOS, prefPhotos);
+				prefEditor.putInt(GM.PREF_DB_FESTIVALS, prefFestivals);
+				//prefEditor.commit();
+				prefEditor.apply();
+
+
+				while (o.contains("<table>")){
+
+					try {
+						table = o.substring(o.indexOf("<table>"), o.indexOf("</table>") + 8);
+						tableName = table.substring(table.indexOf("<name>") + 6, table.indexOf("</name>"));
+						queryList.add("DELETE FROM " + tableName + ";");
+						while (table.contains("<row>")) {
+
+							try {
+								if (table.length() < 5) {
+									break;
+								}
+								row = table.substring(table.indexOf("<row>") + 5, table.indexOf("</row>"));
+								query = "INSERT INTO " + tableName + " ";
+								queryFields = "(";
+								queryValues = "(";
+								while (row.contains(">,")) {
+
+										try {
+											if (row.length() < 5) {
+												break;
+											}
+											line = row.substring(0, row.indexOf(">,"));
+											line = line.substring(line.indexOf("<"));
+											fieldName = line.substring(line.indexOf("<") + 1, line.indexOf(">"));
+											queryFields = queryFields + fieldName + ", ";
+											fieldValue = line.substring(line.indexOf("<" + fieldName + ">") + 2 + fieldName.length());
+											fieldValue = fieldValue.substring(0, fieldValue.length() - fieldName.length() - 2);
+											if (fieldValue.length() == 0)
+												fieldValue = "null";
+											if (fieldValue.charAt(0) == '\'' && fieldValue.charAt(fieldValue.length() - 1) == '\'') {
+												fieldValue = fieldValue.substring(1, fieldValue.length() - 1);
+												fieldValue = fieldValue.replace("'", "''");
+												fieldValue = "\'" + fieldValue + "\'";
+											}
+											queryValues = queryValues + fieldValue + ", ";
+											row = row.substring(row.indexOf(">,") + 2);
+										}
+										catch(Exception ex){
+											Log.e("Parsing error", "Error getting values from row: " + ex.toString());
+											errorCount ++;
+											break;
+										}
+								}
+
+								queryFields = queryFields.substring(0, queryFields.length() - 2) + ")";
+								queryValues = queryValues.substring(0, queryValues.length() - 2) + ")";
+								query = query + queryFields + " VALUES " + queryValues + ";";
+								queryList.add(query);
+
+								table = table.substring(table.indexOf("</row>") + 6);
+							}
+							catch(Exception ex){
+								Log.e("Parsing error", "Error getting rows from tables: " + ex.toString());
+								errorCount ++;
+								break;
+							}
+						}
+					}
+					catch(Exception ex){
+						Log.e("Parsing error", "Error getting tables from the sync file: " + ex.toString());
+						errorCount ++;
+						break;
+					}
+					o = o.substring(o.indexOf("</table>") + 8);
+				}
+			}
+			catch(Exception ex){
+				Log.e("Sync error", "Error parsing remote info: " + ex.toString());
+				errorCount ++;
+			}
+		}
+		try{
+			SQLiteDatabase db = myContextRef.openOrCreateDatabase(GM.DB_NAME, Activity.MODE_PRIVATE, null);
+			for(int i = 0; i < queryList.size(); i++){
+				try {
+					db.execSQL(queryList.get(i));
+				}
+				catch(Exception ex){
+					Log.e("Query Error", "Error on sync query: " + ex.toString());
+					errorCount ++;
+				}
+			}
+			db.close();
+
+			//Set current database version in preferences.
+			if (errorCount == 0){
+				prefEditor.putInt(GM.PREF_DB_VERSION, newVersion);
+				//prefEditor.commit();
+				prefEditor.apply();
+			}
+			else{
+				Log.e("DB UPDATE", "Not updating db version because there were errors");
+				if (preferences.getInt(GM.PREF_DB_VERSION, GM.DEFAULT_PREF_DB_VERSION) == GM.DEFAULT_PREF_DB_VERSION) {
+					prefEditor.putInt(GM.PREF_DB_VERSION, GM.DEFAULT_PREF_DB_VERSION + 1);
+					//prefEditor.commit();
+					prefEditor.apply();
+				}
+			}
+		}
+		catch(Exception ex){
+			Log.e("Sync error", "Error updating info: " + ex.toString());
+		}
+		return null;
+    	
+	}
+}

BIN
app/src/main/res/drawable-xhdpi/pinpoint_gm.png


BIN
app/src/main/res/drawable-xxhdpi/pinpoint_gm.png


+ 14 - 0
app/src/main/res/drawable/album.xml

@@ -0,0 +1,14 @@
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+
+    <stroke
+        android:width="2dp"
+        android:color="@color/album_border" />
+    <solid android:color="@color/album_background" />
+    <corners android:bottomRightRadius="7dp" android:bottomLeftRadius="7dp"
+        android:topLeftRadius="7dp" android:topRightRadius="7dp"/>
+    <padding android:left="8dp"
+        android:top="8dp"
+        android:right="8dp"
+        android:bottom="8dp" />
+</shape>

BIN
app/src/main/res/drawable/alpha.png


+ 18 - 0
app/src/main/res/drawable/arrowbutton.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Shape for blue-ish arrow buttons -->
+
+<shape 
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	android:shape="rectangle">
+	<gradient
+		android:startColor="@color/arrow_button_start"
+		android:centerColor="@color/arrow_button_center"
+		android:endColor="@color/arrow_button_start"
+		android:angle="270" />
+	<corners 
+		android:radius="5dp" />
+	<stroke 
+		android:width="2px"
+		android:color="@color/arrow_button_border" />
+</shape>

+ 18 - 0
app/src/main/res/drawable/arrowbuttonpressed.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Shape for blue-ish arrow buttons when pressed -->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+	android:shape="rectangle">
+	<gradient
+		android:startColor="@color/arrow_button_start_pressed"
+		android:centerColor="@color/arrow_button_center_pressed"
+		android:endColor="@color/arrow_button_start_pressed"
+		android:angle="270" />
+		<corners
+		    android:radius="5dp" />
+		<stroke
+		    android:width="2px"
+		    android:color="@color/arrow_button_border" />
+	</shape>

+ 13 - 0
app/src/main/res/drawable/arrowbuttonselector.xml

@@ -0,0 +1,13 @@
+<!-- Selector for the arrow buttons -->
+
+<selector
+    xmlns:android="http://schemas.android.com/apk/res/android">
+	<item
+	    android:state_focused="true"
+	    android:drawable="@drawable/arrowbutton"/>
+	<item
+	    android:state_pressed="true"
+	    android:drawable="@drawable/arrowbuttonpressed" />
+	<item
+	    android:drawable="@drawable/arrowbutton" />
+</selector>

+ 18 - 0
app/src/main/res/drawable/background_app.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Shape for the slider menu -->
+
+<selector
+    xmlns:android="http://schemas.android.com/apk/res/android">
+	<item>
+	    <shape>
+	        <gradient
+	            android:angle="90"
+	            android:centerY="10%"
+	            android:centerX="0.1"
+	            android:startColor="@color/background_app_gradient"
+	            android:endColor="@color/background_app"
+	            android:type="linear" />
+	    </shape>
+	</item>
+</selector>

+ 18 - 0
app/src/main/res/drawable/background_menu.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Shape for the slider menu -->
+
+<selector
+    xmlns:android="http://schemas.android.com/apk/res/android">
+	<item>
+	    <shape>
+	        <gradient
+	            android:angle="0"
+	            android:centerY="10%"
+	            android:centerX="0.1"
+	            android:startColor="@color/background_menu_gradient"
+	            android:endColor="@color/background_menu"
+	            android:type="linear" />
+	    </shape>
+	</item>
+</selector>

+ 15 - 0
app/src/main/res/drawable/button.xml

@@ -0,0 +1,15 @@
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+
+    <stroke
+        android:width="5dp"
+        android:color="@color/input_border" />
+    <solid android:color="@color/input_background" />
+    <corners android:bottomRightRadius="7dp" android:bottomLeftRadius="7dp"
+        android:topLeftRadius="7dp" android:topRightRadius="7dp"/>
+    <padding android:left="5dp"
+        android:top="5dp"
+        android:right="5dp"
+        android:bottom="5dp" />
+
+</shape>

+ 11 - 0
app/src/main/res/drawable/button_selector.xml

@@ -0,0 +1,11 @@
+<selector
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:state_focused="true"
+        android:drawable="@drawable/button"/>
+    <item
+        android:state_pressed="true"
+        android:drawable="@drawable/buttonpressed" />
+    <item
+        android:drawable="@drawable/button" />
+</selector>

+ 15 - 0
app/src/main/res/drawable/buttonpressed.xml

@@ -0,0 +1,15 @@
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+
+    <stroke
+        android:width="5dp"
+        android:color="@color/input_border" />
+    <solid android:color="@color/input_background_pressed" />
+    <corners android:bottomRightRadius="7dp" android:bottomLeftRadius="7dp"
+        android:topLeftRadius="7dp" android:topRightRadius="7dp"/>
+    <padding android:left="5dp"
+        android:top="5dp"
+        android:right="5dp"
+        android:bottom="5dp" />
+
+</shape>

BIN
app/src/main/res/drawable/comment.png


+ 18 - 0
app/src/main/res/drawable/datebar.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Shape for the date selector bar -->
+
+<selector
+    xmlns:android="http://schemas.android.com/apk/res/android">
+	<item>
+	    <shape>
+	        <gradient
+	            android:angle="90"
+	            android:centerY="10%"
+	            android:centerX="0.1"
+	            android:startColor="@color/background_date_gradient"
+	            android:endColor="@color/background_date"
+	            android:type="linear" />
+	    </shape>
+	</item>
+</selector>

+ 14 - 0
app/src/main/res/drawable/dialog_schedule.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+	android:shape="rectangle">
+	<gradient
+		android:angle="90"
+		android:centerY="10%"
+		android:centerX="0.1"
+		android:startColor="@color/background_app_gradient"
+		android:endColor="@color/background_app"
+		android:type="linear" />
+	<stroke 
+		android:width="2px"
+		android:color="@color/black" />
+</shape>

+ 11 - 0
app/src/main/res/drawable/dialog_schedule_map.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+	android:shape="rectangle">
+	<corners
+		android:radius="5dp"/>
+	<stroke 
+		android:width="5px"
+		android:color="@color/black" />
+	<solid 
+	    android:color="@color/white" />
+</shape>

BIN
app/src/main/res/drawable/divider.png


+ 9 - 0
app/src/main/res/drawable/entry.xml

@@ -0,0 +1,9 @@
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+
+    <stroke
+        android:width="2dp"
+        android:color="@color/entry_border" />
+    <solid android:color="@color/entry_background" />
+
+</shape>

+ 11 - 0
app/src/main/res/drawable/home_section_title.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+  android:shape="rectangle">
+  <gradient
+	android:startColor="@color/home_section_background"
+    android:endColor="#00ffffff"
+    android:angle="270" />
+  <corners
+      android:topLeftRadius="12dp"
+      android:topRightRadius="12dp" />
+</shape>

BIN
app/src/main/res/drawable/ic_launcher.png


BIN
app/src/main/res/drawable/ic_launcher_old.png


BIN
app/src/main/res/drawable/ic_notification.png


BIN
app/src/main/res/drawable/icon_about.png


BIN
app/src/main/res/drawable/icon_activities.png


BIN
app/src/main/res/drawable/icon_around.png


BIN
app/src/main/res/drawable/icon_blog.png


BIN
app/src/main/res/drawable/icon_gallery.png


BIN
app/src/main/res/drawable/icon_gm.png


BIN
app/src/main/res/drawable/icon_go.png


BIN
app/src/main/res/drawable/icon_home.png


BIN
app/src/main/res/drawable/icon_lablanca.png


BIN
app/src/main/res/drawable/icon_location.png


BIN
app/src/main/res/drawable/icon_news.png


BIN
app/src/main/res/drawable/icon_program.png


BIN
app/src/main/res/drawable/icon_settings.png


+ 14 - 0
app/src/main/res/drawable/input.xml

@@ -0,0 +1,14 @@
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+
+    <stroke
+        android:width="5dp"
+        android:color="@color/input_border" />
+    <solid android:color="@color/input_background" />
+    <corners android:bottomRightRadius="7dp" android:bottomLeftRadius="7dp"
+        android:topLeftRadius="7dp" android:topRightRadius="7dp"/>
+    <padding android:left="8dp"
+        android:top="8dp"
+        android:right="8dp"
+        android:bottom="8dp" />
+</shape>

+ 11 - 0
app/src/main/res/drawable/location_map.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+	android:shape="rectangle">
+	<corners
+		android:radius="5dp"/>
+	<stroke 
+		android:width="5px"
+		android:color="@color/black" />
+	<solid 
+	    android:color="@color/white" />
+</shape>

BIN
app/src/main/res/drawable/menu.png


BIN
app/src/main/res/drawable/pinpoint.png


BIN
app/src/main/res/drawable/pinpoint_gm.png


BIN
app/src/main/res/drawable/pinpoint_map.png


BIN
app/src/main/res/drawable/price_day.png


BIN
app/src/main/res/drawable/price_offer.png


+ 13 - 0
app/src/main/res/drawable/schedule_entry.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+	android:shape="rectangle">
+	<solid
+		android:color="@color/around_background"/>
+	<corners
+	    android:radius="2dp" />
+	<stroke
+	    android:width="2px"
+	    android:color="@color/around_border" />
+</shape>

BIN
app/src/main/res/drawable/schedule_point.png


BIN
app/src/main/res/drawable/schedule_timeline.png


+ 9 - 0
app/src/main/res/drawable/section.xml

@@ -0,0 +1,9 @@
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+
+    <stroke
+        android:width="4dp"
+        android:color="@color/section_border" />
+    <solid android:color="@color/section_background" />
+
+</shape>

BIN
app/src/main/res/drawable/social_facebook.png


BIN
app/src/main/res/drawable/social_googleplus.png


BIN
app/src/main/res/drawable/social_instagram.png


BIN
app/src/main/res/drawable/social_mail.png


BIN
app/src/main/res/drawable/social_twitter.png


BIN
app/src/main/res/drawable/social_web.png


BIN
app/src/main/res/drawable/social_whatsapp.png


BIN
app/src/main/res/drawable/social_youtube.png


BIN
app/src/main/res/drawable/spinner_spinning.gif


BIN
app/src/main/res/drawable/spinner_stop.png


+ 8 - 0
app/src/main/res/drawable/timeline.xml

@@ -0,0 +1,8 @@
+<!-- Bitmap to use as background of the dotted timeline in schedules. -->
+
+<bitmap
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	android:src="@drawable/schedule_timeline"
+	android:tileMode="repeat"
+	android:gravity="center"
+	android:dither="true" />

+ 18 - 0
app/src/main/res/drawable/titlebar.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Shape for the title bar -->
+
+<selector
+    xmlns:android="http://schemas.android.com/apk/res/android">
+	<item>
+	    <shape>
+	        <gradient
+	            android:angle="90"
+	            android:centerY="10%"
+	            android:centerX="0.1"
+	            android:startColor="@color/background_bar_gradient"
+	            android:endColor="@color/background_bar"
+	            android:type="linear" />
+	    </shape>
+	</item>
+</selector>

+ 281 - 0
app/src/main/res/layout/activity_main.xml

@@ -0,0 +1,281 @@
+<com.ivalentin.gm.MainLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/main_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+	android:background="@color/background_menu"
+	android:fitsSystemWindows="true" >
+    
+	
+    <!-- Slider menu -->
+
+    <ScrollView
+        android:layout_width="wrap_content"
+        android:layout_height="fill_parent" >
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:divider="@drawable/divider"
+            android:orientation="vertical"
+            android:padding="10dp">
+
+            <TextView
+                android:id="@+id/menu_home"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="10dp"
+                android:layout_marginTop="10dp"
+                android:gravity="center_vertical"
+                android:text="@string/menu_home"
+                android:textAppearance="?android:attr/textAppearanceLarge"
+				android:textStyle="bold"
+				android:textColor="@color/menu_entry" />
+			<View
+				android:layout_width="fill_parent"
+				android:layout_height="1dp"
+				android:background="@color/background_separator"/>
+
+			<TextView
+                android:id="@+id/menu_location"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="10dp"
+                android:layout_marginTop="10dp"
+				android:gravity="center_vertical"
+                android:text="@string/menu_location"
+                android:textAppearance="?android:attr/textAppearanceLarge"
+                android:textStyle="bold"
+				android:textColor="@color/menu_entry" />
+
+			<View
+				android:layout_width="fill_parent"
+				android:layout_height="1dp"
+				android:background="@color/background_separator"/>
+
+			<TextView
+				android:id="@+id/menu_lablanca"
+				android:layout_width="fill_parent"
+				android:layout_height="wrap_content"
+				android:layout_marginBottom="10dp"
+				android:layout_marginTop="10dp"
+				android:gravity="center_vertical"
+				android:text="@string/menu_lablanca"
+				android:textAppearance="?android:attr/textAppearanceLarge"
+				android:textStyle="bold"
+				android:textColor="@color/menu_entry" />
+
+            <TextView
+                android:id="@+id/menu_lablanca_schedule"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="10dp"
+                android:layout_marginTop="10dp"
+				android:layout_marginStart="20dp"
+				android:layout_marginLeft="20dp"
+                android:gravity="center_vertical"
+                android:text="@string/menu_lablanca_schedule"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+				android:textColor="@color/menu_entry" />
+
+            <TextView
+                android:id="@+id/menu_lablanca_gm_schedule"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="10dp"
+                android:layout_marginTop="10dp"
+				android:layout_marginStart="20dp"
+				android:layout_marginLeft="20dp"
+                android:gravity="center_vertical"
+                android:text="@string/menu_lablanca_gm_schedule"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+				android:textColor="@color/menu_entry" />
+
+            <TextView
+                android:id="@+id/menu_lablanca_around"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="10dp"
+                android:layout_marginTop="10dp"
+				android:layout_marginStart="20dp"
+				android:layout_marginLeft="20dp"
+                android:gravity="center_vertical"
+                android:text="@string/menu_lablanca_around"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+				android:textColor="@color/menu_entry" />
+
+			<View
+				android:layout_width="fill_parent"
+				android:layout_height="1dp"
+				android:background="@color/background_separator"/>
+
+			<TextView
+				android:id="@+id/menu_activities"
+				android:layout_width="fill_parent"
+				android:layout_height="wrap_content"
+				android:layout_marginBottom="10dp"
+				android:layout_marginTop="10dp"
+				android:gravity="center_vertical"
+				android:text="@string/menu_activities"
+				android:textAppearance="?android:attr/textAppearanceLarge"
+				android:textStyle="bold"
+				android:textColor="@color/menu_entry" />
+
+			<View
+				android:layout_width="fill_parent"
+				android:layout_height="1dp"
+				android:background="@color/background_separator"/>
+
+			<TextView
+				android:id="@+id/menu_blog"
+				android:layout_width="fill_parent"
+				android:layout_height="wrap_content"
+				android:layout_marginBottom="10dp"
+				android:layout_marginTop="10dp"
+				android:gravity="center_vertical"
+				android:text="@string/menu_blog"
+				android:textAppearance="?android:attr/textAppearanceLarge"
+				android:textStyle="bold"
+				android:textColor="@color/menu_entry" />
+
+			<View
+				android:layout_width="fill_parent"
+				android:layout_height="1dp"
+				android:background="@color/background_separator"/>
+
+			<TextView
+				android:id="@+id/menu_gallery"
+				android:layout_width="fill_parent"
+				android:layout_height="wrap_content"
+				android:layout_marginBottom="10dp"
+				android:layout_marginTop="10dp"
+				android:gravity="center_vertical"
+				android:text="@string/menu_gallery"
+				android:textAppearance="?android:attr/textAppearanceLarge"
+				android:textStyle="bold"
+				android:textColor="@color/menu_entry" />
+
+			<View
+				android:layout_width="fill_parent"
+				android:layout_height="1dp"
+				android:background="@color/background_separator"/>
+
+			<TextView
+				android:id="@+id/menu_about"
+				android:layout_width="fill_parent"
+				android:layout_height="wrap_content"
+				android:layout_marginBottom="10dp"
+				android:layout_marginTop="10dp"
+				android:gravity="center_vertical"
+				android:text="@string/menu_about"
+				android:textAppearance="?android:attr/textAppearanceLarge"
+				android:textStyle="bold"
+				android:textColor="@color/menu_entry" />
+
+			<View
+				android:layout_width="fill_parent"
+				android:layout_height="1dp"
+				android:background="@color/background_separator"/>
+
+            <TextView
+                android:id="@+id/menu_settings"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="10dp"
+                android:layout_marginTop="10dp"
+                android:gravity="center_vertical"
+                android:text="@string/menu_settings"
+                android:textAppearance="?android:attr/textAppearanceLarge"
+				android:textStyle="bold"
+				android:textColor="@color/menu_entry" />
+
+        </LinearLayout>
+
+    </ScrollView>
+
+	<!-- The visible screen -->
+
+	<LinearLayout
+	    xmlns:android="http://schemas.android.com/apk/res/android"
+	    android:layout_width="match_parent"
+	    android:layout_height="match_parent"
+	    android:background="@color/background_app"
+	    android:orientation="vertical" >
+
+		<!-- The action bar -->
+
+		<LinearLayout
+		    android:layout_width="fill_parent"
+		    android:layout_height="wrap_content"
+		    android:background="@drawable/titlebar"
+		    android:gravity="center_vertical"
+		    android:orientation="horizontal" >
+			
+		    <!-- Button to open slider menu -->
+
+			<ImageButton
+			    android:id="@+id/bt_menu"
+			    android:layout_width="wrap_content"
+			    android:layout_height="wrap_content"
+			    android:layout_weight=".2"
+			    android:adjustViewBounds="true"
+			    android:background="#00000000"
+			    android:contentDescription="@string/app_name"
+			    android:maxHeight="60dp"
+			    android:maxWidth="60dp"
+			    android:padding="2dp"
+			    android:scaleType="fitCenter"
+			    android:src="@drawable/ic_launcher" />
+
+			<!-- Layout with the app title and current section -->
+
+			<LinearLayout
+			    android:layout_width="wrap_content"
+			    android:layout_height="match_parent"
+			    android:layout_gravity="center"
+			    android:layout_weight=".8"
+			    android:gravity="center"
+			    android:orientation="vertical" >
+
+			    <!-- App name. Remains unchanged -->
+
+			    <TextView
+			        android:layout_width="wrap_content"
+			        android:layout_height="wrap_content"
+			        android:gravity="center"
+			        android:text="@string/app_name"
+			        android:textSize="18sp"
+			        android:textStyle="bold" />
+			    
+			    <!-- Section title -->
+
+				<TextView
+				    android:id="@+id/activity_main_content_title"
+				    android:layout_width="wrap_content"
+				    android:layout_height="wrap_content"
+				    android:gravity="center"
+				    android:text="@string/menu_home"
+				    android:textSize="20sp" />
+
+			</LinearLayout>
+
+			<ProgressBar
+			    android:id="@+id/pb_sync"
+			    android:layout_width="wrap_content"
+			    android:layout_height="wrap_content"
+			    android:layout_weight=".2"
+			    android:visibility="invisible" />
+			
+		</LinearLayout>	
+		
+		<!-- The part where the fragments will be loaded -->
+
+		<FrameLayout
+		    android:id="@+id/activity_main_content_fragment"
+		    android:layout_width="match_parent"
+		    android:layout_height="match_parent" >
+		
+		</FrameLayout>
+		
+	</LinearLayout>
+
+</com.ivalentin.gm.MainLayout>

+ 139 - 0
app/src/main/res/layout/dialog_around.xml

@@ -0,0 +1,139 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:background="@drawable/dialog_schedule"
+    android:orientation="vertical" >
+
+    <LinearLayout
+        android:id="@+id/ll_dialog_schedule_buttons"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:orientation="horizontal" >
+
+        <Button
+            android:id="@+id/bt_around_close"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="5dp"
+            android:layout_marginEnd="25dp"
+            android:layout_marginLeft="25dp"
+            android:layout_marginRight="25dp"
+            android:layout_marginStart="25dp"
+            android:layout_marginTop="5dp"
+            android:layout_weight=".5"
+            android:background="@drawable/arrowbutton"
+            android:minHeight="40dp"
+            android:text="@string/schedule_close" />
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_above="@id/ll_dialog_schedule_buttons"
+        android:layout_alignParentTop="true"
+        android:orientation="vertical"
+        android:padding="10dp" >
+
+        <TextView
+            android:id="@+id/tv_dialog_around_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="5dp"
+            android:textColor="@color/text_dialog"
+            android:textSize="25sp"
+            android:textStyle="bold" />
+        
+        <TextView
+            android:layout_width="fill_parent"
+            android:layout_height="1dp"
+            android:layout_margin="5dp"
+            android:background="@color/black" />
+
+        <TextView
+            android:id="@+id/tv_dialog_around_description"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="10dp"
+            android:layout_marginBottom="10dp"
+            android:textColor="@color/text_dialog"
+            android:textSize="14sp" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" >
+
+            <TextView
+                android:id="@+id/tv_dialog_around_date"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textColor="@color/text_dialog"
+                android:textSize="14sp" />
+
+            <TextView
+                android:id="@+id/tv_dialog_around_time"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="10dp"
+                android:layout_marginStart="10dp"
+                android:textColor="@color/text_dialog"
+                android:textSize="14sp" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="10dp"
+            android:orientation="horizontal" >
+
+            <ImageView
+                android:id="@+id/imageView1"
+                android:layout_width="wrap_content"
+                android:layout_height="fill_parent"
+                android:adjustViewBounds="true"
+                android:contentDescription="@string/arrow_right"
+                android:maxHeight="50dp"
+                android:maxWidth="50dp"
+                android:scaleType="centerInside"
+                android:src="@drawable/pinpoint" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical" >
+
+                <TextView
+                    android:id="@+id/tv_dialog_around_place"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="@color/text_dialog"
+                    android:textSize="14sp" />
+
+                <TextView
+                    android:id="@+id/tv_dialog_around_address"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="@color/text_dialog"
+                    android:textSize="12sp" />
+
+            </LinearLayout>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_margin="20dp"
+            android:background="@drawable/dialog_schedule_map"
+            android:padding="3dp" >
+
+            <com.google.android.gms.maps.MapView
+                android:id="@+id/mv_dialog_around_map"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent" >
+            </com.google.android.gms.maps.MapView>
+        </LinearLayout>
+    </LinearLayout>
+
+</RelativeLayout>

+ 22 - 0
app/src/main/res/layout/dialog_change_username.xml

@@ -0,0 +1,22 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+    <TextView
+        android:id="@+id/textView1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/settings_account_message_text" />
+
+    <EditText
+        android:id="@+id/et_change_username"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:ems="10"
+        android:inputType="textPersonName" >
+
+        <requestFocus />
+    </EditText>
+
+</LinearLayout>

+ 77 - 0
app/src/main/res/layout/dialog_notification.xml

@@ -0,0 +1,77 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/background_app"
+    android:orientation="vertical"
+    android:padding="5dp" >
+
+    <TextView
+        android:id="@+id/tv_dialog_notification_title"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_marginTop="10dp"
+        android:ellipsize="end"
+        android:gravity="center_horizontal"
+        android:maxLines="2"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:textColor="@color/text_dialog"
+        android:textSize="25sp" />
+
+    <TextView
+        android:id="@+id/tv_dialog_notification_separator"
+        android:layout_width="fill_parent"
+        android:layout_height="1dp"
+        android:layout_below="@id/tv_dialog_notification_title"
+        android:layout_margin="15dp"
+        android:background="@color/black" />
+
+    <LinearLayout
+        android:id="@+id/ll_dialog_notification_buttons"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:gravity="center_horizontal"
+        android:orientation="horizontal" >
+
+        <Button
+            android:id="@+id/bt_dialog_notification_action"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="5dp"
+            android:background="@drawable/arrowbutton" />
+
+        <Button
+            android:id="@+id/bt_dialog_notification_close"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="5dp"
+            android:background="@drawable/arrowbutton"
+            android:text="@string/notification_close" />
+
+    </LinearLayout>
+
+    <ScrollView
+        android:id="@+id/scrollView1"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_above="@id/ll_dialog_notification_buttons"
+        android:layout_below="@id/tv_dialog_notification_separator" >
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical" >
+
+            <TextView
+                android:id="@+id/tv_dialog_notification_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="12dp"
+                android:textColor="@color/text_dialog"
+                android:textSize="18sp" />
+
+        </LinearLayout>
+    </ScrollView>
+
+</RelativeLayout>

+ 485 - 0
app/src/main/res/layout/dialog_prices.xml

@@ -0,0 +1,485 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="@drawable/background_app"
+    android:paddingBottom="5dp" >
+
+    <Button
+        android:id="@+id/bt_dialog_prices_close"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_centerHorizontal="true"
+        android:layout_centerVertical="false"
+        android:layout_marginBottom="10dp"
+        android:background="@drawable/arrowbutton"
+        android:minHeight="48dp"
+        android:minWidth="95dp"
+        android:text="@string/prices_close" />
+
+	<ScrollView
+	    android:id="@+id/scrollView1"
+	    android:layout_width="fill_parent"
+	    android:layout_height="fill_parent"
+	    android:layout_above="@id/bt_dialog_prices_close"
+	    android:layout_alignParentTop="true"
+	    android:fadingEdge="vertical"
+	    android:fadingEdgeLength="30dp"
+	    android:padding="0dp"
+	    android:requiresFadingEdge="vertical" >
+	
+	    <LinearLayout
+	        android:layout_width="match_parent"
+	        android:layout_height="wrap_content"
+	        android:layout_marginEnd="6dp"
+	        android:layout_marginLeft="6dp"
+	        android:layout_marginRight="6dp"
+	        android:layout_marginStart="6dp"
+	        android:orientation="vertical" >
+	
+	        <TextView
+	            android:id="@+id/textView1"
+	            android:layout_width="fill_parent"
+	            android:layout_height="wrap_content"
+	            android:text="@string/prices_title"
+	            android:textAppearance="@android:style/TextAppearance.Large"
+	            android:textColor="@color/text_dialog"
+	            android:textSize="30sp"
+	            android:textStyle="bold" />
+	
+	        <TextView
+	            android:id="@+id/textView2"
+	            android:layout_width="fill_parent"
+	            android:layout_height="wrap_content"
+	            android:layout_marginTop="15dp"
+	            android:background="@drawable/home_section_title"
+	            android:padding="3dp"
+	            android:text="@string/prices_section_days"
+	            android:textAppearance="?android:attr/textAppearanceMedium"
+	            android:textColor="@color/text_dialog"
+	            android:textSize="20sp" />
+	        
+	        <TableLayout
+	            android:layout_width="match_parent"
+	            android:layout_height="wrap_content"
+	            android:layout_marginEnd="10dp"
+	            android:layout_marginLeft="10dp"
+	            android:layout_marginRight="10dp"
+	            android:layout_marginStart="10dp"
+	            android:layout_marginTop="20dp"
+	            android:shrinkColumns="0" >
+
+	            <TableRow
+	                android:id="@+id/tableRow4"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_marginBottom="8dp"
+	                android:layout_marginTop="8dp" >
+
+	                <TextView
+	                    android:id="@+id/tv_prices_day_name_0"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+
+	                <TextView
+	                    android:id="@+id/tv_prices_day_price_0"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:layout_gravity="center_vertical"
+	                    android:layout_marginLeft="10dp"
+	                    android:layout_marginStart="10dp"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+
+	            </TableRow>
+
+	            <TableRow
+	                android:id="@+id/TableRow01"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_marginBottom="8dp"
+	                android:layout_marginTop="8dp" >
+
+	                <TextView
+	                    android:id="@+id/tv_prices_day_name_1"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+
+	                <TextView
+	                    android:id="@+id/tv_prices_day_price_1"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:layout_gravity="center_vertical"
+	                    android:layout_marginLeft="10dp"
+	                    android:layout_marginStart="10dp"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+
+	            </TableRow>
+
+	            <TableRow
+	                android:id="@+id/TableRow02"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_marginBottom="8dp"
+	                android:layout_marginTop="8dp" >
+
+	                <TextView
+	                    android:id="@+id/tv_prices_day_name_2"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+
+	                <TextView
+	                    android:id="@+id/tv_prices_day_price_2"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:layout_gravity="center_vertical"
+	                    android:layout_marginLeft="10dp"
+	                    android:layout_marginStart="10dp"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+
+	            </TableRow>
+
+	            <TableRow
+	                android:id="@+id/TableRow03"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_marginBottom="8dp"
+	                android:layout_marginTop="8dp" >
+
+	                <TextView
+	                    android:id="@+id/tv_prices_day_name_3"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+
+	                <TextView
+	                    android:id="@+id/tv_prices_day_price_3"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:layout_gravity="center_vertical"
+	                    android:layout_marginLeft="10dp"
+	                    android:layout_marginStart="10dp"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+
+	            </TableRow>
+
+	            <TableRow
+	                android:id="@+id/TableRow04"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_marginBottom="8dp"
+	                android:layout_marginTop="8dp" >
+
+	                <TextView
+	                    android:id="@+id/tv_prices_day_name_4"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+
+	                <TextView
+	                    android:id="@+id/tv_prices_day_price_4"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:layout_gravity="center_vertical"
+	                    android:layout_marginLeft="10dp"
+	                    android:textColor="@color/text_dialog"
+	                    android:layout_marginStart="10dp"
+	                    android:textSize="17sp" />
+
+	            </TableRow>
+
+	            <TableRow
+	                android:id="@+id/TableRow05"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_marginBottom="8dp"
+	                android:layout_marginTop="8dp" >
+
+	                <TextView
+	                    android:id="@+id/tv_prices_day_name_5"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+
+	                <TextView
+	                    android:id="@+id/tv_prices_day_price_5"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:layout_gravity="center_vertical"
+	                    android:layout_marginLeft="10dp"
+	                    android:layout_marginStart="10dp"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+
+	            </TableRow>
+	
+	        </TableLayout>
+	        
+	        <TextView
+	            android:layout_width="fill_parent"
+	            android:layout_height="wrap_content"
+	            android:layout_marginTop="35dp"
+	            android:background="@drawable/home_section_title"
+	            android:padding="3dp"
+	            android:text="@string/prices_section_packs"
+	            android:textAppearance="?android:attr/textAppearanceMedium"
+	            android:textColor="@color/text_dialog"
+	            android:textSize="20sp" />
+
+	        <TableLayout
+	            android:layout_width="match_parent"
+	            android:layout_height="wrap_content"
+	            android:layout_marginEnd="10dp"
+	            android:layout_marginLeft="10dp"
+	            android:layout_marginRight="10dp"
+	            android:layout_marginStart="10dp"
+	            android:layout_marginTop="20dp"
+	            android:shrinkColumns="0" >
+
+	            <TableRow
+	                android:id="@+id/tableRow1"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_marginBottom="8dp"
+	                android:layout_marginTop="8dp" >
+
+	                <TextView
+	                    android:id="@+id/tv_prices_offer_name_0"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+
+	                <TextView
+	                    android:id="@+id/tv_prices_offer_price_0"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:layout_gravity="center_vertical"
+	                    android:layout_marginLeft="10dp"
+	                    android:layout_marginStart="10dp"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+	            </TableRow>
+
+	            <TableRow
+	                android:id="@+id/tableRow2"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_marginBottom="8dp"
+	                android:layout_marginTop="8dp" >
+
+	                <TextView
+	                    android:id="@+id/tv_prices_offer_name_1"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+
+	                <TextView
+	                    android:id="@+id/tv_prices_offer_price_1"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:layout_gravity="center_vertical"
+	                    android:layout_marginLeft="10dp"
+	                    android:layout_marginStart="10dp"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+	            </TableRow>
+
+	            <TableRow
+	                android:id="@+id/tableRow3"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_marginBottom="8dp"
+	                android:layout_marginTop="8dp" >
+
+	                <TextView
+	                    android:id="@+id/tv_prices_offer_name_2"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+
+	                <TextView
+	                    android:id="@+id/tv_prices_offer_price_2"
+	                    android:layout_width="wrap_content"
+	                    android:layout_height="wrap_content"
+	                    android:layout_gravity="center_vertical"
+	                    android:layout_marginLeft="10dp"
+	                    android:layout_marginStart="10dp"
+	                    android:textColor="@color/text_dialog"
+	                    android:textSize="17sp" />
+	            </TableRow>
+	        </TableLayout>
+
+	        <TextView
+	            android:layout_width="fill_parent"
+	            android:layout_height="wrap_content"
+	            android:layout_marginTop="35dp"
+	            android:background="@drawable/home_section_title"
+	            android:padding="3dp"
+	            android:text="@string/prices_section_calculator"
+	            android:textAppearance="?android:attr/textAppearanceMedium"
+	            android:textColor="@color/text_dialog"
+	            android:textSize="20sp" />
+
+	        <LinearLayout
+	            android:layout_width="match_parent"
+	            android:layout_height="wrap_content"
+	            android:layout_marginEnd="10dp"
+	            android:layout_marginLeft="10dp"
+	            android:layout_marginRight="10dp"
+	            android:layout_marginStart="10dp"
+	            android:layout_marginTop="20dp"
+	            android:orientation="vertical" >
+
+	            <TextView
+	                android:id="@+id/textView3"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:textColor="@color/text_dialog"
+	                android:text="@string/prices_calculator" />
+
+	            <CheckBox
+	                android:id="@+id/cb_dialog_prices_0"
+	                android:textColor="@color/text_dialog"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content" />
+	            
+	            <CheckBox
+	                android:id="@+id/cb_dialog_prices_1"
+	                android:textColor="@color/text_dialog"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content" />
+	            
+	            <CheckBox
+	                android:id="@+id/cb_dialog_prices_2"
+	                android:textColor="@color/text_dialog"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content" />
+	            
+	            <CheckBox
+	                android:id="@+id/cb_dialog_prices_3"
+	                android:textColor="@color/text_dialog"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content" />
+	            
+	            <CheckBox
+	                android:id="@+id/cb_dialog_prices_4"
+	                android:textColor="@color/text_dialog"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content" />
+	            
+	            <CheckBox
+	                android:id="@+id/cb_dialog_prices_5"
+	                android:textColor="@color/text_dialog"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content" />
+
+	            <TextView
+	                android:id="@+id/tv_dialog_prices_total"
+	                android:textColor="@color/text_dialog"
+	                android:layout_width="fill_parent"
+	                android:layout_height="wrap_content"
+	                android:gravity="center_horizontal"
+	                android:text="@string/prices_total_0"
+	                android:textAppearance="?android:attr/textAppearanceMedium"
+	                android:textSize="18sp" />
+
+	        </LinearLayout>
+
+	        <TextView
+	            android:layout_width="fill_parent"
+	            android:layout_height="wrap_content"
+	            android:textColor="@color/text_dialog"
+	            android:layout_marginTop="35dp"
+	            android:background="@drawable/home_section_title"
+	            android:padding="3dp"
+	            android:text="@string/prices_section_howto"
+	            android:textAppearance="?android:attr/textAppearanceMedium"
+	            android:textSize="20sp" />
+
+	        <LinearLayout
+	            android:layout_width="match_parent"
+	            android:layout_height="wrap_content"
+	            android:layout_marginBottom="20dp"
+	            android:layout_marginEnd="10dp"
+	            android:layout_marginLeft="10dp"
+	            android:layout_marginRight="10dp"
+	            android:layout_marginStart="10dp"
+	            android:layout_marginTop="20dp"
+	            android:orientation="vertical" >
+
+	            <TextView
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:textColor="@color/text_dialog"
+	                android:text="@string/prices_howto_0" />
+	            
+	            <TextView
+	                android:layout_width="fill_parent"
+	                android:layout_height="wrap_content"
+	                android:layout_marginTop="15dp"
+	                android:gravity="center_horizontal"
+	                android:text="@string/prices_howto_1"
+	                android:textColor="@color/text_dialog"
+	                android:textStyle="italic" />
+	            
+	            <TextView
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_marginTop="15dp"
+	                android:textColor="@color/text_dialog"
+	                android:text="@string/prices_howto_2" />
+	            
+	            <TextView
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_marginTop="15dp"
+	                android:textColor="@color/text_dialog"
+	                android:text="@string/prices_howto_3" />
+
+	            <TextView
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_marginTop="15dp"
+	                android:text="@string/prices_howto_4"
+	                android:textColor="@color/text_dialog" />
+	            
+	            <TextView
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_marginTop="15dp"
+	                android:text="@string/prices_contact_text"
+	                android:textColor="@color/text_dialog" />
+
+	            <Button
+	                android:id="@+id/bt_dialog_prices_contact"
+	                android:layout_width="wrap_content"
+	                android:layout_height="wrap_content"
+	                android:layout_gravity="center_horizontal"
+	                android:layout_marginBottom="10dp"
+	                android:layout_marginTop="10dp"
+	                android:background="@drawable/arrowbutton"
+	                android:padding="5dp"
+	                android:text="@string/prices_contact_button" />
+
+	        </LinearLayout>
+	
+	    </LinearLayout>
+	
+	</ScrollView>
+
+</RelativeLayout>

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels