Page MenuHomeGitPull.it

D17.1779724709.diff
No OneTemporary

Authored By
Unknown
Size
224 KB
Referenced Files
None
Subscribers
None

D17.1779724709.diff

diff --git a/0001-Changed-repository.patch b/0001-Changed-repository.patch
new file mode 100644
--- /dev/null
+++ b/0001-Changed-repository.patch
@@ -0,0 +1,48 @@
+From 981fb167ec1cd255f2ec41cf58e9002fa90acbb5 Mon Sep 17 00:00:00 2001
+From: Andrea <andrea.ugo15@gmail.com>
+Date: Mon, 9 Mar 2020 15:01:21 +0100
+Subject: [PATCH] Changed repository
+
+---
+ build.gradle | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/build.gradle b/build.gradle
+index 874e06b..41dcd4f 100644
+--- a/build.gradle
++++ b/build.gradle
+@@ -1,9 +1,8 @@
+ buildscript {
+ repositories {
+- mavenCentral()
++ jcenter()
+ maven { url 'https://maven.google.com' }
+ google()
+- jcenter()
+
+ }
+
+@@ -16,10 +15,9 @@ buildscript {
+ }
+ allprojects {
+ repositories {
+- mavenCentral()
++ jcenter()
+ maven { url 'https://maven.google.com' }
+ google()
+- jcenter()
+
+ }
+ }
+@@ -66,7 +64,7 @@ android {
+ }
+
+ repositories {
+- mavenCentral()
++ jcenter()
+ mavenLocal()
+ }
+
+--
+2.25.1.windows.1
+
diff --git a/Changed-repository.diff b/Changed-repository.diff
new file mode 100644
--- /dev/null
+++ b/Changed-repository.diff
@@ -0,0 +1,36 @@
+diff --git a/build.gradle b/build.gradle
+index 874e06b..41dcd4f 100644
+--- a/build.gradle
++++ b/build.gradle
+@@ -1,9 +1,8 @@
+ buildscript {
+ repositories {
+- mavenCentral()
++ jcenter()
+ maven { url 'https://maven.google.com' }
+ google()
+- jcenter()
+
+ }
+
+@@ -16,10 +15,9 @@ buildscript {
+ }
+ allprojects {
+ repositories {
+- mavenCentral()
++ jcenter()
+ maven { url 'https://maven.google.com' }
+ google()
+- jcenter()
+
+ }
+ }
+@@ -66,7 +64,7 @@ android {
+ }
+
+ repositories {
+- mavenCentral()
++ jcenter()
+ mavenLocal()
+ }
+
diff --git a/Changed-repository.patch b/Changed-repository.patch
new file mode 100644
--- /dev/null
+++ b/Changed-repository.patch
@@ -0,0 +1,48 @@
+From 981fb167ec1cd255f2ec41cf58e9002fa90acbb5 Mon Sep 17 00:00:00 2001
+From: Andrea <andrea.ugo15@gmail.com>
+Date: Mon, 9 Mar 2020 15:01:21 +0100
+Subject: Changed repository
+
+---
+ build.gradle | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/build.gradle b/build.gradle
+index 874e06b..41dcd4f 100644
+--- a/build.gradle
++++ b/build.gradle
+@@ -1,9 +1,8 @@
+ buildscript {
+ repositories {
+- mavenCentral()
++ jcenter()
+ maven { url 'https://maven.google.com' }
+ google()
+- jcenter()
+
+ }
+
+@@ -16,10 +15,9 @@ buildscript {
+ }
+ allprojects {
+ repositories {
+- mavenCentral()
++ jcenter()
+ maven { url 'https://maven.google.com' }
+ google()
+- jcenter()
+
+ }
+ }
+@@ -66,7 +64,7 @@ android {
+ }
+
+ repositories {
+- mavenCentral()
++ jcenter()
+ mavenLocal()
+ }
+
+--
+2.25.1.windows.1
+
diff --git a/build.gradle b/build.gradle
--- a/build.gradle
+++ b/build.gradle
@@ -1,84 +1,85 @@
-buildscript {
- repositories {
- jcenter()
- maven { url 'https://maven.google.com' }
- google()
-
- }
-
- dependencies {
- classpath 'com.android.tools.build:gradle:3.1.0'
- }
- ext {
- support_ver = "25.4.0"
- }
-}
-allprojects {
- repositories {
- jcenter()
- maven { url 'https://maven.google.com' }
- google()
-
- }
-}
-
-apply plugin: 'com.android.application'
-
-android {
- compileSdkVersion 25
- buildToolsVersion '27.0.3'
-
- defaultConfig {
- applicationId "it.reyboz.bustorino"
- minSdkVersion 9
- targetSdkVersion 25
- versionCode 27
- versionName "1.11"
- }
-
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
-
- sourceSets {
- main {
- manifest.srcFile 'AndroidManifest.xml'
- java.srcDirs = ['src']
- resources.srcDirs = ['src']
- aidl.srcDirs = ['src']
- renderscript.srcDirs = ['src']
- res.srcDirs = ['res']
- assets.srcDirs = ['assets']
- }
- }
- buildTypes {
- debug {
- applicationIdSuffix ".debug"
- versionNameSuffix "-dev"
- }
- }
-
- lintOptions {
- abortOnError false
- }
-
- repositories {
- jcenter()
- mavenLocal()
- }
-
- dependencies {
- implementation "com.android.support:support-v4:$support_ver"
- implementation "com.android.support:appcompat-v7:$support_ver"
- implementation "com.android.support:design:$support_ver"
- implementation "com.android.support:recyclerview-v7:$support_ver"
- implementation "com.android.support:preference-v7:$support_ver"
- implementation "com.android.support:cardview-v7:$support_ver"
-
-
- implementation 'org.jsoup:jsoup:1.11.3'
- implementation 'com.readystatesoftware.sqliteasset:sqliteassethelper:2.0.1'
- implementation 'com.android.volley:volley:1.1.1'
- }
-}
+buildscript {
+ repositories {
+ jcenter()
+ maven { url 'https://maven.google.com' }
+ google()
+
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.1.0'
+ }
+ ext {
+ support_ver = "25.4.0"
+ }
+}
+allprojects {
+ repositories {
+ jcenter()
+ maven { url 'https://maven.google.com' }
+ google()
+
+ }
+}
+
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion '27.0.3'
+
+ defaultConfig {
+ applicationId "it.reyboz.bustorino"
+ minSdkVersion 9
+ targetSdkVersion 25
+ versionCode 27
+ versionName "1.11"
+ vectorDrawables.useSupportLibrary = true
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ java.srcDirs = ['src']
+ resources.srcDirs = ['src']
+ aidl.srcDirs = ['src']
+ renderscript.srcDirs = ['src']
+ res.srcDirs = ['res']
+ assets.srcDirs = ['assets']
+ }
+ }
+ buildTypes {
+ debug {
+ applicationIdSuffix ".debug"
+ versionNameSuffix "-dev"
+ }
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ repositories {
+ jcenter()
+ mavenLocal()
+ }
+
+ dependencies {
+ implementation "com.android.support:support-v4:$support_ver"
+ implementation "com.android.support:appcompat-v7:$support_ver"
+ implementation "com.android.support:design:$support_ver"
+ implementation "com.android.support:recyclerview-v7:$support_ver"
+ implementation "com.android.support:preference-v7:$support_ver"
+ implementation "com.android.support:cardview-v7:$support_ver"
+
+
+ implementation 'org.jsoup:jsoup:1.11.3'
+ implementation 'com.readystatesoftware.sqliteasset:sqliteassethelper:2.0.1'
+ implementation 'com.android.volley:volley:1.1.1'
+ }
+}
diff --git a/gradlew.bat b/gradlew.bat
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,84 +1,84 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/res/drawable-xxxhdpi/qrcode_button_custom.xml b/res/drawable-xxxhdpi/qrcode_button_custom.xml
--- a/res/drawable-xxxhdpi/qrcode_button_custom.xml
+++ b/res/drawable-xxxhdpi/qrcode_button_custom.xml
@@ -1,8 +1,8 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:drawable="@drawable/qrcode_button_pressed" android:state_pressed="true"/>
- <item android:drawable="@drawable/qrcode_button_pressed" android:state_focused="true"/>
- <item android:drawable="@drawable/qrcode_button_default"/>
-
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:drawable="@drawable/qrcode_button_pressed" android:state_pressed="true"/>
+ <item android:drawable="@drawable/qrcode_button_pressed" android:state_focused="true"/>
+ <item android:drawable="@drawable/qrcode_button_default"/>
+
</selector>
\ No newline at end of file
diff --git a/res/drawable/ic_star_filled.xml b/res/drawable/ic_star_filled.xml
new file mode 100644
--- /dev/null
+++ b/res/drawable/ic_star_filled.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@color/orange_500"
+ android:pathData="M12,17.27L18.18,21L16.54,13.97L22,9.24L14.81,8.62L12,2L9.19,8.62L2,9.24L7.45,13.97L5.82,21L12,17.27Z"/>
+</vector>
diff --git a/res/drawable/ic_star_outline.xml b/res/drawable/ic_star_outline.xml
new file mode 100644
--- /dev/null
+++ b/res/drawable/ic_star_outline.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@color/orange_500"
+ android:pathData="M12,15.39L8.24,17.66L9.23,13.38L5.91,10.5L10.29,10.13L12,6.09L13.71,10.13L18.09,10.5L14.77,13.38L15.76,17.66M22,9.24L14.81,8.63L12,2L9.19,8.63L2,9.24L7.45,13.97L5.82,21L12,17.27L18.18,21L16.54,13.97L22,9.24Z"/>
+</vector>
diff --git a/res/layout/fragment_list_view.xml b/res/layout/fragment_list_view.xml
--- a/res/layout/fragment_list_view.xml
+++ b/res/layout/fragment_list_view.xml
@@ -4,18 +4,36 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
>
+
<TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginEnd="16dp"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp"
- android:layout_marginStart="16dp"
- android:layout_marginTop="10dp"
- android:id="@+id/messageTextView" android:gravity="center_vertical"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:minHeight="48dp"
- android:layout_marginBottom="10dp" />
+ android:id="@+id/messageTextView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginTop="10dp"
+ android:layout_marginEnd="307dp"
+ android:layout_marginRight="10dp"
+ android:layout_marginBottom="10dp"
+ android:layout_toStartOf="@+id/addToFavorites"
+ android:layout_toLeftOf="@+id/addToFavorites"
+ android:gravity="center_vertical"
+ android:minHeight="48dp"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <ImageButton
+ android:id="@+id/addToFavorites"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_above="@+id/resultsListView"
+ android:layout_alignParentRight="true"
+ android:layout_marginLeft="16dp"
+ android:layout_marginTop="10dp"
+ android:layout_marginRight="16dp"
+ android:layout_marginBottom="16dp"
+ android:background="@android:color/transparent"
+ fab:srcCompat="@drawable/ic_star_outline" />
+
<ListView
android:layout_below="@id/messageTextView"
android:id="@+id/resultsListView"
diff --git a/res/layout/rename_dialog.xml b/res/layout/rename_dialog.xml
--- a/res/layout/rename_dialog.xml
+++ b/res/layout/rename_dialog.xml
@@ -1,15 +1,15 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <EditText
- android:id="@+id/rename_dialog_bus_stop_name"
- android:inputType="text"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginLeft="20dp"
- android:layout_marginRight="20dp"
- android:selectAllOnFocus="true"/>
-
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <EditText
+ android:id="@+id/rename_dialog_bus_stop_name"
+ android:inputType="text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="20dp"
+ android:layout_marginRight="20dp"
+ android:selectAllOnFocus="true"/>
+
</LinearLayout>
\ No newline at end of file
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -1,111 +1,111 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-
-
- <string name="app_description">Stai utilizzando l\'ultimo ritrovato in materia di rispetto della tua privacy.</string>
- <string name="search">Cerca</string>
- <string name="qrcode">QR Code</string>
- <string name="insert_bus_stop_number">Numero fermata</string>
- <string name="insert_bus_stop_name">Nome fermata</string>
- <string name="insert_bus_stop_number_error">Inserisci il numero della fermata</string>
- <string name="insert_bus_stop_name_error">Inserisci il nome della fermata</string>
- <string name="network_error">Verifica l\'accesso ad Internet!</string>
- <string name="no_bus_stop_have_this_name">Sembra che nessuna fermata abbia questo nome</string>
- <string name="parsing_error">Errore di lettura del sito 5T/GTT (dannato sito!)</string>
- <string name="passages">Fermata: %1$s</string>
- <string name="lines">Linee: %1$s</string>
- <string name="results">Scegli la fermata…</string>
- <string name="no_passages">Nessun passaggio</string>
- <string name="no_qrcode">Nessun QR code</string>
- <string name="action_favorites">Preferiti</string>
- <string name="action_help">Aiuto</string>
- <string name="action_about">Informazioni</string>
- <string name="action_about_more">Più informazioni</string>
- <string name="action_news">News</string>
- <string name="action_bugs">Invia bug</string>
- <string name="action_source">Codice sorgente</string>
- <string name="action_licence">Licenza</string>
- <string name="action_author">Incontra l\'autore</string>
- <string name="added_in_favorites">Fermata aggiunta ai preferiti</string>
- <string name="cant_add_to_favorites">Impossibile aggiungere ai preferiti (memoria piena o database corrotto?)!</string>
- <string name="title_activity_favorites">Preferiti</string>
- <string name="tip_add_favorite">Tocca il nome di una fermata per aggiungerla in questa lista</string>
- <string name="action_remove_from_favourites">Rimuovi</string>
- <string name="action_rename_bus_stop_username">Rinomina</string>
- <string name="dialog_rename_bus_stop_username_title">Rinomina fermata</string>
- <string name="dialog_rename_bus_stop_username_reset_button">Reset</string>
- <string name="about">Informazioni</string>
- <string name="howDoesItWork"><b>Tocca il nome della fermata</b> per aggiungerla ai preferiti\n\n<b>Come leggere gli orari:</b>\n<b>&#160;&#160;&#160;12:56*</b> Orario in tempo reale\n<b>&#160;&#160;&#160;12:56</b> &#160; Orario programmato\n\n<b>Trascina giù per aggiornare</b> l\'orario.</string>
- <string name="hint_button">OK !</string>
- <string name="about_history">
-<![CDATA[
- <h1>Benvenuto!</h1>
-
- <p>Grazie per aver scelto BusTO, un\'app <b>indipendente</b> da GTT/5T, per spostarsi a Torino attraverso <b>software libero</b>:</p>
-
- <p>Perché usare BusTO?</p>
- <p>
- - Non sei <b>monitorato</b><br>
- - Non ci sono <b>pubblicità</b><br>
- - La tua <b>privacy</b> è al sicuro<br>
- - Inoltre l\'app è molto leggera!<br>
- </p>
-
- <h2>Come Funziona?</h2>
- <p>Quest\'app ottiene i passaggi dei bus in tempo reale filtrando i dati forniti pubblicamente sul sito <b>www.gtt.to.it</b> o <i>www.5t.torino.it</i> "per uso personale".</p>
-
- <p>Ingredienti:<br>
- - <b>Fabio Mazza</b> attuale rockstar developer.<br>
- - <b>Ludovico Pavesi</b> ex rockstar developer.<br>
- - <b>Valerio Bozzolan</b> attuale manutentore.<br>
- - <b>Marco Gagino</b> apprezzato ex collaboratore, ideatore icona e grafica.<br>
- - <b>JSoup</b> libreria per "<i>web scaping</i>".<br>
- - <b>Google</b> icone e libreria di supporto per il Material Design.<br>
- - Tutti i contributori!
- </p>
-
- <h2>Licenze</h2>
- <p>L\'app e il relativo codice sorgente sono distribuiti sotto la licenza <i>GNU General Public License v3+</i>.
- Ciò <b>significa</b> che puoi usare, studiare, migliorare e ricondividere quest\'app con <b>qualunque mezzo</b> e per <b>qualsiasi scopo</b>: a patto di mantenere sempre questi diritti a tua volta e di dare credito a Valerio Bozzolan.
- </p>
-
- <h2>Note</h2>
- <p>Quest\'applicazione è rilasciata <b>nella speranza che sia utile a tutti</b> ma senza NESSUNA garanzia.</p>
- <p>Buon utilizzo! :)</p>
- ]]>
- </string>
- <string name="query_too_short">Nome troppo corto, digita più caratteri e riprova</string>
- <string name="route_towards_destination">%1$s verso %2$s</string>
- <string name="route_towards_unknown">%s (destinazione sconosciuta)</string>
- <string name="internal_error">Errore interno inaspettato, impossibile estrarre dati dal sito GTT/5T</string>
- <string name="action_view_on_map">Visualizza sulla mappa</string>
- <string name="cannot_show_on_map_no_activity">Non trovo un\'applicazione dove mostrarla</string>
- <string name="cannot_show_on_map_no_position">Posizione della fermata non trovata</string>
-
-
- <string name="nearby_stops_message">Fermate vicine</string>
- <string name="position_searching_message">Ricerca della posizione in corso&#8230;</string>
- <string name="no_stops_nearby">Nessuna fermata nei dintorni</string>
- <string name="main_menu_pref">Preferenze</string>
- <string name="database_update_message">Aggiornamento del database&#8230;</string>
- <string name="pref_num_elements">Numero di fermate</string>
- <string name="title_activity_settings">Impostazioni</string>
- <string name="action_settings">Impostazioni</string>
- <string name="pref_recents_group_title">Fermate recenti</string>
- <string name="settings_group_general">Impostazioni generali</string>
- <string name="settings_group_database">Gestione del database</string>
- <string name="settings_reset_database">Comincia aggiornamento manuale del database</string>
-
-
- <string name="enableGpsText">Abilitare il GPS</string>
- <string name="settings_search_radius">Raggio di ricerca</string>
- <string name="settings_experimental">Funzionalità sperimentali</string>
- <string name="bus_arriving_at">arriva alle</string>
- <string name="arrivals_card_at_the_stop">alla fermata</string>
- <string name="show_arrivals">Mostra arrivi</string>
- <string name="show_stops">Mostra fermate</string>
- <string name="nearby_arrivals_message">Arrivi qui vicino</string>
- <string name="removed_from_favorites">Fermata rimossa dai preferiti</string>
-
-
-</resources>
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+
+ <string name="app_description">Stai utilizzando l\'ultimo ritrovato in materia di rispetto della tua privacy.</string>
+ <string name="search">Cerca</string>
+ <string name="qrcode">QR Code</string>
+ <string name="insert_bus_stop_number">Numero fermata</string>
+ <string name="insert_bus_stop_name">Nome fermata</string>
+ <string name="insert_bus_stop_number_error">Inserisci il numero della fermata</string>
+ <string name="insert_bus_stop_name_error">Inserisci il nome della fermata</string>
+ <string name="network_error">Verifica l\'accesso ad Internet!</string>
+ <string name="no_bus_stop_have_this_name">Sembra che nessuna fermata abbia questo nome</string>
+ <string name="parsing_error">Errore di lettura del sito 5T/GTT (dannato sito!)</string>
+ <string name="passages">Fermata: %1$s</string>
+ <string name="lines">Linee: %1$s</string>
+ <string name="results">Scegli la fermata…</string>
+ <string name="no_passages">Nessun passaggio</string>
+ <string name="no_qrcode">Nessun QR code</string>
+ <string name="action_favorites">Preferiti</string>
+ <string name="action_help">Aiuto</string>
+ <string name="action_about">Informazioni</string>
+ <string name="action_about_more">Più informazioni</string>
+ <string name="action_news">News</string>
+ <string name="action_bugs">Invia bug</string>
+ <string name="action_source">Codice sorgente</string>
+ <string name="action_licence">Licenza</string>
+ <string name="action_author">Incontra l\'autore</string>
+ <string name="added_in_favorites">Fermata aggiunta ai preferiti</string>
+ <string name="cant_add_to_favorites">Impossibile aggiungere ai preferiti (memoria piena o database corrotto?)!</string>
+ <string name="title_activity_favorites">Preferiti</string>
+ <string name="tip_add_favorite">Tocca il nome di una fermata per aggiungerla in questa lista</string>
+ <string name="action_remove_from_favourites">Rimuovi</string>
+ <string name="action_rename_bus_stop_username">Rinomina</string>
+ <string name="dialog_rename_bus_stop_username_title">Rinomina fermata</string>
+ <string name="dialog_rename_bus_stop_username_reset_button">Reset</string>
+ <string name="about">Informazioni</string>
+ <string name="howDoesItWork"><b>Tocca il nome della fermata</b> per aggiungerla ai preferiti\n\n<b>Come leggere gli orari:</b>\n<b>&#160;&#160;&#160;12:56*</b> Orario in tempo reale\n<b>&#160;&#160;&#160;12:56</b> &#160; Orario programmato\n\n<b>Trascina giù per aggiornare</b> l\'orario.</string>
+ <string name="hint_button">OK !</string>
+ <string name="about_history">
+<![CDATA[
+ <h1>Benvenuto!</h1>
+
+ <p>Grazie per aver scelto BusTO, un\'app <b>indipendente</b> da GTT/5T, per spostarsi a Torino attraverso <b>software libero</b>:</p>
+
+ <p>Perché usare BusTO?</p>
+ <p>
+ - Non sei <b>monitorato</b><br>
+ - Non ci sono <b>pubblicità</b><br>
+ - La tua <b>privacy</b> è al sicuro<br>
+ - Inoltre l\'app è molto leggera!<br>
+ </p>
+
+ <h2>Come Funziona?</h2>
+ <p>Quest\'app ottiene i passaggi dei bus in tempo reale filtrando i dati forniti pubblicamente sul sito <b>www.gtt.to.it</b> o <i>www.5t.torino.it</i> "per uso personale".</p>
+
+ <p>Ingredienti:<br>
+ - <b>Fabio Mazza</b> attuale rockstar developer.<br>
+ - <b>Ludovico Pavesi</b> ex rockstar developer.<br>
+ - <b>Valerio Bozzolan</b> attuale manutentore.<br>
+ - <b>Marco Gagino</b> apprezzato ex collaboratore, ideatore icona e grafica.<br>
+ - <b>JSoup</b> libreria per "<i>web scaping</i>".<br>
+ - <b>Google</b> icone e libreria di supporto per il Material Design.<br>
+ - Tutti i contributori!
+ </p>
+
+ <h2>Licenze</h2>
+ <p>L\'app e il relativo codice sorgente sono distribuiti sotto la licenza <i>GNU General Public License v3+</i>.
+ Ciò <b>significa</b> che puoi usare, studiare, migliorare e ricondividere quest\'app con <b>qualunque mezzo</b> e per <b>qualsiasi scopo</b>: a patto di mantenere sempre questi diritti a tua volta e di dare credito a Valerio Bozzolan.
+ </p>
+
+ <h2>Note</h2>
+ <p>Quest\'applicazione è rilasciata <b>nella speranza che sia utile a tutti</b> ma senza NESSUNA garanzia.</p>
+ <p>Buon utilizzo! :)</p>
+ ]]>
+ </string>
+ <string name="query_too_short">Nome troppo corto, digita più caratteri e riprova</string>
+ <string name="route_towards_destination">%1$s verso %2$s</string>
+ <string name="route_towards_unknown">%s (destinazione sconosciuta)</string>
+ <string name="internal_error">Errore interno inaspettato, impossibile estrarre dati dal sito GTT/5T</string>
+ <string name="action_view_on_map">Visualizza sulla mappa</string>
+ <string name="cannot_show_on_map_no_activity">Non trovo un\'applicazione dove mostrarla</string>
+ <string name="cannot_show_on_map_no_position">Posizione della fermata non trovata</string>
+
+
+ <string name="nearby_stops_message">Fermate vicine</string>
+ <string name="position_searching_message">Ricerca della posizione in corso&#8230;</string>
+ <string name="no_stops_nearby">Nessuna fermata nei dintorni</string>
+ <string name="main_menu_pref">Preferenze</string>
+ <string name="database_update_message">Aggiornamento del database&#8230;</string>
+ <string name="pref_num_elements">Numero di fermate</string>
+ <string name="title_activity_settings">Impostazioni</string>
+ <string name="action_settings">Impostazioni</string>
+ <string name="pref_recents_group_title">Fermate recenti</string>
+ <string name="settings_group_general">Impostazioni generali</string>
+ <string name="settings_group_database">Gestione del database</string>
+ <string name="settings_reset_database">Comincia aggiornamento manuale del database</string>
+
+
+ <string name="enableGpsText">Abilitare il GPS</string>
+ <string name="settings_search_radius">Raggio di ricerca</string>
+ <string name="settings_experimental">Funzionalità sperimentali</string>
+ <string name="bus_arriving_at">arriva alle</string>
+ <string name="arrivals_card_at_the_stop">alla fermata</string>
+ <string name="show_arrivals">Mostra arrivi</string>
+ <string name="show_stops">Mostra fermate</string>
+ <string name="nearby_arrivals_message">Arrivi qui vicino</string>
+ <string name="removed_from_favorites">Fermata rimossa dai preferiti</string>
+
+
+</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1,120 +1,120 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-
- <string name="app_name" translatable="false">BusTO</string>
- <string name="app_description">You\'re using the latest in technology when it comes to respecting your privacy.
- </string>
- <string name="search">Search</string>
- <string name="qrcode">Scan QR Code</string>
- <string name="insert_bus_stop_number">Bus stop number</string>
- <string name="insert_bus_stop_name">Bus stop name</string>
- <string name="insert_bus_stop_number_error">Insert bus stop number</string>
- <string name="insert_bus_stop_name_error">Insert bus stop name</string>
- <string name="route_towards_destination">%1$s towards %2$s</string>
- <string name="route_towards_unknown">%s (unknown destination)</string>
- <string name="network_error">Verify your Internet connection!</string>
- <string name="no_bus_stop_have_this_name">Seems that no bus stop have this name</string>
- <string name="parsing_error">Error parsing the 5T/GTT website (damn site!)</string>
- <string name="query_too_short">Name too short, type more characters and retry
- </string> <!-- TODO: carry out experiments to determine the best wording for this message and publish a paper with the findings -->
- <string name="passages">Arrivals at: %1$s</string>
- <string name="results">Choose the bus stop…</string>
- <string name="lines">Lines: %1$s</string>
- <string name="no_passages">No timetable found</string>
- <string name="no_qrcode">No QR code</string>
- <string name="internal_error">Unexpected internal error, cannot extract data from GTT/5T website</string>
- <string name="action_help">Help</string>
- <string name="action_about">About</string>
- <string name="action_about_more">More about</string>
- <string name="action_news">News releases</string>
- <string name="action_bugs">Bug submission</string>
- <string name="action_source">Source code</string>
- <string name="action_licence">Licence</string>
- <string name="action_author">Meet the author</string>
- <string name="added_in_favorites">Bus stop is now in your favorites</string>
- <string name="removed_from_favorites">Bus stop removed from your favorites</string>
- <string name="action_favorites">Favorites</string>
- <string name="title_activity_favorites">Favorites</string>
- <string name="tip_add_favorite">Press on a bus stop name to populate this list</string>
- <string name="action_remove_from_favourites">Delete</string>
- <string name="action_rename_bus_stop_username">Rename</string>
- <string name="dialog_rename_bus_stop_username_title">Rename the bus stop</string>
- <string name="dialog_rename_bus_stop_username_reset_button">Reset</string>
- <string name="about">About</string>
- <string name="howDoesItWork">
- <b>Tap the bus stop name</b>
- to add it to the favourites\n\n<b>How to read timelines:</b>\n<b>&#160;&#160;&#160;12:56*</b> Real-time
- arrivals\n<b>&#160;&#160;&#160;12:56</b> &#160; Scheduled arrivals\n\n<b>Pull down to refresh</b> the timetable
- </string>
- <string name="hint_button">GOT IT!</string>
- <string name="about_history">
- <![CDATA[
- <h1>Welcome!</h1>
-
- <p>Thanks for using BusTO, a "politically" <b>independent</b> app useful to move around Torino using a <b>Free/Libre software</b>.</p>
-
- <p>Why use this app?</p>
- <p>
- - You\'ll never be <b>tracked</b><br>
- - You\'ll never see boring <b>ads</b><br>
- - We\'ll always respect your <b>privacy</b><br>
- - Moreover, it\'s lightweight!<br>
- </p>
-
- <h2>How does it work?</h2>
- <p>This app will show you bus timetables gathering data from <b>www.gtt.to.it</b> or <b>www.5t.torino.it</b> "for personal use".</p>
-
- <p>Who worked on BusTO:<br>
- - <b>Fabio Mazza</b> current rockstar developer.<br>
- - <b>Ludovico Pavesi</b> previous rockstar developer.<br>
- - <b>Valerio Bozzolan</b> maintainer.<br>
- - <b>Marco Gagino</b> ex contributor and icon creator.<br>
- - <b>JSoup</b> web scraper library.<br>
- - <b>makovkastar</b> floating buttons.<br>
- - <b>Google</b> Material Design icons.<br>
- - All the contributors!
- </p>
-
- <h2>Licenses</h2>
- <p>The app and the related source code are released by Valerio Bozzolan under the terms of the <i>GNU General Public License v3+</i>).
- So everyone is allowed to use, to study, to improve and to share this app by <b>any kind of means</b> and for <b>any purpose</b>: under the conditions of maintaining this rights and of attributing the original work to Valerio Bozzolan.</p>
-
- <h2>Notes</h2>
- <p>This app has been developed <b>hoping to be useful to everyone</b> but without ANY warranty.</p>
- <p>This translation is kindly provided by Riccardo Caniato and Marco Gagino.</p>
- <p>Get involved! :)</p>
- ]]>
- </string>
- <string name="cant_add_to_favorites">Cannot add to favorites (storage full or corrupted database?)!</string>
- <string name="action_view_on_map">View on a map</string>
- <string name="cannot_show_on_map_no_activity">Cannot find any application to show it in</string>
- <string name="cannot_show_on_map_no_position">Cannot find the position of the stop</string>
-
- <string name="list_fragment_debug" translatable="false">ListFragment - BusTO</string>
- <string name="mainSharedPreferences" translatable="false">it.reyboz.bustorino.preferences</string>
- <string name="databaseUpdatingPref" translatable="false">db_is_updating</string>
-
- <string name="nearby_stops_message">Nearby stops</string>
- <string name="nearby_arrivals_message">Nearby connections</string>
-
- <string name="position_searching_message">Finding the position&#8230;</string>
- <string name="no_stops_nearby">No stops nearby</string>
- <string name="pref_num_elements">Number of stops</string>
- <string name="main_menu_pref">Preferences</string>
- <string name="title_activity_settings">Settings</string>
- <string name="action_settings">Settings</string>
- <string name="settings_experimental">Experimental features</string>
- <string name="settings_search_radius">Search radius</string>
- <string name="pref_recents_group_title">Recent stops</string>
- <string name="settings_group_general">General settings</string>
- <string name="settings_group_database">Database management</string>
- <string name="settings_reset_database">Launch manual database update</string>
-
- <string name="enableGpsText">Please enable GPS</string>
- <string name="database_update_message">Database update in progress&#8230;</string>
- <string name="bus_arriving_at">is arriving at</string>
- <string name="arrivals_card_at_the_stop">at the stop</string>
- <string name="two_strings_format" translatable="false">%1$s - %2$s</string>
- <string name="show_arrivals">Show arrivals</string>
- <string name="show_stops">Show stops</string>
-</resources>
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="app_name" translatable="false">BusTO</string>
+ <string name="app_description">You\'re using the latest in technology when it comes to respecting your privacy.
+ </string>
+ <string name="search">Search</string>
+ <string name="qrcode">Scan QR Code</string>
+ <string name="insert_bus_stop_number">Bus stop number</string>
+ <string name="insert_bus_stop_name">Bus stop name</string>
+ <string name="insert_bus_stop_number_error">Insert bus stop number</string>
+ <string name="insert_bus_stop_name_error">Insert bus stop name</string>
+ <string name="route_towards_destination">%1$s towards %2$s</string>
+ <string name="route_towards_unknown">%s (unknown destination)</string>
+ <string name="network_error">Verify your Internet connection!</string>
+ <string name="no_bus_stop_have_this_name">Seems that no bus stop have this name</string>
+ <string name="parsing_error">Error parsing the 5T/GTT website (damn site!)</string>
+ <string name="query_too_short">Name too short, type more characters and retry
+ </string> <!-- TODO: carry out experiments to determine the best wording for this message and publish a paper with the findings -->
+ <string name="passages">Arrivals at: %1$s</string>
+ <string name="results">Choose the bus stop…</string>
+ <string name="lines">Lines: %1$s</string>
+ <string name="no_passages">No timetable found</string>
+ <string name="no_qrcode">No QR code</string>
+ <string name="internal_error">Unexpected internal error, cannot extract data from GTT/5T website</string>
+ <string name="action_help">Help</string>
+ <string name="action_about">About</string>
+ <string name="action_about_more">More about</string>
+ <string name="action_news">News releases</string>
+ <string name="action_bugs">Bug submission</string>
+ <string name="action_source">Source code</string>
+ <string name="action_licence">Licence</string>
+ <string name="action_author">Meet the author</string>
+ <string name="added_in_favorites">Bus stop is now in your favorites</string>
+ <string name="removed_from_favorites">Bus stop removed from your favorites</string>
+ <string name="action_favorites">Favorites</string>
+ <string name="title_activity_favorites">Favorites</string>
+ <string name="tip_add_favorite">Press on a bus stop name to populate this list</string>
+ <string name="action_remove_from_favourites">Delete</string>
+ <string name="action_rename_bus_stop_username">Rename</string>
+ <string name="dialog_rename_bus_stop_username_title">Rename the bus stop</string>
+ <string name="dialog_rename_bus_stop_username_reset_button">Reset</string>
+ <string name="about">About</string>
+ <string name="howDoesItWork">
+ <b>Tap the bus stop name</b>
+ to add it to the favourites\n\n<b>How to read timelines:</b>\n<b>&#160;&#160;&#160;12:56*</b> Real-time
+ arrivals\n<b>&#160;&#160;&#160;12:56</b> &#160; Scheduled arrivals\n\n<b>Pull down to refresh</b> the timetable
+ </string>
+ <string name="hint_button">GOT IT!</string>
+ <string name="about_history">
+ <![CDATA[
+ <h1>Welcome!</h1>
+
+ <p>Thanks for using BusTO, a "politically" <b>independent</b> app useful to move around Torino using a <b>Free/Libre software</b>.</p>
+
+ <p>Why use this app?</p>
+ <p>
+ - You\'ll never be <b>tracked</b><br>
+ - You\'ll never see boring <b>ads</b><br>
+ - We\'ll always respect your <b>privacy</b><br>
+ - Moreover, it\'s lightweight!<br>
+ </p>
+
+ <h2>How does it work?</h2>
+ <p>This app will show you bus timetables gathering data from <b>www.gtt.to.it</b> or <b>www.5t.torino.it</b> "for personal use".</p>
+
+ <p>Who worked on BusTO:<br>
+ - <b>Fabio Mazza</b> current rockstar developer.<br>
+ - <b>Ludovico Pavesi</b> previous rockstar developer.<br>
+ - <b>Valerio Bozzolan</b> maintainer.<br>
+ - <b>Marco Gagino</b> ex contributor and icon creator.<br>
+ - <b>JSoup</b> web scraper library.<br>
+ - <b>makovkastar</b> floating buttons.<br>
+ - <b>Google</b> Material Design icons.<br>
+ - All the contributors!
+ </p>
+
+ <h2>Licenses</h2>
+ <p>The app and the related source code are released by Valerio Bozzolan under the terms of the <i>GNU General Public License v3+</i>).
+ So everyone is allowed to use, to study, to improve and to share this app by <b>any kind of means</b> and for <b>any purpose</b>: under the conditions of maintaining this rights and of attributing the original work to Valerio Bozzolan.</p>
+
+ <h2>Notes</h2>
+ <p>This app has been developed <b>hoping to be useful to everyone</b> but without ANY warranty.</p>
+ <p>This translation is kindly provided by Riccardo Caniato and Marco Gagino.</p>
+ <p>Get involved! :)</p>
+ ]]>
+ </string>
+ <string name="cant_add_to_favorites">Cannot add to favorites (storage full or corrupted database?)!</string>
+ <string name="action_view_on_map">View on a map</string>
+ <string name="cannot_show_on_map_no_activity">Cannot find any application to show it in</string>
+ <string name="cannot_show_on_map_no_position">Cannot find the position of the stop</string>
+
+ <string name="list_fragment_debug" translatable="false">ListFragment - BusTO</string>
+ <string name="mainSharedPreferences" translatable="false">it.reyboz.bustorino.preferences</string>
+ <string name="databaseUpdatingPref" translatable="false">db_is_updating</string>
+
+ <string name="nearby_stops_message">Nearby stops</string>
+ <string name="nearby_arrivals_message">Nearby connections</string>
+
+ <string name="position_searching_message">Finding the position&#8230;</string>
+ <string name="no_stops_nearby">No stops nearby</string>
+ <string name="pref_num_elements">Number of stops</string>
+ <string name="main_menu_pref">Preferences</string>
+ <string name="title_activity_settings">Settings</string>
+ <string name="action_settings">Settings</string>
+ <string name="settings_experimental">Experimental features</string>
+ <string name="settings_search_radius">Search radius</string>
+ <string name="pref_recents_group_title">Recent stops</string>
+ <string name="settings_group_general">General settings</string>
+ <string name="settings_group_database">Database management</string>
+ <string name="settings_reset_database">Launch manual database update</string>
+
+ <string name="enableGpsText">Please enable GPS</string>
+ <string name="database_update_message">Database update in progress&#8230;</string>
+ <string name="bus_arriving_at">is arriving at</string>
+ <string name="arrivals_card_at_the_stop">at the stop</string>
+ <string name="two_strings_format" translatable="false">%1$s - %2$s</string>
+ <string name="show_arrivals">Show arrivals</string>
+ <string name="show_stops">Show stops</string>
+</resources>
diff --git a/src/it/reyboz/bustorino/ActivityFavorites.java b/src/it/reyboz/bustorino/ActivityFavorites.java
--- a/src/it/reyboz/bustorino/ActivityFavorites.java
+++ b/src/it/reyboz/bustorino/ActivityFavorites.java
@@ -1,302 +1,302 @@
-/*
- BusTO - Arrival times for Turin public transports.
- Copyright (C) 2014 Valerio Bozzolan
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package it.reyboz.bustorino;
-
-import android.database.Cursor;
-import android.support.v4.app.LoaderManager;
-import android.support.v4.content.Loader;
-import android.widget.*;
-import it.reyboz.bustorino.backend.Stop;
-import it.reyboz.bustorino.adapters.StopAdapter;
-import it.reyboz.bustorino.middleware.AsyncStopFavoriteAction;
-import it.reyboz.bustorino.middleware.StopsDB;
-import it.reyboz.bustorino.middleware.UserDB;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.support.v4.app.NavUtils;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.content.Intent;
-import android.database.sqlite.SQLiteDatabase;
-import android.os.Bundle;
-
-import java.util.List;
-
-public class ActivityFavorites extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
- private ListView favoriteListView;
- private SQLiteDatabase userDB;
- private EditText bus_stop_name;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_favorites);
-
- // this should be done in onStarted and closed in onStop, but apparently onStarted is never run.
- this.userDB = new UserDB(getApplicationContext()).getWritableDatabase();
-
- ActionBar ab = getSupportActionBar();
- assert ab != null;
- ab.setIcon(R.drawable.ic_launcher);
- ab.setDisplayHomeAsUpEnabled(true); // Back button
-
- favoriteListView = (ListView) findViewById(R.id.favoriteListView);
-
- createFavoriteList();
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, v, menuInfo);
- if (v.getId() == R.id.favoriteListView) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.menu_favourites_entry, menu);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- // Respond to the action bar's Up/Home button
- case android.R.id.home:
- NavUtils.navigateUpFromSameTask(this);
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
- .getMenuInfo();
-
- Stop busStop = (Stop) favoriteListView.getItemAtPosition(info.position);
-
- switch (item.getItemId()) {
- case R.id.action_favourite_entry_delete:
-
- // remove the stop from the favorites in background
- new AsyncStopFavoriteAction(getApplicationContext(), AsyncStopFavoriteAction.Action.REMOVE) {
-
- /**
- * Callback fired when everything was done
- *
- * @param result
- */
- @Override
- protected void onPostExecute(Boolean result) {
- super.onPostExecute(result);
-
- // update the favorite list
- createFavoriteList();
- }
- }.execute(busStop);
-
- return true;
- case R.id.action_rename_bus_stop_username:
- showBusStopUsernameInputDialog(busStop);
- return true;
- case R.id.action_view_on_map:
- final String theGeoUrl = busStop.getGeoURL();
- if(theGeoUrl==null){
- //doesn't have a position
- Toast.makeText(getApplicationContext(),R.string.cannot_show_on_map_no_position,Toast.LENGTH_SHORT).show();
- return true;
- }
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(theGeoUrl));
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- if(intent.resolveActivity(getPackageManager())!=null)
- startActivity(intent);
- else {
- Toast.makeText(getApplicationContext(),R.string.cannot_show_on_map_no_activity,Toast.LENGTH_SHORT).show();
- }
- return true;
- default:
- return super.onContextItemSelected(item);
- }
- }
-
- void createFavoriteList() {
- // TODO: memoize default list, query only user names every time?
- new AsyncGetFavorites(getApplicationContext(), this.userDB).execute();
- }
-
- public void showBusStopUsernameInputDialog(final Stop busStop) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
-
- LayoutInflater inflater = this.getLayoutInflater();
- View renameDialogLayout = inflater.inflate(R.layout.rename_dialog, null);
-
- bus_stop_name = (EditText) renameDialogLayout.findViewById(R.id.rename_dialog_bus_stop_name);
- bus_stop_name.setText(busStop.getStopDisplayName());
- bus_stop_name.setHint(busStop.getStopDefaultName());
-
- builder.setTitle(getString(R.string.dialog_rename_bus_stop_username_title));
- builder.setView(renameDialogLayout);
- builder.setPositiveButton(getString(android.R.string.ok), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- String busStopUsername = bus_stop_name.getText().toString();
- String oldUserName = busStop.getStopUserName();
-
- // changed to none
- if(busStopUsername.length() == 0) {
- // unless it was already empty, set new
- if(oldUserName != null) {
- busStop.setStopUserName(null);
- UserDB.updateStop(busStop, userDB);
- createFavoriteList();
- }
- } else { // changed to something
- // something different?
- if(oldUserName == null || !busStopUsername.equals(oldUserName)) {
- busStop.setStopUserName(busStopUsername);
- UserDB.updateStop(busStop, userDB);
- createFavoriteList();
- }
- }
- }
- });
- builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.cancel();
- }
- });
- builder.setNeutralButton(R.string.dialog_rename_bus_stop_username_reset_button, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // delete user name from database
- busStop.setStopUserName(null);
- UserDB.updateStop(busStop, userDB);
-
- createFavoriteList();
- }
- });
- builder.show();
- }
-
- /**
- * This one runs. onStart instead gets ignored for no reason whatsoever.
- *
- * @see <a href="https://i.stack.imgur.com/SAX9I.png">Android Activity Lifecycle</a>
- */
- @Override
- protected void onStop() {
- super.onStop();
- this.userDB.close();
- }
-
- @Override
- public Loader<Cursor> onCreateLoader(int id, Bundle args) {
- return null;
- }
-
- @Override
- public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
-
- }
-
- @Override
- public void onLoaderReset(Loader<Cursor> loader) {
-
- }
-
- private class AsyncGetFavorites extends AsyncTask<Void, Void, List<Stop>> {
- private Context c;
- private SQLiteDatabase userDB;
-
- AsyncGetFavorites(Context c, SQLiteDatabase userDB) {
- this.c = c;
- this.userDB = userDB;
- }
-
- @Override
- protected List<Stop> doInBackground(Void... voids) {
- StopsDB stopsDB = new StopsDB(c);
- stopsDB.openIfNeeded();
- List<Stop> busStops = UserDB.getFavorites(this.userDB, stopsDB);
- stopsDB.closeIfNeeded();
-
- return busStops;
- }
-
- @Override
- protected void onPostExecute(List<Stop> busStops) {
- // If no data is found show a friendly message
- if (busStops.size() == 0) {
- favoriteListView.setVisibility(View.INVISIBLE);
- TextView favoriteTipTextView = (TextView) findViewById(R.id.favoriteTipTextView);
- assert favoriteTipTextView != null;
- favoriteTipTextView.setVisibility(View.VISIBLE);
- }
-
- /* There's a nice method called notifyDataSetChanged() to avoid building the ListView
- * all over again. This method exists in a billion answers on Stack Overflow, but
- * it's nowhere to be seen around here, Android Studio can't find it no matter what.
- * Anyway, it only works from Android 2.3 onward (which is why it refuses to appear, I
- * guess) and requires to modify the list with .add() and .clear() and some other
- * methods, so to update a single stop we need to completely rebuild the list for no
- * reason. It would probably end up as "slow" as throwing away the old ListView and
- * redrwaing everything.
- */
-
- // Show results
- favoriteListView.setAdapter(new StopAdapter(this.c, busStops));
- favoriteListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- /**
- * Casting because of Javamerda
- * @url http://stackoverflow.com/questions/30549485/androids-list-view-parameterized-type-in-adapterview-onitemclicklistener
- */
- Stop busStop = (Stop) parent.getItemAtPosition(position);
-
- Intent intent = new Intent(ActivityFavorites.this,
- ActivityMain.class);
-
- Bundle b = new Bundle();
- // TODO: is passing a serialized object a good idea? Or rather, is it reasonably fast?
- //b.putSerializable("bus-stop-serialized", busStop);
- b.putString("bus-stop-ID", busStop.ID);
- b.putString("bus-stop-display-name", busStop.getStopDisplayName());
- intent.putExtras(b);
- //intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
- // Intent.FLAG_ACTIVITY_CLEAR_TASK isn't supported in API < 11 and we're targeting API 7...
- intent.setFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
-
- startActivity(intent);
-
- finish();
- }
- });
- registerForContextMenu(favoriteListView);
- }
- }
-}
+/*
+ BusTO - Arrival times for Turin public transports.
+ Copyright (C) 2014 Valerio Bozzolan
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package it.reyboz.bustorino;
+
+import android.database.Cursor;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.Loader;
+import android.widget.*;
+import it.reyboz.bustorino.backend.Stop;
+import it.reyboz.bustorino.adapters.StopAdapter;
+import it.reyboz.bustorino.middleware.AsyncStopFavoriteAction;
+import it.reyboz.bustorino.middleware.StopsDB;
+import it.reyboz.bustorino.middleware.UserDB;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.support.v4.app.NavUtils;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.content.Intent;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.Bundle;
+
+import java.util.List;
+
+public class ActivityFavorites extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
+ private ListView favoriteListView;
+ private SQLiteDatabase userDB;
+ private EditText bus_stop_name;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_favorites);
+
+ // this should be done in onStarted and closed in onStop, but apparently onStarted is never run.
+ this.userDB = new UserDB(getApplicationContext()).getWritableDatabase();
+
+ ActionBar ab = getSupportActionBar();
+ assert ab != null;
+ ab.setIcon(R.drawable.ic_launcher);
+ ab.setDisplayHomeAsUpEnabled(true); // Back button
+
+ favoriteListView = (ListView) findViewById(R.id.favoriteListView);
+
+ createFavoriteList();
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v,
+ ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ if (v.getId() == R.id.favoriteListView) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.menu_favourites_entry, menu);
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ // Respond to the action bar's Up/Home button
+ case android.R.id.home:
+ NavUtils.navigateUpFromSameTask(this);
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
+ .getMenuInfo();
+
+ Stop busStop = (Stop) favoriteListView.getItemAtPosition(info.position);
+
+ switch (item.getItemId()) {
+ case R.id.action_favourite_entry_delete:
+
+ // remove the stop from the favorites in background
+ new AsyncStopFavoriteAction(getApplicationContext(), AsyncStopFavoriteAction.Action.REMOVE) {
+
+ /**
+ * Callback fired when everything was done
+ *
+ * @param result
+ */
+ @Override
+ protected void onPostExecute(Boolean result) {
+ super.onPostExecute(result);
+
+ // update the favorite list
+ createFavoriteList();
+ }
+ }.execute(busStop);
+
+ return true;
+ case R.id.action_rename_bus_stop_username:
+ showBusStopUsernameInputDialog(busStop);
+ return true;
+ case R.id.action_view_on_map:
+ final String theGeoUrl = busStop.getGeoURL();
+ if(theGeoUrl==null){
+ //doesn't have a position
+ Toast.makeText(getApplicationContext(),R.string.cannot_show_on_map_no_position,Toast.LENGTH_SHORT).show();
+ return true;
+ }
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(theGeoUrl));
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ if(intent.resolveActivity(getPackageManager())!=null)
+ startActivity(intent);
+ else {
+ Toast.makeText(getApplicationContext(),R.string.cannot_show_on_map_no_activity,Toast.LENGTH_SHORT).show();
+ }
+ return true;
+ default:
+ return super.onContextItemSelected(item);
+ }
+ }
+
+ void createFavoriteList() {
+ // TODO: memoize default list, query only user names every time?
+ new AsyncGetFavorites(getApplicationContext(), this.userDB).execute();
+ }
+
+ public void showBusStopUsernameInputDialog(final Stop busStop) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+
+ LayoutInflater inflater = this.getLayoutInflater();
+ View renameDialogLayout = inflater.inflate(R.layout.rename_dialog, null);
+
+ bus_stop_name = (EditText) renameDialogLayout.findViewById(R.id.rename_dialog_bus_stop_name);
+ bus_stop_name.setText(busStop.getStopDisplayName());
+ bus_stop_name.setHint(busStop.getStopDefaultName());
+
+ builder.setTitle(getString(R.string.dialog_rename_bus_stop_username_title));
+ builder.setView(renameDialogLayout);
+ builder.setPositiveButton(getString(android.R.string.ok), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String busStopUsername = bus_stop_name.getText().toString();
+ String oldUserName = busStop.getStopUserName();
+
+ // changed to none
+ if(busStopUsername.length() == 0) {
+ // unless it was already empty, set new
+ if(oldUserName != null) {
+ busStop.setStopUserName(null);
+ UserDB.updateStop(busStop, userDB);
+ createFavoriteList();
+ }
+ } else { // changed to something
+ // something different?
+ if(oldUserName == null || !busStopUsername.equals(oldUserName)) {
+ busStop.setStopUserName(busStopUsername);
+ UserDB.updateStop(busStop, userDB);
+ createFavoriteList();
+ }
+ }
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ });
+ builder.setNeutralButton(R.string.dialog_rename_bus_stop_username_reset_button, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // delete user name from database
+ busStop.setStopUserName(null);
+ UserDB.updateStop(busStop, userDB);
+
+ createFavoriteList();
+ }
+ });
+ builder.show();
+ }
+
+ /**
+ * This one runs. onStart instead gets ignored for no reason whatsoever.
+ *
+ * @see <a href="https://i.stack.imgur.com/SAX9I.png">Android Activity Lifecycle</a>
+ */
+ @Override
+ protected void onStop() {
+ super.onStop();
+ this.userDB.close();
+ }
+
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ return null;
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+
+ }
+
+ private class AsyncGetFavorites extends AsyncTask<Void, Void, List<Stop>> {
+ private Context c;
+ private SQLiteDatabase userDB;
+
+ AsyncGetFavorites(Context c, SQLiteDatabase userDB) {
+ this.c = c;
+ this.userDB = userDB;
+ }
+
+ @Override
+ protected List<Stop> doInBackground(Void... voids) {
+ StopsDB stopsDB = new StopsDB(c);
+ stopsDB.openIfNeeded();
+ List<Stop> busStops = UserDB.getFavorites(this.userDB, stopsDB);
+ stopsDB.closeIfNeeded();
+
+ return busStops;
+ }
+
+ @Override
+ protected void onPostExecute(List<Stop> busStops) {
+ // If no data is found show a friendly message
+ if (busStops.size() == 0) {
+ favoriteListView.setVisibility(View.INVISIBLE);
+ TextView favoriteTipTextView = (TextView) findViewById(R.id.favoriteTipTextView);
+ assert favoriteTipTextView != null;
+ favoriteTipTextView.setVisibility(View.VISIBLE);
+ }
+
+ /* There's a nice method called notifyDataSetChanged() to avoid building the ListView
+ * all over again. This method exists in a billion answers on Stack Overflow, but
+ * it's nowhere to be seen around here, Android Studio can't find it no matter what.
+ * Anyway, it only works from Android 2.3 onward (which is why it refuses to appear, I
+ * guess) and requires to modify the list with .add() and .clear() and some other
+ * methods, so to update a single stop we need to completely rebuild the list for no
+ * reason. It would probably end up as "slow" as throwing away the old ListView and
+ * redrwaing everything.
+ */
+
+ // Show results
+ favoriteListView.setAdapter(new StopAdapter(this.c, busStops));
+ favoriteListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ /**
+ * Casting because of Javamerda
+ * @url http://stackoverflow.com/questions/30549485/androids-list-view-parameterized-type-in-adapterview-onitemclicklistener
+ */
+ Stop busStop = (Stop) parent.getItemAtPosition(position);
+
+ Intent intent = new Intent(ActivityFavorites.this,
+ ActivityMain.class);
+
+ Bundle b = new Bundle();
+ // TODO: is passing a serialized object a good idea? Or rather, is it reasonably fast?
+ //b.putSerializable("bus-stop-serialized", busStop);
+ b.putString("bus-stop-ID", busStop.ID);
+ b.putString("bus-stop-display-name", busStop.getStopDisplayName());
+ intent.putExtras(b);
+ //intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+ // Intent.FLAG_ACTIVITY_CLEAR_TASK isn't supported in API < 11 and we're targeting API 7...
+ intent.setFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
+
+ startActivity(intent);
+
+ finish();
+ }
+ });
+ registerForContextMenu(favoriteListView);
+ }
+ }
+}
diff --git a/src/it/reyboz/bustorino/ActivityMain.java b/src/it/reyboz/bustorino/ActivityMain.java
--- a/src/it/reyboz/bustorino/ActivityMain.java
+++ b/src/it/reyboz/bustorino/ActivityMain.java
@@ -1,877 +1,903 @@
-/*
- BusTO - Arrival times for Turin public transports.
- Copyright (C) 2014 Valerio Bozzolan
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package it.reyboz.bustorino;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.database.sqlite.SQLiteDatabase;
-import android.location.*;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.annotation.NonNull;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.app.NavUtils;
-import android.support.v4.widget.SwipeRefreshLayout;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.*;
-
-import com.google.zxing.integration.android.IntentIntegrator;
-import com.google.zxing.integration.android.IntentResult;
-import android.support.design.widget.FloatingActionButton;
-
-import it.reyboz.bustorino.backend.*;
-import it.reyboz.bustorino.fragments.*;
-import it.reyboz.bustorino.middleware.*;
-
-import java.util.List;
-
-public class ActivityMain extends GeneralActivity implements FragmentListener {
-
- /*
- * Layout elements
- */
- private EditText busStopSearchByIDEditText;
- private EditText busStopSearchByNameEditText;
- private ProgressBar progressBar;
- private TextView howDoesItWorkTextView;
- private Button hideHintButton;
- private MenuItem actionHelpMenuItem;
- private SwipeRefreshLayout swipeRefreshLayout;
- private FloatingActionButton floatingActionButton;
- private FragmentManager framan;
- private Snackbar snackbar;
-
- /*
- * Search mode
- */
- private static final int SEARCH_BY_NAME = 0;
- private static final int SEARCH_BY_ID = 1;
- private static final int SEARCH_BY_ROUTE = 2; // TODO: implement this -- https://gitpull.it/T12
- private int searchMode;
-
- /*
- * Options
- */
- private final String OPTION_SHOW_LEGEND = "show_legend";
- private final String LOCATION_PERMISSION_GIVEN = "loc_permission";
- /*
- * Status
- */
- private DBStatusManager prefsManager;
- private DBStatusManager.OnDBUpdateStatusChangeListener updatelistener;
- private static final String DEBUG_TAG="BusTO - MainActivity";
- /* // useful for testing:
- public class MockFetcher implements ArrivalsFetcher {
- @Override
- public Palina ReadArrivalTimesAll(String routeID, AtomicReference<result> res) {
- SystemClock.sleep(5000);
- res.set(result.SERVER_ERROR);
- return new Palina();
- }
- }
- private ArrivalsFetcher[] ArrivalFetchers = {new MockFetcher(), new MockFetcher(), new MockFetcher(), new MockFetcher(), new MockFetcher()};*/
-
- private RecursionHelper<ArrivalsFetcher> ArrivalFetchersRecursionHelper = new RecursionHelper<>(new ArrivalsFetcher[] {new GTTJSONFetcher(), new FiveTScraperFetcher()});
- private RecursionHelper<StopsFinderByName> StopsFindersByNameRecursionHelper = new RecursionHelper<>(new StopsFinderByName[] {new GTTStopsFetcher(), new FiveTStopsFetcher()});
- /*
- * Position
- */
- //Fine location criteria
- private final Criteria cr = new Criteria();
- private boolean pendingNearbyStopsRequest = false;
- private LocationManager locmgr;
- /*
- * Database Access
- */
- private StopsDB stopsDB;
- private UserDB userDB;
- private FragmentHelper fh;
-
- ///////////////////////////////// EVENT HANDLERS ///////////////////////////////////////////////
-
- /*
- * @see swipeRefreshLayout
- */
- private Handler handler = new Handler();
- private final Runnable refreshing = new Runnable() {
- public void run() {
- if(framan.findFragmentById(R.id.resultFrame) instanceof ArrivalsFragment){
- ArrivalsFragment fragment = (ArrivalsFragment) framan.findFragmentById(R.id.resultFrame);
- String stopName = fragment.getStopID();
- new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS,fh).execute(stopName);
- } else
- new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS,fh).execute();
- }
- };
-
- //// MAIN METHOD ///
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- framan = getSupportFragmentManager();
- this.stopsDB = new StopsDB(getApplicationContext());
- this.userDB = new UserDB(getApplicationContext());
- setContentView(R.layout.activity_main);
- busStopSearchByIDEditText = (EditText) findViewById(R.id.busStopSearchByIDEditText);
- busStopSearchByNameEditText = (EditText) findViewById(R.id.busStopSearchByNameEditText);
- progressBar = (ProgressBar) findViewById(R.id.progressBar);
- howDoesItWorkTextView = (TextView) findViewById(R.id.howDoesItWorkTextView);
- hideHintButton = (Button) findViewById(R.id.hideHintButton);
- swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.listRefreshLayout);
- floatingActionButton = (FloatingActionButton) findViewById(R.id.floatingActionButton);
-
- framan.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
- @Override
- public void onBackStackChanged() {
- Log.d("MainActivity, BusTO", "BACK STACK CHANGED");
- }
- });
-
- busStopSearchByIDEditText.setSelectAllOnFocus(true);
- busStopSearchByIDEditText
- .setOnEditorActionListener(new TextView.OnEditorActionListener() {
- @Override
- public boolean onEditorAction(TextView v, int actionId,
- KeyEvent event) {
- // IME_ACTION_SEARCH alphabetical option
- if (actionId == EditorInfo.IME_ACTION_SEARCH) {
- onSearchClick(v);
- return true;
- }
- return false;
- }
- });
- busStopSearchByNameEditText
- .setOnEditorActionListener(new TextView.OnEditorActionListener() {
- @Override
- public boolean onEditorAction(TextView v, int actionId,
- KeyEvent event) {
- // IME_ACTION_SEARCH alphabetical option
- if (actionId == EditorInfo.IME_ACTION_SEARCH) {
- onSearchClick(v);
- return true;
- }
- return false;
- }
- });
-
- // Called when the layout is pulled down
- swipeRefreshLayout
- .setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
- @Override
- public void onRefresh() {
- handler.post(refreshing);
- }
- });
-
- /**
- * @author Marco Gagino!!!
- */
- //swipeRefreshLayout.setColorSchemeColors(R.color.blue_500, R.color.orange_500); // setColorScheme is deprecated, setColorSchemeColors isn't
- swipeRefreshLayout.setColorSchemeResources(R.color.blue_500,R.color.orange_500);
- fh = new FragmentHelper(this,R.id.listRefreshLayout,R.id.resultFrame);
- setSearchModeBusStopID();
-
- //---------------------------- START INTENT CHECK QUEUE ------------------------------------
-
- // Intercept calls from URL intent
- boolean tryedFromIntent = false;
-
- String busStopID = null;
- String busStopDisplayName = null;
- Uri data = getIntent().getData();
- if (data != null) {
- busStopID = getBusStopIDFromUri(data);
- tryedFromIntent = true;
- }
-
- // Intercept calls from other activities
- if (!tryedFromIntent) {
- Bundle b = getIntent().getExtras();
- if (b != null) {
- busStopID = b.getString("bus-stop-ID");
- busStopDisplayName = b.getString("bus-stop-display-name");
-
- /**
- * I'm not very sure if you are coming from an Intent.
- * Some launchers work in strange ways.
- */
- tryedFromIntent = busStopID != null;
- }
- }
-
- //---------------------------- END INTENT CHECK QUEUE --------------------------------------
-
- if (busStopID == null) {
- // Show keyboard if can't start from intent
- // JUST DON'T
- // showKeyboard();
-
- // You haven't obtained anything... from an intent?
- if (tryedFromIntent) {
-
- // This shows a luser warning
- ArrivalFetchersRecursionHelper.reset();
- Toast.makeText(getApplicationContext(),
- R.string.insert_bus_stop_number_error, Toast.LENGTH_SHORT).show();
- }
- } else {
- // If you are here an intent has worked successfully
- setBusStopSearchByIDEditText(busStopID);
- /*
- //THIS PART SHOULDN'T BE NECESSARY SINCE THE LAST SUCCESSFULLY SEARCHED BUS
- // STOP IS ADDED AUTOMATICALLY
- Stop nextStop = new Stop(busStopID);
- // forcing it as user name even though it could be standard name, it doesn't really matter
- nextStop.setStopUserName(busStopDisplayName);
- //set stop as last succe
- fh.setLastSuccessfullySearchedBusStop(nextStop);
- */
- createFragmentForStop(busStopID);
- }
- //Try (hopefully) database update
- //TODO: Start the service in foreground, check last time it ran before
- DatabaseUpdateService.startDBUpdate(getApplicationContext());
- /*
- Set database update
- */
- updatelistener = new DBStatusManager.OnDBUpdateStatusChangeListener(){
- @Override
- public boolean defaultStatusValue() {
- return true;
- }
-
- @Override
- public void onDBStatusChanged(boolean updating) {
-
- if(updating){
- createDefaultSnackbar();
- }
- else if(snackbar!=null){
- snackbar.dismiss();
- snackbar = null;
- }
-
-
- }
- };
- prefsManager = new DBStatusManager(getApplicationContext(),updatelistener);
- prefsManager.registerListener();
-
- //locationHandler = new GPSLocationAdapter(getApplicationContext());
- //--------- NEARBY STOPS--------//
- //SETUP LOCATION
- locmgr = (LocationManager) getSystemService(LOCATION_SERVICE);
- cr.setAccuracy(Criteria.ACCURACY_FINE);
- cr.setAltitudeRequired(false);
- cr.setBearingRequired(false);
- cr.setCostAllowed(true);
- cr.setPowerRequirement(Criteria.NO_REQUIREMENT);
- //We want the nearby bus stops!
- handler.post(new NearbyStopsRequester());
- //If there are no providers available, then, wait for them
-
-
- Log.d("MainActivity", "Created");
-
- }
-
- /**
- * Reload bus stop timetable when it's fulled resumed from background.
- */
- /**
- @Override
- protected void onPostResume() {
- super.onPostResume();
- Log.d("ActivityMain", "onPostResume fired. Last successfully bus stop ID: " + fh.getLastSuccessfullySearchedBusStop());
- if (searchMode == SEARCH_BY_ID && fh.getLastSuccessfullySearchedBusStop() != null) {
- setBusStopSearchByIDEditText(fh.getLastSuccessfullySearchedBusStop().ID);
- //new asyncWgetBusStopFromBusStopID(lastSuccessfullySearchedBusStop.ID, ArrivalFetchersRecursionHelper, lastSuccessfullySearchedBusStop);
- new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS,fh).execute();
- } else {
- //we have new activity or we don't have a new searched stop.
- //Let's search stops nearby
- LocationManager locManager = (LocationManager) getSystemService(LOCATION_SERVICE);
- Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.resultFrame);
-
-
- }
- //show the FAB since it remains hidden
- floatingActionButton.show();
-
- }
- **/
-
-
- @Override
- protected void onPause() {
- super.onPause();
- fh.stopLastRequestIfNeeded();
- fh.setBlockAllActivities(true);
- if(updatelistener!=null && prefsManager!=null) prefsManager.unregisterListener();
- locmgr.removeUpdates(locListener);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- fh.setBlockAllActivities(false);
- if(updatelistener!=null && prefsManager!=null) {
- prefsManager.registerListener();
- if(prefsManager.isDBUpdating(true)){
- createDefaultSnackbar();
- }
- }
- if(pendingNearbyStopsRequest)
- handler.post(new NearbyStopsRequester());
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.main, menu);
-
- actionHelpMenuItem = menu.findItem(R.id.action_help);
- return true;
- }
-
- /**
- * Callback fired when a MenuItem is selected
- *
- * @param item
- * @return
- */
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button, so long
- // as you specify a parent activity in AndroidManifest.xml.
- switch (item.getItemId()) {
- case android.R.id.home:
- // Respond to the action bar's Up/Home button
- NavUtils.navigateUpFromSameTask(this);
- return true;
- case R.id.action_help:
- showHints();
- return true;
- case R.id.action_favorites:
- startActivity(new Intent(ActivityMain.this, ActivityFavorites.class));
- return true;
- case R.id.action_about:
- startActivity(new Intent(ActivityMain.this, ActivityAbout.class));
- return true;
- case R.id.action_news:
- openIceweasel("https://gitpull.it/w/librebusto/#how-to-get-news");
- return true;
- case R.id.action_bugs:
- openIceweasel("https://gitpull.it/w/librebusto/#how-to-create-a-bug-feature");
- return true;
- case R.id.action_source:
- openIceweasel("https://gitpull.it/w/librebusto/#how-to-hack-busto");
- return true;
- case R.id.action_licence:
- openIceweasel("https://www.gnu.org/licenses/gpl-3.0.html");
- return true;
- case R.id.action_settings:
- Log.d("MAINBusTO","Pressed button preferences");
- startActivity(new Intent(ActivityMain.this,ActivitySettings.class));
- }
- return super.onOptionsItemSelected(item);
- }
-
- /**
- * OK this is pure shit
- *
- * @param v View clicked
- */
- public void onSearchClick(View v) {
- if (searchMode == SEARCH_BY_ID) {
- String busStopID = busStopSearchByIDEditText.getText().toString();
- //OLD ASYNCTASK
- //new asyncWgetBusStopFromBusStopID(busStopID, ArrivalFetchersRecursionHelper, lastSuccessfullySearchedBusStop);
-
- if(busStopID == null || busStopID.length() <= 0) {
- showMessage(R.string.insert_bus_stop_number_error);
- toggleSpinner(false);
- } else{
- new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS,fh).execute(busStopID);
- Log.d("MainActiv","Started search for arrivals of stop "+busStopID);
- }
- } else { // searchMode == SEARCH_BY_NAME
- String query = busStopSearchByNameEditText.getText().toString();
- //new asyncWgetBusStopSuggestions(query, stopsDB, StopsFindersByNameRecursionHelper);
- new AsyncDataDownload(AsyncDataDownload.RequestType.STOPS,fh).execute(query);
- }
- }
- /** PERMISSION STUFF **/
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- switch (requestCode){
- case PERMISSION_REQUEST_POSITION:
- if(grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
- setOption(LOCATION_PERMISSION_GIVEN,true);
- //if we sent a request for a new NearbyStopsFragment
- if(pendingNearbyStopsRequest){
- pendingNearbyStopsRequest=false;
- handler.post(new NearbyStopsRequester());
- }
-
- } else {
- //permission denied
- setOption(LOCATION_PERMISSION_GIVEN,false);
- }
- //add other cases for permissions
- }
-
- }
-
-
- @Override
- public void createFragmentForStop(String ID) {
- //new asyncWgetBusStopFromBusStopID(ID, ArrivalFetchersRecursionHelper,lastSuccessfullySearchedBusStop);
- if(ID == null || ID.length() <= 0) {
- // we're still in UI thread, no need to mess with Progress
- showMessage(R.string.insert_bus_stop_number_error);
- toggleSpinner(false);
- } else {
- new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS,fh).execute(ID);
- Log.d("MainActiv","Started search for arrivals of stop "+ID);
- }
- }
-
-
-
- /**
- * QR scan button clicked
- *
- * @param v View QRButton clicked
- */
- public void onQRButtonClick(View v) {
- IntentIntegrator integrator = new IntentIntegrator(this);
- integrator.initiateScan();
- }
-
- /**
- * Receive the Barcode Scanner Intent
- *
- */
- public void onActivityResult(int requestCode, int resultCode, Intent intent) {
- IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
-
- Uri uri;
- try {
- uri = Uri.parse(scanResult != null ? scanResult.getContents() : null); // this apparently prevents NullPointerException. Somehow.
- } catch (NullPointerException e) {
- Toast.makeText(getApplicationContext(),
- R.string.no_qrcode, Toast.LENGTH_SHORT).show();
- return;
- }
-
- String busStopID = getBusStopIDFromUri(uri);
- busStopSearchByIDEditText.setText(busStopID);
- createFragmentForStop(busStopID);
- }
-
- public void onHideHint(View v) {
- hideHints();
- setOption(OPTION_SHOW_LEGEND, false);
- }
-
- public void onToggleKeyboardLayout(View v) {
- if (searchMode == SEARCH_BY_NAME) {
- setSearchModeBusStopID();
- if (busStopSearchByIDEditText.requestFocus()) {
- showKeyboard();
- }
- } else { // searchMode == SEARCH_BY_ID
- setSearchModeBusStopName();
- if (busStopSearchByNameEditText.requestFocus()) {
- showKeyboard();
- }
- }
- }
- private void createDefaultSnackbar(){
- if(snackbar==null){
- snackbar = Snackbar.make(findViewById(R.id.searchButton),R.string.database_update_message,Snackbar.LENGTH_INDEFINITE);
- }
- snackbar.show();
- }
- ///////////////////////////////// POSITION STUFF//////////////////////////////////////////////
-
- private void resolveStopRequest(String provider){
- Log.d(DEBUG_TAG,"Provider "+provider+" got enabled");
- if(locmgr!=null && pendingNearbyStopsRequest && locmgr.getProvider(provider).meetsCriteria(cr)){
- pendingNearbyStopsRequest = false;
- handler.post(new NearbyStopsRequester());
- }
- }
- final LocationListener locListener = new LocationListener() {
- @Override
- public void onLocationChanged(Location location) {
- Log.d(DEBUG_TAG,"Location changed");
- }
-
- @Override
- public void onStatusChanged(String provider, int status, Bundle extras) {
- Log.d(DEBUG_TAG,"Location provider status: "+status);
- if(status== LocationProvider.AVAILABLE){
- resolveStopRequest(provider);
- }
- }
-
- @Override
- public void onProviderEnabled(String provider) {
- resolveStopRequest(provider);
- }
-
- @Override
- public void onProviderDisabled(String provider) {
-
- }
- };
-
- class NearbyStopsRequester implements Runnable{
- @SuppressLint("MissingPermission")
- @Override
- public void run() {
- final boolean canRunPosition = Build.VERSION.SDK_INT < Build.VERSION_CODES.M || getOption(LOCATION_PERMISSION_GIVEN, false);
-
- if(!canRunPosition){
- pendingNearbyStopsRequest = true;
- assertLocationPermissions();
- return;
- } else setOption(LOCATION_PERMISSION_GIVEN,true);
-
- LocationManager locManager = (LocationManager) getSystemService(LOCATION_SERVICE);
- if(locManager == null) {
- Log.e(DEBUG_TAG, "location manager is nihil, cannot create NearbyStopsFragment");
- return;
- }
- if(anyLocationProviderMatchesCriteria(locManager,cr,true) && fh.getLastSuccessfullySearchedBusStop()==null) {
- //Go ahead with the request
- Log.d("mainActivity","Recreating stop fragment");
- swipeRefreshLayout.setVisibility(View.VISIBLE);
- NearbyStopsFragment fragment = NearbyStopsFragment.newInstance(NearbyStopsFragment.TYPE_STOPS);
- Fragment oldFrag = framan.findFragmentById(R.id.resultFrame);
- FragmentTransaction ft = framan.beginTransaction();
- if(oldFrag!=null)
- ft.remove(oldFrag);
- ft.add(R.id.resultFrame,fragment,"nearbyStop_correct");
- ft.commit();
- framan.executePendingTransactions();
- pendingNearbyStopsRequest = false;
- } else if(!anyLocationProviderMatchesCriteria(locManager,cr,true)){
- //Wait for the providers
- Log.d(DEBUG_TAG,"Queuing position request");
- pendingNearbyStopsRequest = true;
- locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,10,0.1f,locListener);
- }
-
- }
- }
-
- private boolean anyLocationProviderMatchesCriteria(LocationManager mng, Criteria cr, boolean enabled){
- List<String> providers = mng.getProviders(cr,enabled);
- Log.d(DEBUG_TAG,"Getting enabled location providers: ");
- for(String s: providers){
- Log.d(DEBUG_TAG,"Provider "+s);
- }
- return providers.size()>0;
- }
-
-
-
- ///////////////////////////////// OTHER STUFF //////////////////////////////////////////////////
-
- /**
- * Get the last successfully searched bus stop or NULL
- *
- * @return
- */
- @Override
- public Stop getLastSuccessfullySearchedBusStop() {
- return fh.getLastSuccessfullySearchedBusStop();
- }
-
- /**
- * Get the last successfully searched bus stop ID or NULL
- *
- * @return
- */
- @Override
- public String getLastSuccessfullySearchedBusStopID() {
- Stop stop = getLastSuccessfullySearchedBusStop();
- return stop == null ? null : stop.ID;
- }
-
- /**
- * Update the star "Add to favorite" icon
- */
- @Override
- public void updateStarIconFromLastBusStop() {
- // check if there is a last Stop
- String stopID = getLastSuccessfullySearchedBusStopID();
- if(stopID == null) {
- // TODO: hide the star
- } else {
- // filled or outline?
- if(isStopInFavorites(stopID)) {
- // TODO: fill star
- } else {
- // TODO: outline star
- }
-
- // TODO: show the star
- }
- }
-
- /**
- * Check if the last Bus Stop is in the favorites
- *
- * @return
- */
- public boolean isStopInFavorites(String busStopId) {
- boolean found = false;
-
- // no stop no party
- if(busStopId != null) {
- SQLiteDatabase userDB = new UserDB(getApplicationContext()).getReadableDatabase();
- found = UserDB.isStopInFavorites(userDB, busStopId);
- }
-
- return found;
- }
-
- /**
- * Add the last Stop to favorites
- */
- @Override
- public void toggleLastStopToFavorites() {
- Stop stop = getLastSuccessfullySearchedBusStop();
- if(stop != null) {
-
- // toggle the status in background
- new AsyncStopFavoriteAction(getApplicationContext(), AsyncStopFavoriteAction.Action.TOGGLE) {
-
- /**
- * Callback fired when the Stop is saved in the favorites
- * @param result
- */
- @Override
- protected void onPostExecute(Boolean result) {
- super.onPostExecute(result);
-
- // update the star icon
- updateStarIconFromLastBusStop();
- }
-
- }.execute(stop);
- } else {
- // this case have no sense, but just immediately update the favorite icon
- updateStarIconFromLastBusStop();
- }
- }
-
- @Override
- public void showFloatingActionButton(boolean yes) {
- if(yes) floatingActionButton.show();
- else floatingActionButton.hide();
- }
-
- @Override
- public void enableRefreshLayout(boolean yes) {
- swipeRefreshLayout.setEnabled(yes);
- }
-
- ////////////////////////////////////// GUI HELPERS /////////////////////////////////////////////
- @Override
- public void showKeyboard() {
- InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
- View view = searchMode == SEARCH_BY_ID ? busStopSearchByIDEditText : busStopSearchByNameEditText;
- imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
- }
-
- @Override
- public void showMessage(int messageID) {
- Toast.makeText(getApplicationContext(), messageID, Toast.LENGTH_SHORT).show();
- }
-
- private void setSearchModeBusStopID() {
- searchMode = SEARCH_BY_ID;
- busStopSearchByNameEditText.setVisibility(View.GONE);
- busStopSearchByNameEditText.setText("");
- busStopSearchByIDEditText.setVisibility(View.VISIBLE);
- floatingActionButton.setImageResource(R.drawable.alphabetical);
- }
-
- private void setSearchModeBusStopName() {
- searchMode = SEARCH_BY_NAME;
- busStopSearchByIDEditText.setVisibility(View.GONE);
- busStopSearchByIDEditText.setText("");
- busStopSearchByNameEditText.setVisibility(View.VISIBLE);
- floatingActionButton.setImageResource(R.drawable.numeric);
- }
-
- /**
- * Having that cursor at the left of the edit text makes me cancer.
- * @param busStopID bus stop ID
- */
- private void setBusStopSearchByIDEditText(String busStopID) {
- busStopSearchByIDEditText.setText(busStopID);
- busStopSearchByIDEditText.setSelection(busStopID.length());
- }
-
- private void showHints() {
- howDoesItWorkTextView.setVisibility(View.VISIBLE);
- hideHintButton.setVisibility(View.VISIBLE);
- actionHelpMenuItem.setVisible(false);
- }
-
- private void hideHints() {
- howDoesItWorkTextView.setVisibility(View.GONE);
- hideHintButton.setVisibility(View.GONE);
- actionHelpMenuItem.setVisible(true);
- }
-
- //TODO: toggle spinner from mainActivity
- @Override
- public void toggleSpinner(boolean enable) {
- if (enable) {
- //already set by the RefreshListener when needed
- //swipeRefreshLayout.setRefreshing(true);
- progressBar.setVisibility(View.VISIBLE);
- } else {
- swipeRefreshLayout.setRefreshing(false);
- progressBar.setVisibility(View.GONE);
- }
- }
-
- private void prepareGUIForBusLines() {
- swipeRefreshLayout.setEnabled(true);
- swipeRefreshLayout.setVisibility(View.VISIBLE);
- actionHelpMenuItem.setVisible(true);
- }
-
- private void prepareGUIForBusStops() {
- swipeRefreshLayout.setEnabled(false);
- swipeRefreshLayout.setVisibility(View.VISIBLE);
- actionHelpMenuItem.setVisible(false);
- }
-
-
- /**
- * This provides a temporary fix to make the transition
- * to a single asynctask go smoother
- * @param fragmentType the type of fragment created
- */
- @Override
- public void readyGUIfor(FragmentKind fragmentType) {
- hideKeyboard();
- //if we are getting results, already, stop waiting for nearbyStops
- if(pendingNearbyStopsRequest && (fragmentType==FragmentKind.ARRIVALS || fragmentType==FragmentKind.STOPS)) {
- locmgr.removeUpdates(locListener);
- pendingNearbyStopsRequest = false;
- }
- if(fragmentType==null) Log.e("ActivityMain","Problem with fragmentType");
- else
- switch (fragmentType){
- case ARRIVALS:
- prepareGUIForBusLines();
- if (getOption(OPTION_SHOW_LEGEND, true)) {
- showHints();
- }
- break;
- case STOPS:
- prepareGUIForBusStops();
- break;
- default:
- Log.e("BusTO Activity","Called readyGUI with unsupported type of Fragment");
- return;
- }
- // Shows hints
-
- }
-
- /**
- * Open an URL in the default browser.
- *
- * @param url URL
- */
- public void openIceweasel(String url) {
- Intent browserIntent1 = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- startActivity(browserIntent1);
- }
-
- ///////////////////// INTENT HELPER ////////////////////////////////////////////////////////////
-
- /**
- * Try to extract the bus stop ID from a URi
- *
- * @param uri The URL
- * @return bus stop ID or null
- */
- public static String getBusStopIDFromUri(Uri uri) {
- String busStopID;
-
- // everithing catches fire when passing null to a switch.
- String host = uri.getHost();
- if(host == null) {
- Log.e("ActivityMain", "Not an URL: " + uri);
- return null;
- }
-
- switch(host) {
- case "m.gtt.to.it":
- // http://m.gtt.to.it/m/it/arrivi.jsp?n=1254
- busStopID = uri.getQueryParameter("n");
- if (busStopID == null) {
- Log.e("ActivityMain", "Expected ?n from: " + uri);
- }
- break;
- case "www.gtt.to.it":
- case "gtt.to.it":
- // http://www.gtt.to.it/cms/percorari/arrivi?palina=1254
- busStopID = uri.getQueryParameter("palina");
- if (busStopID == null) {
- Log.e("ActivityMain", "Expected ?palina from: " + uri);
- }
- break;
- default:
- Log.e("ActivityMain", "Unexpected intent URL: " + uri);
- busStopID = null;
- }
- return busStopID;
- }
-
-
-
+/*
+ BusTO - Arrival times for Turin public transports.
+ Copyright (C) 2014 Valerio Bozzolan
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package it.reyboz.bustorino;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.database.sqlite.SQLiteDatabase;
+import android.location.*;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.annotation.NonNull;
+import android.support.design.widget.Snackbar;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.app.NavUtils;
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.*;
+
+import com.google.zxing.integration.android.IntentIntegrator;
+import com.google.zxing.integration.android.IntentResult;
+import android.support.design.widget.FloatingActionButton;
+
+import it.reyboz.bustorino.backend.*;
+import it.reyboz.bustorino.fragments.*;
+import it.reyboz.bustorino.middleware.*;
+
+import java.util.List;
+
+public class ActivityMain extends GeneralActivity implements FragmentListener {
+
+ /*
+ * Layout elements
+ */
+ private EditText busStopSearchByIDEditText;
+ private EditText busStopSearchByNameEditText;
+ private ProgressBar progressBar;
+ private TextView howDoesItWorkTextView;
+ private Button hideHintButton;
+ private MenuItem actionHelpMenuItem;
+ private SwipeRefreshLayout swipeRefreshLayout;
+ private FloatingActionButton floatingActionButton;
+ private FragmentManager framan;
+ private Snackbar snackbar;
+
+ /*
+ * Search mode
+ */
+ private static final int SEARCH_BY_NAME = 0;
+ private static final int SEARCH_BY_ID = 1;
+ private static final int SEARCH_BY_ROUTE = 2; // TODO: implement this -- https://gitpull.it/T12
+ private int searchMode;
+ private ImageButton addToFavorites;
+
+ /*
+ * Options
+ */
+ private final String OPTION_SHOW_LEGEND = "show_legend";
+ private final String LOCATION_PERMISSION_GIVEN = "loc_permission";
+ /*
+ * Status
+ */
+ private DBStatusManager prefsManager;
+ private DBStatusManager.OnDBUpdateStatusChangeListener updatelistener;
+ private static final String DEBUG_TAG="BusTO - MainActivity";
+ /* // useful for testing:
+ public class MockFetcher implements ArrivalsFetcher {
+ @Override
+ public Palina ReadArrivalTimesAll(String routeID, AtomicReference<result> res) {
+ SystemClock.sleep(5000);
+ res.set(result.SERVER_ERROR);
+ return new Palina();
+ }
+ }
+ private ArrivalsFetcher[] ArrivalFetchers = {new MockFetcher(), new MockFetcher(), new MockFetcher(), new MockFetcher(), new MockFetcher()};*/
+
+ private RecursionHelper<ArrivalsFetcher> ArrivalFetchersRecursionHelper = new RecursionHelper<>(new ArrivalsFetcher[] {new GTTJSONFetcher(), new FiveTScraperFetcher()});
+ private RecursionHelper<StopsFinderByName> StopsFindersByNameRecursionHelper = new RecursionHelper<>(new StopsFinderByName[] {new GTTStopsFetcher(), new FiveTStopsFetcher()});
+ /*
+ * Position
+ */
+ //Fine location criteria
+ private final Criteria cr = new Criteria();
+ private boolean pendingNearbyStopsRequest = false;
+ private LocationManager locmgr;
+ /*
+ * Database Access
+ */
+ private StopsDB stopsDB;
+ private UserDB userDB;
+ private FragmentHelper fh;
+
+ ///////////////////////////////// EVENT HANDLERS ///////////////////////////////////////////////
+
+ /*
+ * @see swipeRefreshLayout
+ */
+ private Handler handler = new Handler();
+ private final Runnable refreshing = new Runnable() {
+ public void run() {
+ if(framan.findFragmentById(R.id.resultFrame) instanceof ArrivalsFragment){
+ ArrivalsFragment fragment = (ArrivalsFragment) framan.findFragmentById(R.id.resultFrame);
+ String stopName = fragment.getStopID();
+ new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS,fh).execute(stopName);
+ } else
+ new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS,fh).execute();
+ }
+ };
+
+ //// MAIN METHOD ///
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ framan = getSupportFragmentManager();
+ this.stopsDB = new StopsDB(getApplicationContext());
+ this.userDB = new UserDB(getApplicationContext());
+ setContentView(R.layout.activity_main);
+ busStopSearchByIDEditText = (EditText) findViewById(R.id.busStopSearchByIDEditText);
+ busStopSearchByNameEditText = (EditText) findViewById(R.id.busStopSearchByNameEditText);
+ progressBar = (ProgressBar) findViewById(R.id.progressBar);
+ howDoesItWorkTextView = (TextView) findViewById(R.id.howDoesItWorkTextView);
+ hideHintButton = (Button) findViewById(R.id.hideHintButton);
+ swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.listRefreshLayout);
+ floatingActionButton = (FloatingActionButton) findViewById(R.id.floatingActionButton);
+
+ framan.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
+ @Override
+ public void onBackStackChanged() {
+ Log.d("MainActivity, BusTO", "BACK STACK CHANGED");
+ }
+ });
+
+ busStopSearchByIDEditText.setSelectAllOnFocus(true);
+ busStopSearchByIDEditText
+ .setOnEditorActionListener(new TextView.OnEditorActionListener() {
+ @Override
+ public boolean onEditorAction(TextView v, int actionId,
+ KeyEvent event) {
+ // IME_ACTION_SEARCH alphabetical option
+ if (actionId == EditorInfo.IME_ACTION_SEARCH) {
+ onSearchClick(v);
+ return true;
+ }
+ return false;
+ }
+ });
+ busStopSearchByNameEditText
+ .setOnEditorActionListener(new TextView.OnEditorActionListener() {
+ @Override
+ public boolean onEditorAction(TextView v, int actionId,
+ KeyEvent event) {
+ // IME_ACTION_SEARCH alphabetical option
+ if (actionId == EditorInfo.IME_ACTION_SEARCH) {
+ onSearchClick(v);
+ return true;
+ }
+ return false;
+ }
+ });
+
+ // Called when the layout is pulled down
+ swipeRefreshLayout
+ .setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
+ @Override
+ public void onRefresh() {
+ handler.post(refreshing);
+ }
+ });
+
+ /**
+ * @author Marco Gagino!!!
+ */
+ //swipeRefreshLayout.setColorSchemeColors(R.color.blue_500, R.color.orange_500); // setColorScheme is deprecated, setColorSchemeColors isn't
+ swipeRefreshLayout.setColorSchemeResources(R.color.blue_500,R.color.orange_500);
+ fh = new FragmentHelper(this,R.id.listRefreshLayout,R.id.resultFrame);
+ setSearchModeBusStopID();
+
+ //---------------------------- START INTENT CHECK QUEUE ------------------------------------
+
+ // Intercept calls from URL intent
+ boolean tryedFromIntent = false;
+
+ String busStopID = null;
+ String busStopDisplayName = null;
+ Uri data = getIntent().getData();
+ if (data != null) {
+ busStopID = getBusStopIDFromUri(data);
+ tryedFromIntent = true;
+ }
+
+ // Intercept calls from other activities
+ if (!tryedFromIntent) {
+ Bundle b = getIntent().getExtras();
+ if (b != null) {
+ busStopID = b.getString("bus-stop-ID");
+ busStopDisplayName = b.getString("bus-stop-display-name");
+
+ /**
+ * I'm not very sure if you are coming from an Intent.
+ * Some launchers work in strange ways.
+ */
+ tryedFromIntent = busStopID != null;
+ }
+ }
+
+ //---------------------------- END INTENT CHECK QUEUE --------------------------------------
+
+ if (busStopID == null) {
+ // Show keyboard if can't start from intent
+ // JUST DON'T
+ // showKeyboard();
+
+ // You haven't obtained anything... from an intent?
+ if (tryedFromIntent) {
+
+ // This shows a luser warning
+ ArrivalFetchersRecursionHelper.reset();
+ Toast.makeText(getApplicationContext(),
+ R.string.insert_bus_stop_number_error, Toast.LENGTH_SHORT).show();
+ }
+ } else {
+ // If you are here an intent has worked successfully
+ setBusStopSearchByIDEditText(busStopID);
+ /*
+ //THIS PART SHOULDN'T BE NECESSARY SINCE THE LAST SUCCESSFULLY SEARCHED BUS
+ // STOP IS ADDED AUTOMATICALLY
+ Stop nextStop = new Stop(busStopID);
+ // forcing it as user name even though it could be standard name, it doesn't really matter
+ nextStop.setStopUserName(busStopDisplayName);
+ //set stop as last succe
+ fh.setLastSuccessfullySearchedBusStop(nextStop);
+ */
+ createFragmentForStop(busStopID);
+ }
+ //Try (hopefully) database update
+ //TODO: Start the service in foreground, check last time it ran before
+ DatabaseUpdateService.startDBUpdate(getApplicationContext());
+ /*
+ Set database update
+ */
+ updatelistener = new DBStatusManager.OnDBUpdateStatusChangeListener(){
+ @Override
+ public boolean defaultStatusValue() {
+ return true;
+ }
+
+ @Override
+ public void onDBStatusChanged(boolean updating) {
+
+ if(updating){
+ createDefaultSnackbar();
+ }
+ else if(snackbar!=null){
+ snackbar.dismiss();
+ snackbar = null;
+ }
+
+
+ }
+ };
+ prefsManager = new DBStatusManager(getApplicationContext(),updatelistener);
+ prefsManager.registerListener();
+
+ //locationHandler = new GPSLocationAdapter(getApplicationContext());
+ //--------- NEARBY STOPS--------//
+ //SETUP LOCATION
+ locmgr = (LocationManager) getSystemService(LOCATION_SERVICE);
+ cr.setAccuracy(Criteria.ACCURACY_FINE);
+ cr.setAltitudeRequired(false);
+ cr.setBearingRequired(false);
+ cr.setCostAllowed(true);
+ cr.setPowerRequirement(Criteria.NO_REQUIREMENT);
+ //We want the nearby bus stops!
+ handler.post(new NearbyStopsRequester());
+ //If there are no providers available, then, wait for them
+
+
+ Log.d("MainActivity", "Created");
+
+ }
+
+ /**
+ * Reload bus stop timetable when it's fulled resumed from background.
+ */
+ /**
+ @Override
+ protected void onPostResume() {
+ super.onPostResume();
+ Log.d("ActivityMain", "onPostResume fired. Last successfully bus stop ID: " + fh.getLastSuccessfullySearchedBusStop());
+ if (searchMode == SEARCH_BY_ID && fh.getLastSuccessfullySearchedBusStop() != null) {
+ setBusStopSearchByIDEditText(fh.getLastSuccessfullySearchedBusStop().ID);
+ //new asyncWgetBusStopFromBusStopID(lastSuccessfullySearchedBusStop.ID, ArrivalFetchersRecursionHelper, lastSuccessfullySearchedBusStop);
+ new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS,fh).execute();
+ } else {
+ //we have new activity or we don't have a new searched stop.
+ //Let's search stops nearby
+ LocationManager locManager = (LocationManager) getSystemService(LOCATION_SERVICE);
+ Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.resultFrame);
+
+
+ }
+ //show the FAB since it remains hidden
+ floatingActionButton.show();
+
+ }
+ **/
+
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ fh.stopLastRequestIfNeeded();
+ fh.setBlockAllActivities(true);
+ if(updatelistener!=null && prefsManager!=null) prefsManager.unregisterListener();
+ locmgr.removeUpdates(locListener);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ fh.setBlockAllActivities(false);
+ if(updatelistener!=null && prefsManager!=null) {
+ prefsManager.registerListener();
+ if(prefsManager.isDBUpdating(true)){
+ createDefaultSnackbar();
+ }
+ }
+ if(pendingNearbyStopsRequest)
+ handler.post(new NearbyStopsRequester());
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.main, menu);
+
+ actionHelpMenuItem = menu.findItem(R.id.action_help);
+ return true;
+ }
+
+ /**
+ * Callback fired when a MenuItem is selected
+ *
+ * @param item
+ * @return
+ */
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle action bar item clicks here. The action bar will
+ // automatically handle clicks on the Home/Up button, so long
+ // as you specify a parent activity in AndroidManifest.xml.
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ // Respond to the action bar's Up/Home button
+ NavUtils.navigateUpFromSameTask(this);
+ return true;
+ case R.id.action_help:
+ showHints();
+ return true;
+ case R.id.action_favorites:
+ startActivity(new Intent(ActivityMain.this, ActivityFavorites.class));
+ return true;
+ case R.id.action_about:
+ startActivity(new Intent(ActivityMain.this, ActivityAbout.class));
+ return true;
+ case R.id.action_news:
+ openIceweasel("https://gitpull.it/w/librebusto/#how-to-get-news");
+ return true;
+ case R.id.action_bugs:
+ openIceweasel("https://gitpull.it/w/librebusto/#how-to-create-a-bug-feature");
+ return true;
+ case R.id.action_source:
+ openIceweasel("https://gitpull.it/w/librebusto/#how-to-hack-busto");
+ return true;
+ case R.id.action_licence:
+ openIceweasel("https://www.gnu.org/licenses/gpl-3.0.html");
+ return true;
+ case R.id.action_settings:
+ Log.d("MAINBusTO","Pressed button preferences");
+ startActivity(new Intent(ActivityMain.this,ActivitySettings.class));
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ /**
+ * OK this is pure shit
+ *
+ * @param v View clicked
+ */
+ public void onSearchClick(View v) {
+ if (searchMode == SEARCH_BY_ID) {
+ String busStopID = busStopSearchByIDEditText.getText().toString();
+ //OLD ASYNCTASK
+ //new asyncWgetBusStopFromBusStopID(busStopID, ArrivalFetchersRecursionHelper, lastSuccessfullySearchedBusStop);
+
+ if(busStopID == null || busStopID.length() <= 0) {
+ showMessage(R.string.insert_bus_stop_number_error);
+ toggleSpinner(false);
+ } else{
+ new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS,fh).execute(busStopID);
+ Log.d("MainActiv","Started search for arrivals of stop "+busStopID);
+ }
+ } else { // searchMode == SEARCH_BY_NAME
+ String query = busStopSearchByNameEditText.getText().toString();
+ //new asyncWgetBusStopSuggestions(query, stopsDB, StopsFindersByNameRecursionHelper);
+ new AsyncDataDownload(AsyncDataDownload.RequestType.STOPS,fh).execute(query);
+ }
+ }
+ /** PERMISSION STUFF **/
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ switch (requestCode){
+ case PERMISSION_REQUEST_POSITION:
+ if(grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
+ setOption(LOCATION_PERMISSION_GIVEN,true);
+ //if we sent a request for a new NearbyStopsFragment
+ if(pendingNearbyStopsRequest){
+ pendingNearbyStopsRequest=false;
+ handler.post(new NearbyStopsRequester());
+ }
+
+ } else {
+ //permission denied
+ setOption(LOCATION_PERMISSION_GIVEN,false);
+ }
+ //add other cases for permissions
+ }
+
+ }
+
+
+ @Override
+ public void createFragmentForStop(String ID) {
+ //new asyncWgetBusStopFromBusStopID(ID, ArrivalFetchersRecursionHelper,lastSuccessfullySearchedBusStop);
+ if(ID == null || ID.length() <= 0) {
+ // we're still in UI thread, no need to mess with Progress
+ showMessage(R.string.insert_bus_stop_number_error);
+ toggleSpinner(false);
+ } else {
+ new AsyncDataDownload(AsyncDataDownload.RequestType.ARRIVALS,fh).execute(ID);
+ Log.d("MainActiv","Started search for arrivals of stop "+ID);
+ }
+ }
+
+
+
+ /**
+ * QR scan button clicked
+ *
+ * @param v View QRButton clicked
+ */
+ public void onQRButtonClick(View v) {
+ IntentIntegrator integrator = new IntentIntegrator(this);
+ integrator.initiateScan();
+ }
+
+ /**
+ * Receive the Barcode Scanner Intent
+ *
+ */
+ public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
+
+ Uri uri;
+ try {
+ uri = Uri.parse(scanResult != null ? scanResult.getContents() : null); // this apparently prevents NullPointerException. Somehow.
+ } catch (NullPointerException e) {
+ Toast.makeText(getApplicationContext(),
+ R.string.no_qrcode, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ String busStopID = getBusStopIDFromUri(uri);
+ busStopSearchByIDEditText.setText(busStopID);
+ createFragmentForStop(busStopID);
+ }
+
+ public void onHideHint(View v) {
+ hideHints();
+ setOption(OPTION_SHOW_LEGEND, false);
+ }
+
+ public void onToggleKeyboardLayout(View v) {
+ if (searchMode == SEARCH_BY_NAME) {
+ setSearchModeBusStopID();
+ if (busStopSearchByIDEditText.requestFocus()) {
+ showKeyboard();
+ }
+ } else { // searchMode == SEARCH_BY_ID
+ setSearchModeBusStopName();
+ if (busStopSearchByNameEditText.requestFocus()) {
+ showKeyboard();
+ }
+ }
+ }
+ private void createDefaultSnackbar(){
+ if(snackbar==null){
+ snackbar = Snackbar.make(findViewById(R.id.searchButton),R.string.database_update_message,Snackbar.LENGTH_INDEFINITE);
+ }
+ snackbar.show();
+ }
+ ///////////////////////////////// POSITION STUFF//////////////////////////////////////////////
+
+ private void resolveStopRequest(String provider){
+ Log.d(DEBUG_TAG,"Provider "+provider+" got enabled");
+ if(locmgr!=null && pendingNearbyStopsRequest && locmgr.getProvider(provider).meetsCriteria(cr)){
+ pendingNearbyStopsRequest = false;
+ handler.post(new NearbyStopsRequester());
+ }
+ }
+ final LocationListener locListener = new LocationListener() {
+ @Override
+ public void onLocationChanged(Location location) {
+ Log.d(DEBUG_TAG,"Location changed");
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ Log.d(DEBUG_TAG,"Location provider status: "+status);
+ if(status== LocationProvider.AVAILABLE){
+ resolveStopRequest(provider);
+ }
+ }
+
+ @Override
+ public void onProviderEnabled(String provider) {
+ resolveStopRequest(provider);
+ }
+
+ @Override
+ public void onProviderDisabled(String provider) {
+
+ }
+ };
+
+ class NearbyStopsRequester implements Runnable{
+ @SuppressLint("MissingPermission")
+ @Override
+ public void run() {
+ final boolean canRunPosition = Build.VERSION.SDK_INT < Build.VERSION_CODES.M || getOption(LOCATION_PERMISSION_GIVEN, false);
+
+ if(!canRunPosition){
+ pendingNearbyStopsRequest = true;
+ assertLocationPermissions();
+ return;
+ } else setOption(LOCATION_PERMISSION_GIVEN,true);
+
+ LocationManager locManager = (LocationManager) getSystemService(LOCATION_SERVICE);
+ if(locManager == null) {
+ Log.e(DEBUG_TAG, "location manager is nihil, cannot create NearbyStopsFragment");
+ return;
+ }
+ if(anyLocationProviderMatchesCriteria(locManager,cr,true) && fh.getLastSuccessfullySearchedBusStop()==null) {
+ //Go ahead with the request
+ Log.d("mainActivity","Recreating stop fragment");
+ swipeRefreshLayout.setVisibility(View.VISIBLE);
+ NearbyStopsFragment fragment = NearbyStopsFragment.newInstance(NearbyStopsFragment.TYPE_STOPS);
+ Fragment oldFrag = framan.findFragmentById(R.id.resultFrame);
+ FragmentTransaction ft = framan.beginTransaction();
+ if(oldFrag!=null)
+ ft.remove(oldFrag);
+ ft.add(R.id.resultFrame,fragment,"nearbyStop_correct");
+ ft.commit();
+ framan.executePendingTransactions();
+ pendingNearbyStopsRequest = false;
+ } else if(!anyLocationProviderMatchesCriteria(locManager,cr,true)){
+ //Wait for the providers
+ Log.d(DEBUG_TAG,"Queuing position request");
+ pendingNearbyStopsRequest = true;
+ locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,10,0.1f,locListener);
+ }
+
+ }
+ }
+
+ private boolean anyLocationProviderMatchesCriteria(LocationManager mng, Criteria cr, boolean enabled){
+ List<String> providers = mng.getProviders(cr,enabled);
+ Log.d(DEBUG_TAG,"Getting enabled location providers: ");
+ for(String s: providers){
+ Log.d(DEBUG_TAG,"Provider "+s);
+ }
+ return providers.size()>0;
+ }
+
+
+
+ ///////////////////////////////// OTHER STUFF //////////////////////////////////////////////////
+
+ /**
+ * Get the last successfully searched bus stop or NULL
+ *
+ * @return
+ */
+ @Override
+ public Stop getLastSuccessfullySearchedBusStop() {
+ return fh.getLastSuccessfullySearchedBusStop();
+ }
+
+ /**
+ * Get the last successfully searched bus stop ID or NULL
+ *
+ * @return
+ */
+ @Override
+ public String getLastSuccessfullySearchedBusStopID() {
+ Stop stop = getLastSuccessfullySearchedBusStop();
+ return stop == null ? null : stop.ID;
+ }
+
+ /**
+ * Update the star "Add to favorite" icon
+ */
+ @Override
+ public void updateStarIconFromLastBusStop() {
+
+ // no favorites no party!
+ addToFavorites = (ImageButton) findViewById(R.id.addToFavorites);
+ if (addToFavorites == null) {
+ Log.d("MainActivity", "Why the fuck the star is not here?!");
+ return;
+ }
+
+ // check if there is a last Stop
+ String stopID = getLastSuccessfullySearchedBusStopID();
+ if(stopID == null) {
+ addToFavorites.setVisibility(View.INVISIBLE);
+ } else {
+ // filled or outline?
+ if(isStopInFavorites(stopID)) {
+ addToFavorites.setImageResource(R.drawable.ic_star_filled);
+ } else {
+ addToFavorites.setImageResource(R.drawable.ic_star_outline);
+ }
+
+ addToFavorites.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * Check if the last Bus Stop is in the favorites
+ *
+ * @return
+ */
+ public boolean isStopInFavorites(String busStopId) {
+ boolean found = false;
+
+ // no stop no party
+ if(busStopId != null) {
+ SQLiteDatabase userDB = new UserDB(getApplicationContext()).getReadableDatabase();
+ found = UserDB.isStopInFavorites(userDB, busStopId);
+ }
+
+ return found;
+ }
+
+ /**
+ * Add the last Stop to favorites
+ */
+ @Override
+ public void toggleLastStopToFavorites() {
+ Stop stop = getLastSuccessfullySearchedBusStop();
+ if(stop != null) {
+
+ // toggle the status in background
+ new AsyncStopFavoriteAction(getApplicationContext(), AsyncStopFavoriteAction.Action.TOGGLE) {
+
+ /**
+ * Callback fired when the Stop is saved in the favorites
+ * @param result
+ */
+ @Override
+ protected void onPostExecute(Boolean result) {
+ super.onPostExecute(result);
+
+
+ // update the star icon
+ updateStarIconFromLastBusStop();
+ }
+
+ }.execute(stop);
+ } else {
+ // this case have no sense, but just immediately update the favorite icon
+ updateStarIconFromLastBusStop();
+ }
+ }
+
+ @Override
+ public void showFloatingActionButton(boolean yes) {
+ if(yes) floatingActionButton.show();
+ else floatingActionButton.hide();
+ }
+
+ @Override
+ public void enableRefreshLayout(boolean yes) {
+ swipeRefreshLayout.setEnabled(yes);
+ }
+
+ ////////////////////////////////////// GUI HELPERS /////////////////////////////////////////////
+ @Override
+ public void showKeyboard() {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ View view = searchMode == SEARCH_BY_ID ? busStopSearchByIDEditText : busStopSearchByNameEditText;
+ imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
+ }
+
+ @Override
+ public void showMessage(int messageID) {
+ Toast.makeText(getApplicationContext(), messageID, Toast.LENGTH_SHORT).show();
+ }
+
+ private void setSearchModeBusStopID() {
+ searchMode = SEARCH_BY_ID;
+ busStopSearchByNameEditText.setVisibility(View.GONE);
+ busStopSearchByNameEditText.setText("");
+ busStopSearchByIDEditText.setVisibility(View.VISIBLE);
+ floatingActionButton.setImageResource(R.drawable.alphabetical);
+ }
+
+ private void setSearchModeBusStopName() {
+ searchMode = SEARCH_BY_NAME;
+ busStopSearchByIDEditText.setVisibility(View.GONE);
+ busStopSearchByIDEditText.setText("");
+ busStopSearchByNameEditText.setVisibility(View.VISIBLE);
+ floatingActionButton.setImageResource(R.drawable.numeric);
+ }
+
+ /**
+ * Having that cursor at the left of the edit text makes me cancer.
+ * @param busStopID bus stop ID
+ */
+ private void setBusStopSearchByIDEditText(String busStopID) {
+ busStopSearchByIDEditText.setText(busStopID);
+ busStopSearchByIDEditText.setSelection(busStopID.length());
+ }
+
+ private void showHints() {
+ howDoesItWorkTextView.setVisibility(View.VISIBLE);
+ hideHintButton.setVisibility(View.VISIBLE);
+ actionHelpMenuItem.setVisible(false);
+ }
+
+ private void hideHints() {
+ howDoesItWorkTextView.setVisibility(View.GONE);
+ hideHintButton.setVisibility(View.GONE);
+ actionHelpMenuItem.setVisible(true);
+ }
+
+ //TODO: toggle spinner from mainActivity
+ @Override
+ public void toggleSpinner(boolean enable) {
+ if (enable) {
+ //already set by the RefreshListener when needed
+ //swipeRefreshLayout.setRefreshing(true);
+ progressBar.setVisibility(View.VISIBLE);
+ } else {
+ swipeRefreshLayout.setRefreshing(false);
+ progressBar.setVisibility(View.GONE);
+ }
+ }
+
+ private void prepareGUIForBusLines() {
+ swipeRefreshLayout.setEnabled(true);
+ swipeRefreshLayout.setVisibility(View.VISIBLE);
+ actionHelpMenuItem.setVisible(true);
+ }
+
+ private void prepareGUIForBusStops() {
+ swipeRefreshLayout.setEnabled(false);
+ swipeRefreshLayout.setVisibility(View.VISIBLE);
+ actionHelpMenuItem.setVisible(false);
+ }
+
+
+ /**
+ * This provides a temporary fix to make the transition
+ * to a single asynctask go smoother
+ * @param fragmentType the type of fragment created
+ */
+ @Override
+ public void readyGUIfor(FragmentKind fragmentType) {
+ hideKeyboard();
+ //if we are getting results, already, stop waiting for nearbyStops
+ if(pendingNearbyStopsRequest && (fragmentType==FragmentKind.ARRIVALS || fragmentType==FragmentKind.STOPS)) {
+ locmgr.removeUpdates(locListener);
+ pendingNearbyStopsRequest = false;
+ }
+ if(fragmentType==null) Log.e("ActivityMain","Problem with fragmentType");
+ else
+ switch (fragmentType){
+ case ARRIVALS:
+ prepareGUIForBusLines();
+ if (getOption(OPTION_SHOW_LEGEND, true)) {
+ showHints();
+ }
+ break;
+ case STOPS:
+ prepareGUIForBusStops();
+ break;
+ default:
+ Log.e("BusTO Activity","Called readyGUI with unsupported type of Fragment");
+ return;
+ }
+ // Shows hints
+
+ }
+
+ /**
+ * Open an URL in the default browser.
+ *
+ * @param url URL
+ */
+ public void openIceweasel(String url) {
+ Intent browserIntent1 = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ startActivity(browserIntent1);
+ }
+
+ ///////////////////// INTENT HELPER ////////////////////////////////////////////////////////////
+
+ /**
+ * Try to extract the bus stop ID from a URi
+ *
+ * @param uri The URL
+ * @return bus stop ID or null
+ */
+ public static String getBusStopIDFromUri(Uri uri) {
+ String busStopID;
+
+ // everithing catches fire when passing null to a switch.
+ String host = uri.getHost();
+ if(host == null) {
+ Log.e("ActivityMain", "Not an URL: " + uri);
+ return null;
+ }
+
+ switch(host) {
+ case "m.gtt.to.it":
+ // http://m.gtt.to.it/m/it/arrivi.jsp?n=1254
+ busStopID = uri.getQueryParameter("n");
+ if (busStopID == null) {
+ Log.e("ActivityMain", "Expected ?n from: " + uri);
+ }
+ break;
+ case "www.gtt.to.it":
+ case "gtt.to.it":
+ // http://www.gtt.to.it/cms/percorari/arrivi?palina=1254
+ busStopID = uri.getQueryParameter("palina");
+ if (busStopID == null) {
+ Log.e("ActivityMain", "Expected ?palina from: " + uri);
+ }
+ break;
+ default:
+ Log.e("ActivityMain", "Unexpected intent URL: " + uri);
+ busStopID = null;
+ }
+ return busStopID;
+ }
+
+ public void changeStarType(String stopID) {
+ if(isStopInFavorites(stopID)) {
+ changeStarFilled();
+ } else {
+ changeStarOutline();
+ }
+ }
+
+ public void changeStarFilled() {
+ addToFavorites.setImageResource(R.drawable.ic_star_filled);
+ }
+
+ public void changeStarOutline() {
+ addToFavorites.setImageResource(R.drawable.ic_star_outline);
+ }
+
+
+
}
\ No newline at end of file
diff --git a/src/it/reyboz/bustorino/fragments/ArrivalsFragment.java b/src/it/reyboz/bustorino/fragments/ArrivalsFragment.java
--- a/src/it/reyboz/bustorino/fragments/ArrivalsFragment.java
+++ b/src/it/reyboz/bustorino/fragments/ArrivalsFragment.java
@@ -1,212 +1,215 @@
-/*
- BusTO - Fragments components
- Copyright (C) 2018 Fabio Mazza
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package it.reyboz.bustorino.fragments;
-
-
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v4.app.LoaderManager;
-import android.support.v4.content.CursorLoader;
-import android.support.v4.content.Loader;
-import android.util.Log;
-import android.widget.TextView;
-
-import it.reyboz.bustorino.R;
-import it.reyboz.bustorino.backend.DBStatusManager;
-import it.reyboz.bustorino.middleware.AppDataProvider;
-import it.reyboz.bustorino.middleware.NextGenDB;
-import it.reyboz.bustorino.middleware.UserDB;
-
-public class ArrivalsFragment extends ResultListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
-
- private final static String KEY_STOP_ID = "stopid";
- private final static String KEY_STOP_NAME = "stopname";
- private final static String DEBUG_TAG = "BUSTOArrivalsFragment";
- private final static int loaderFavId = 2;
- private final static int loaderStopId = 1;
- private @Nullable String stopID,stopName;
- private TextView messageTextView;
- private DBStatusManager prefs;
- private DBStatusManager.OnDBUpdateStatusChangeListener listener;
- private boolean justCreated = false;
-
- public static ArrivalsFragment newInstance(String stopID){
- Bundle args = new Bundle();
- args.putString(KEY_STOP_ID,stopID);
- ArrivalsFragment fragment = new ArrivalsFragment();
- //parameter for ResultListFragment
- args.putSerializable(LIST_TYPE,FragmentKind.ARRIVALS);
- fragment.setArguments(args);
- return fragment;
- }
- public static ArrivalsFragment newInstance(String stopID,String stopName){
- ArrivalsFragment fragment = newInstance(stopID);
- Bundle args = fragment.getArguments();
- args.putString(KEY_STOP_NAME,stopName);
- fragment.setArguments(args);
- return fragment;
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- stopID = getArguments().getString(KEY_STOP_ID);
- //this might really be null
- stopName = getArguments().getString(KEY_STOP_NAME);
- final ArrivalsFragment f = this;
- listener = new DBStatusManager.OnDBUpdateStatusChangeListener() {
- @Override
- public void onDBStatusChanged(boolean updating) {
- if(!updating){
- getLoaderManager().restartLoader(loaderFavId,getArguments(),f);
- } else {
- final LoaderManager lm = getLoaderManager();
- lm.destroyLoader(loaderFavId);
- lm.destroyLoader(loaderStopId);
- }
- }
-
- @Override
- public boolean defaultStatusValue() {
- return true;
- }
- };
- prefs = new DBStatusManager(getContext().getApplicationContext(),listener);
- justCreated = true;
-
- }
-
- @Override
- public void onResume() {
- super.onResume();
- LoaderManager loaderManager = getLoaderManager();
-
- if(stopID!=null){
- //refresh the arrivals
- if(!justCreated)
- mListener.createFragmentForStop(stopID);
- else justCreated = false;
- //start the loader
- if(prefs.isDBUpdating(true)){
- prefs.registerListener();
- } else {
- loaderManager.restartLoader(loaderFavId, getArguments(), this);
- }
- updateMessage();
- }
- }
-
- @Nullable
- public String getStopID() {
- return stopID;
- }
-
- /**
- * Update the message in the fragment
- *
- * It may eventually change the "Add to Favorite" icon
- */
- private void updateMessage(){
- String message = null;
- if (stopName != null && stopID != null && stopName.length() > 0) {
- message = (stopID.concat(" - ").concat(stopName));
- } else if(stopID!=null) {
- message = stopID;
- } else {
- Log.e("ArrivalsFragm"+getTag(),"NO ID FOR THIS FRAGMENT - something went horribly wrong");
- }
- if(message!=null) {
- setTextViewMessage(getString(R.string.passages,message));
- }
-
- // whatever is the case, update the star icon
- mListener.updateStarIconFromLastBusStop();
- }
-
- @Override
- public Loader<Cursor> onCreateLoader(int id, Bundle args) {
- if(args.getString(KEY_STOP_ID)==null) return null;
- final String stopID = args.getString(KEY_STOP_ID);
- final Uri.Builder builder = AppDataProvider.getUriBuilderToComplete();
- CursorLoader cl;
- switch (id){
- case loaderFavId:
- builder.appendPath("favorites").appendPath(stopID);
- cl = new CursorLoader(getContext(),builder.build(),UserDB.getFavoritesColumnNamesAsArray,null,null,null);
-
- break;
- case loaderStopId:
- builder.appendPath("stop").appendPath(stopID);
- cl = new CursorLoader(getContext(),builder.build(),new String[]{NextGenDB.Contract.StopsTable.COL_NAME},
- null,null,null);
- break;
- default:
- return null;
- }
- cl.setUpdateThrottle(500);
- return cl;
- }
-
- @Override
- public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
-
- switch (loader.getId()){
- case loaderFavId:
- final int colUserName = data.getColumnIndex(UserDB.getFavoritesColumnNamesAsArray[1]);
- if(data.getCount()>0){
- data.moveToFirst();
- final String probableName = data.getString(colUserName);
- if(probableName!=null && !probableName.isEmpty()){
- stopName = probableName;
- updateMessage();
- }
- }
- if(stopName == null){
- //stop is not inside the favorites and wasn't provided
- Log.d("ArrivalsFragment"+getTag(),"Stop wasn't in the favorites and has no name, looking in the DB");
- getLoaderManager().restartLoader(loaderStopId,getArguments(),this);
- }
- break;
- case loaderStopId:
- if(data.getCount()>0){
- data.moveToFirst();
- stopName = data.getString(data.getColumnIndex(
- NextGenDB.Contract.StopsTable.COL_NAME
- ));
- updateMessage();
- } else {
- Log.w("ArrivalsFragment"+getTag(),"Stop is not inside the database... CLOISTER BELL");
- }
- }
-
- }
-
- @Override
- public void onPause() {
- if(listener!=null)
- prefs.unregisterListener();
- super.onPause();
- }
-
- @Override
- public void onLoaderReset(Loader<Cursor> loader) {
- //NOTHING TO DO
- }
-}
+/*
+ BusTO - Fragments components
+ Copyright (C) 2018 Fabio Mazza
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package it.reyboz.bustorino.fragments;
+
+
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.CursorLoader;
+import android.support.v4.content.Loader;
+import android.util.Log;
+import android.widget.ImageButton;
+import android.widget.TextView;
+
+import it.reyboz.bustorino.R;
+import it.reyboz.bustorino.backend.DBStatusManager;
+import it.reyboz.bustorino.middleware.AppDataProvider;
+import it.reyboz.bustorino.middleware.NextGenDB;
+import it.reyboz.bustorino.middleware.UserDB;
+
+public class ArrivalsFragment extends ResultListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
+
+ private final static String KEY_STOP_ID = "stopid";
+ private final static String KEY_STOP_NAME = "stopname";
+ private final static String DEBUG_TAG = "BUSTOArrivalsFragment";
+ private final static int loaderFavId = 2;
+ private final static int loaderStopId = 1;
+ private @Nullable String stopID,stopName;
+ private TextView messageTextView;
+ private DBStatusManager prefs;
+ private DBStatusManager.OnDBUpdateStatusChangeListener listener;
+ private boolean justCreated = false;
+ private ImageButton addToFavorites;
+
+
+ public static ArrivalsFragment newInstance(String stopID){
+ Bundle args = new Bundle();
+ args.putString(KEY_STOP_ID,stopID);
+ ArrivalsFragment fragment = new ArrivalsFragment();
+ //parameter for ResultListFragment
+ args.putSerializable(LIST_TYPE,FragmentKind.ARRIVALS);
+ fragment.setArguments(args);
+ return fragment;
+ }
+ public static ArrivalsFragment newInstance(String stopID,String stopName){
+ ArrivalsFragment fragment = newInstance(stopID);
+ Bundle args = fragment.getArguments();
+ args.putString(KEY_STOP_NAME,stopName);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ stopID = getArguments().getString(KEY_STOP_ID);
+ //this might really be null
+ stopName = getArguments().getString(KEY_STOP_NAME);
+ final ArrivalsFragment f = this;
+ listener = new DBStatusManager.OnDBUpdateStatusChangeListener() {
+ @Override
+ public void onDBStatusChanged(boolean updating) {
+ if(!updating){
+ getLoaderManager().restartLoader(loaderFavId,getArguments(),f);
+ } else {
+ final LoaderManager lm = getLoaderManager();
+ lm.destroyLoader(loaderFavId);
+ lm.destroyLoader(loaderStopId);
+ }
+ }
+
+ @Override
+ public boolean defaultStatusValue() {
+ return true;
+ }
+ };
+ prefs = new DBStatusManager(getContext().getApplicationContext(),listener);
+ justCreated = true;
+
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ LoaderManager loaderManager = getLoaderManager();
+
+ if(stopID!=null){
+ //refresh the arrivals
+ if(!justCreated)
+ mListener.createFragmentForStop(stopID);
+ else justCreated = false;
+ //start the loader
+ if(prefs.isDBUpdating(true)){
+ prefs.registerListener();
+ } else {
+ loaderManager.restartLoader(loaderFavId, getArguments(), this);
+ }
+ updateMessage();
+ }
+ }
+
+ @Nullable
+ public String getStopID() {
+ return stopID;
+ }
+
+ /**
+ * Update the message in the fragment
+ *
+ * It may eventually change the "Add to Favorite" icon
+ */
+ private void updateMessage(){
+ String message = null;
+ if (stopName != null && stopID != null && stopName.length() > 0) {
+ message = (stopID.concat(" - ").concat(stopName));
+ } else if(stopID!=null) {
+ message = stopID;
+ } else {
+ Log.e("ArrivalsFragm"+getTag(),"NO ID FOR THIS FRAGMENT - something went horribly wrong");
+ }
+ if(message!=null) {
+ setTextViewMessage(getString(R.string.passages,message));
+ }
+
+ // whatever is the case, update the star icon
+ mListener.updateStarIconFromLastBusStop();
+ }
+
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ if(args.getString(KEY_STOP_ID)==null) return null;
+ final String stopID = args.getString(KEY_STOP_ID);
+ final Uri.Builder builder = AppDataProvider.getUriBuilderToComplete();
+ CursorLoader cl;
+ switch (id){
+ case loaderFavId:
+ builder.appendPath("favorites").appendPath(stopID);
+ cl = new CursorLoader(getContext(),builder.build(),UserDB.getFavoritesColumnNamesAsArray,null,null,null);
+
+ break;
+ case loaderStopId:
+ builder.appendPath("stop").appendPath(stopID);
+ cl = new CursorLoader(getContext(),builder.build(),new String[]{NextGenDB.Contract.StopsTable.COL_NAME},
+ null,null,null);
+ break;
+ default:
+ return null;
+ }
+ cl.setUpdateThrottle(500);
+ return cl;
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+
+ switch (loader.getId()){
+ case loaderFavId:
+ final int colUserName = data.getColumnIndex(UserDB.getFavoritesColumnNamesAsArray[1]);
+ if(data.getCount()>0){
+ data.moveToFirst();
+ final String probableName = data.getString(colUserName);
+ if(probableName!=null && !probableName.isEmpty()){
+ stopName = probableName;
+ updateMessage();
+ }
+ }
+ if(stopName == null){
+ //stop is not inside the favorites and wasn't provided
+ Log.d("ArrivalsFragment"+getTag(),"Stop wasn't in the favorites and has no name, looking in the DB");
+ getLoaderManager().restartLoader(loaderStopId,getArguments(),this);
+ }
+ break;
+ case loaderStopId:
+ if(data.getCount()>0){
+ data.moveToFirst();
+ stopName = data.getString(data.getColumnIndex(
+ NextGenDB.Contract.StopsTable.COL_NAME
+ ));
+ updateMessage();
+ } else {
+ Log.w("ArrivalsFragment"+getTag(),"Stop is not inside the database... CLOISTER BELL");
+ }
+ }
+
+ }
+
+ @Override
+ public void onPause() {
+ if(listener!=null)
+ prefs.unregisterListener();
+ super.onPause();
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ //NOTHING TO DO
+ }
+}
diff --git a/src/it/reyboz/bustorino/fragments/FragmentHelper.java b/src/it/reyboz/bustorino/fragments/FragmentHelper.java
--- a/src/it/reyboz/bustorino/fragments/FragmentHelper.java
+++ b/src/it/reyboz/bustorino/fragments/FragmentHelper.java
@@ -1,230 +1,230 @@
-/*
- BusTO (fragments)
- Copyright (C) 2018 Fabio Mazza
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package it.reyboz.bustorino.fragments;
-
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.database.sqlite.SQLiteException;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.widget.SwipeRefreshLayout;
-import android.util.Log;
-import it.reyboz.bustorino.R;
-import it.reyboz.bustorino.adapters.PalinaAdapter;
-import it.reyboz.bustorino.backend.Fetcher;
-import it.reyboz.bustorino.backend.Palina;
-import it.reyboz.bustorino.backend.Stop;
-import it.reyboz.bustorino.middleware.*;
-
-import java.lang.ref.WeakReference;
-import java.util.List;
-
-/**
- * Helper class to manage the fragments and their needs
- */
-public class FragmentHelper {
- GeneralActivity act;
- private Stop lastSuccessfullySearchedBusStop;
- //support for multiple frames
- private int primaryFrameLayout,secondaryFrameLayout, swipeRefID;
- public static final int NO_FRAME = -3;
- private WeakReference<AsyncDataDownload> lastTaskRef;
- private NextGenDB newDBHelper;
- private boolean shouldHaltAllActivities=false;
-
-
- public FragmentHelper(GeneralActivity act, int swipeRefID, int mainFrame) {
- this(act,swipeRefID,mainFrame,NO_FRAME);
- }
-
- public FragmentHelper(GeneralActivity act, int swipeRefID, int primaryFrameLayout, int secondaryFrameLayout) {
- this.act = act;
- this.swipeRefID = swipeRefID;
- this.primaryFrameLayout = primaryFrameLayout;
- this.secondaryFrameLayout = secondaryFrameLayout;
- newDBHelper = NextGenDB.getInstance(act.getApplicationContext());
- }
-
- /**
- * Get the last successfully searched bus stop or NULL
- *
- * @return
- */
- public Stop getLastSuccessfullySearchedBusStop() {
- return lastSuccessfullySearchedBusStop;
- }
-
- public void setLastSuccessfullySearchedBusStop(Stop stop) {
- this.lastSuccessfullySearchedBusStop = stop;
- }
-
- public void setLastTaskRef(WeakReference<AsyncDataDownload> lastTaskRef) {
- this.lastTaskRef = lastTaskRef;
- }
-
- /**
- * Called when you need to create a fragment for a specified Palina
- * @param p the Stop that needs to be displayed
- */
- public void createOrUpdateStopFragment(Palina p){
- boolean sameFragment;
- ArrivalsFragment arrivalsFragment;
-
- if(act==null || shouldHaltAllActivities) {
- //SOMETHING WENT VERY WRONG
- return;
- }
-
- SwipeRefreshLayout srl = (SwipeRefreshLayout) act.findViewById(swipeRefID);
- FragmentManager fm = act.getSupportFragmentManager();
-
- if(fm.findFragmentById(R.id.resultFrame) instanceof ArrivalsFragment) {
- arrivalsFragment = (ArrivalsFragment) fm.findFragmentById(R.id.resultFrame);
- sameFragment = arrivalsFragment.isFragmentForTheSameStop(p);
- } else
- sameFragment = false;
-
- setLastSuccessfullySearchedBusStop(p);
-
- if(!sameFragment) {
- //set the String to be displayed on the fragment
- String displayName = p.getStopDisplayName();
- String displayStuff;
-
- if (displayName != null && displayName.length() > 0) {
- arrivalsFragment = ArrivalsFragment.newInstance(p.ID,displayName);
- } else {
- arrivalsFragment = ArrivalsFragment.newInstance(p.ID);
- }
- attachFragmentToContainer(fm,arrivalsFragment,true,ResultListFragment.getFragmentTag(p));
- } else {
- Log.d("BusTO", "Same bus stop, accessing existing fragment");
- arrivalsFragment = (ArrivalsFragment) fm.findFragmentById(R.id.resultFrame);
- }
-
- arrivalsFragment.setListAdapter(new PalinaAdapter(act.getApplicationContext(),p));
- act.hideKeyboard();
- toggleSpinner(false);
- }
-
- /**
- * Called when you need to display the results of a search of stops
- * @param resultList the List of stops found
- * @param query String queried
- */
- public void createFragmentFor(List<Stop> resultList,String query){
- act.hideKeyboard();
- StopListFragment listfragment = StopListFragment.newInstance(query);
- attachFragmentToContainer(act.getSupportFragmentManager(),listfragment,false,"search_"+query);
- listfragment.setStopList(resultList);
- toggleSpinner(false);
-
- }
-
- /**
- * Wrapper for toggleSpinner in Activity
- * @param on new status of spinner system
- */
- public void toggleSpinner(boolean on){
- if (act instanceof FragmentListener)
- ((FragmentListener) act).toggleSpinner(on);
- else {
- SwipeRefreshLayout srl = (SwipeRefreshLayout) act.findViewById(swipeRefID);
- srl.setRefreshing(false);
- }
- }
-
- /**
- * Attach a new fragment to a cointainer
- * @param fm the FragmentManager
- * @param fragment the Fragment
- * @param sendToSecondaryFrame needs to be displayed in secondary frame or not
- * @param tag tag for the fragment
- */
- public void attachFragmentToContainer(FragmentManager fm,Fragment fragment, boolean sendToSecondaryFrame, String tag){
- FragmentTransaction ft = fm.beginTransaction();
- if(sendToSecondaryFrame && secondaryFrameLayout!=NO_FRAME)
- ft.replace(secondaryFrameLayout,fragment,tag);
- else ft.replace(primaryFrameLayout,fragment,tag);
- ft.addToBackStack("state_"+tag);
- ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
- ft.commit();
- //fm.executePendingTransactions();
- }
-
- synchronized public int insertBatchDataInNextGenDB(ContentValues[] valuesArr,String tableName){
- if(newDBHelper !=null)
- try {
- return newDBHelper.insertBatchContent(valuesArr, tableName);
- } catch (SQLiteException exc){
- Log.w("DB Batch inserting: ","ERROR Inserting the data batch: ",exc.fillInStackTrace());
- return -2;
- }
- else return -1;
- }
-
- synchronized public ContentResolver getContentResolver(){
- return act.getContentResolver();
- }
-
- public void setBlockAllActivities(boolean shouldI) {
- this.shouldHaltAllActivities = shouldI;
- }
-
- public void stopLastRequestIfNeeded(){
- if(lastTaskRef == null) return;
- AsyncDataDownload task = lastTaskRef.get();
- if(task!=null){
- task.cancel(true);
- }
- }
-
- /**
- * Wrapper to show the errors/status that happened
- * @param res result from Fetcher
- */
- public void showErrorMessage(Fetcher.result res){
- //TODO: implement a common set of errors for all fragments
- switch (res){
- case OK:
- break;
- case CLIENT_OFFLINE:
- act.showMessage(R.string.network_error);
- break;
- case SERVER_ERROR:
- if (act.isConnected()) {
- act.showMessage(R.string.parsing_error);
- } else {
- act.showMessage(R.string.network_error);
- }
- case PARSER_ERROR:
- default:
- act.showMessage(R.string.internal_error);
- break;
- case QUERY_TOO_SHORT:
- act.showMessage(R.string.query_too_short);
- break;
- case EMPTY_RESULT_SET:
- act.showMessage(R.string.no_bus_stop_have_this_name);
- break;
- }
- }
-
-}
+/*
+ BusTO (fragments)
+ Copyright (C) 2018 Fabio Mazza
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package it.reyboz.bustorino.fragments;
+
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.sqlite.SQLiteException;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.util.Log;
+import it.reyboz.bustorino.R;
+import it.reyboz.bustorino.adapters.PalinaAdapter;
+import it.reyboz.bustorino.backend.Fetcher;
+import it.reyboz.bustorino.backend.Palina;
+import it.reyboz.bustorino.backend.Stop;
+import it.reyboz.bustorino.middleware.*;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+
+/**
+ * Helper class to manage the fragments and their needs
+ */
+public class FragmentHelper {
+ GeneralActivity act;
+ private Stop lastSuccessfullySearchedBusStop;
+ //support for multiple frames
+ private int primaryFrameLayout,secondaryFrameLayout, swipeRefID;
+ public static final int NO_FRAME = -3;
+ private WeakReference<AsyncDataDownload> lastTaskRef;
+ private NextGenDB newDBHelper;
+ private boolean shouldHaltAllActivities=false;
+
+
+ public FragmentHelper(GeneralActivity act, int swipeRefID, int mainFrame) {
+ this(act,swipeRefID,mainFrame,NO_FRAME);
+ }
+
+ public FragmentHelper(GeneralActivity act, int swipeRefID, int primaryFrameLayout, int secondaryFrameLayout) {
+ this.act = act;
+ this.swipeRefID = swipeRefID;
+ this.primaryFrameLayout = primaryFrameLayout;
+ this.secondaryFrameLayout = secondaryFrameLayout;
+ newDBHelper = NextGenDB.getInstance(act.getApplicationContext());
+ }
+
+ /**
+ * Get the last successfully searched bus stop or NULL
+ *
+ * @return
+ */
+ public Stop getLastSuccessfullySearchedBusStop() {
+ return lastSuccessfullySearchedBusStop;
+ }
+
+ public void setLastSuccessfullySearchedBusStop(Stop stop) {
+ this.lastSuccessfullySearchedBusStop = stop;
+ }
+
+ public void setLastTaskRef(WeakReference<AsyncDataDownload> lastTaskRef) {
+ this.lastTaskRef = lastTaskRef;
+ }
+
+ /**
+ * Called when you need to create a fragment for a specified Palina
+ * @param p the Stop that needs to be displayed
+ */
+ public void createOrUpdateStopFragment(Palina p){
+ boolean sameFragment;
+ ArrivalsFragment arrivalsFragment;
+
+ if(act==null || shouldHaltAllActivities) {
+ //SOMETHING WENT VERY WRONG
+ return;
+ }
+
+ SwipeRefreshLayout srl = (SwipeRefreshLayout) act.findViewById(swipeRefID);
+ FragmentManager fm = act.getSupportFragmentManager();
+
+ if(fm.findFragmentById(R.id.resultFrame) instanceof ArrivalsFragment) {
+ arrivalsFragment = (ArrivalsFragment) fm.findFragmentById(R.id.resultFrame);
+ sameFragment = arrivalsFragment.isFragmentForTheSameStop(p);
+ } else
+ sameFragment = false;
+
+ setLastSuccessfullySearchedBusStop(p);
+
+ if(!sameFragment) {
+ //set the String to be displayed on the fragment
+ String displayName = p.getStopDisplayName();
+ String displayStuff;
+
+ if (displayName != null && displayName.length() > 0) {
+ arrivalsFragment = ArrivalsFragment.newInstance(p.ID,displayName);
+ } else {
+ arrivalsFragment = ArrivalsFragment.newInstance(p.ID);
+ }
+ attachFragmentToContainer(fm,arrivalsFragment,true,ResultListFragment.getFragmentTag(p));
+ } else {
+ Log.d("BusTO", "Same bus stop, accessing existing fragment");
+ arrivalsFragment = (ArrivalsFragment) fm.findFragmentById(R.id.resultFrame);
+ }
+
+ arrivalsFragment.setListAdapter(new PalinaAdapter(act.getApplicationContext(),p));
+ act.hideKeyboard();
+ toggleSpinner(false);
+ }
+
+ /**
+ * Called when you need to display the results of a search of stops
+ * @param resultList the List of stops found
+ * @param query String queried
+ */
+ public void createFragmentFor(List<Stop> resultList,String query){
+ act.hideKeyboard();
+ StopListFragment listfragment = StopListFragment.newInstance(query);
+ attachFragmentToContainer(act.getSupportFragmentManager(),listfragment,false,"search_"+query);
+ listfragment.setStopList(resultList);
+ toggleSpinner(false);
+
+ }
+
+ /**
+ * Wrapper for toggleSpinner in Activity
+ * @param on new status of spinner system
+ */
+ public void toggleSpinner(boolean on){
+ if (act instanceof FragmentListener)
+ ((FragmentListener) act).toggleSpinner(on);
+ else {
+ SwipeRefreshLayout srl = (SwipeRefreshLayout) act.findViewById(swipeRefID);
+ srl.setRefreshing(false);
+ }
+ }
+
+ /**
+ * Attach a new fragment to a cointainer
+ * @param fm the FragmentManager
+ * @param fragment the Fragment
+ * @param sendToSecondaryFrame needs to be displayed in secondary frame or not
+ * @param tag tag for the fragment
+ */
+ public void attachFragmentToContainer(FragmentManager fm,Fragment fragment, boolean sendToSecondaryFrame, String tag){
+ FragmentTransaction ft = fm.beginTransaction();
+ if(sendToSecondaryFrame && secondaryFrameLayout!=NO_FRAME)
+ ft.replace(secondaryFrameLayout,fragment,tag);
+ else ft.replace(primaryFrameLayout,fragment,tag);
+ ft.addToBackStack("state_"+tag);
+ ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
+ ft.commit();
+ //fm.executePendingTransactions();
+ }
+
+ synchronized public int insertBatchDataInNextGenDB(ContentValues[] valuesArr,String tableName){
+ if(newDBHelper !=null)
+ try {
+ return newDBHelper.insertBatchContent(valuesArr, tableName);
+ } catch (SQLiteException exc){
+ Log.w("DB Batch inserting: ","ERROR Inserting the data batch: ",exc.fillInStackTrace());
+ return -2;
+ }
+ else return -1;
+ }
+
+ synchronized public ContentResolver getContentResolver(){
+ return act.getContentResolver();
+ }
+
+ public void setBlockAllActivities(boolean shouldI) {
+ this.shouldHaltAllActivities = shouldI;
+ }
+
+ public void stopLastRequestIfNeeded(){
+ if(lastTaskRef == null) return;
+ AsyncDataDownload task = lastTaskRef.get();
+ if(task!=null){
+ task.cancel(true);
+ }
+ }
+
+ /**
+ * Wrapper to show the errors/status that happened
+ * @param res result from Fetcher
+ */
+ public void showErrorMessage(Fetcher.result res){
+ //TODO: implement a common set of errors for all fragments
+ switch (res){
+ case OK:
+ break;
+ case CLIENT_OFFLINE:
+ act.showMessage(R.string.network_error);
+ break;
+ case SERVER_ERROR:
+ if (act.isConnected()) {
+ act.showMessage(R.string.parsing_error);
+ } else {
+ act.showMessage(R.string.network_error);
+ }
+ case PARSER_ERROR:
+ default:
+ act.showMessage(R.string.internal_error);
+ break;
+ case QUERY_TOO_SHORT:
+ act.showMessage(R.string.query_too_short);
+ break;
+ case EMPTY_RESULT_SET:
+ act.showMessage(R.string.no_bus_stop_have_this_name);
+ break;
+ }
+ }
+
+}
diff --git a/src/it/reyboz/bustorino/fragments/FragmentListener.java b/src/it/reyboz/bustorino/fragments/FragmentListener.java
--- a/src/it/reyboz/bustorino/fragments/FragmentListener.java
+++ b/src/it/reyboz/bustorino/fragments/FragmentListener.java
@@ -1,72 +1,72 @@
-/*
- BusTO - Fragments components
- Copyright (C) 2018 Fabio Mazza
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package it.reyboz.bustorino.fragments;
-
-import it.reyboz.bustorino.backend.Stop;
-
-public interface FragmentListener {
- void toggleSpinner(boolean state);
- /**
- * Sends the message to the activity to adapt the GUI
- * to the fragment that has been attached
- * @param fragmentType the type of fragment attached
- */
- void readyGUIfor(FragmentKind fragmentType);
- /**
- * Houston, we need another fragment!
- *
- * @param ID the Stop ID
- */
- void createFragmentForStop(String ID);
-
- /**
- * Add the last successfully searched stop to the favorites
- */
- void toggleLastStopToFavorites();
-
- /**
- * Get the last successfully searched bus stop or NULL
- *
- * @return
- */
- Stop getLastSuccessfullySearchedBusStop();
-
- /**
- * Get the last successfully searched bus stop ID or NULL
- *
- * @return
- */
- String getLastSuccessfullySearchedBusStopID();
-
- /**
- * Automatically update the "Add to favorite" star icon
- */
- void updateStarIconFromLastBusStop();
-
- /**
- * Tell the activity that we need to disable/enable its floatingActionButton
- * @param yes or no
- */
- void showFloatingActionButton(boolean yes);
-
- /**
- * Tell activity that we need to enable/disable the refreshLayout
- * @param yes or no
- */
- void enableRefreshLayout(boolean yes);
-}
+/*
+ BusTO - Fragments components
+ Copyright (C) 2018 Fabio Mazza
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package it.reyboz.bustorino.fragments;
+
+import it.reyboz.bustorino.backend.Stop;
+
+public interface FragmentListener {
+ void toggleSpinner(boolean state);
+ /**
+ * Sends the message to the activity to adapt the GUI
+ * to the fragment that has been attached
+ * @param fragmentType the type of fragment attached
+ */
+ void readyGUIfor(FragmentKind fragmentType);
+ /**
+ * Houston, we need another fragment!
+ *
+ * @param ID the Stop ID
+ */
+ void createFragmentForStop(String ID);
+
+ /**
+ * Add the last successfully searched stop to the favorites
+ */
+ void toggleLastStopToFavorites();
+
+ /**
+ * Get the last successfully searched bus stop or NULL
+ *
+ * @return
+ */
+ Stop getLastSuccessfullySearchedBusStop();
+
+ /**
+ * Get the last successfully searched bus stop ID or NULL
+ *
+ * @return
+ */
+ String getLastSuccessfullySearchedBusStopID();
+
+ /**
+ * Automatically update the "Add to favorite" star icon
+ */
+ void updateStarIconFromLastBusStop();
+
+ /**
+ * Tell the activity that we need to disable/enable its floatingActionButton
+ * @param yes or no
+ */
+ void showFloatingActionButton(boolean yes);
+
+ /**
+ * Tell activity that we need to enable/disable the refreshLayout
+ * @param yes or no
+ */
+ void enableRefreshLayout(boolean yes);
+}
diff --git a/src/it/reyboz/bustorino/fragments/ResultListFragment.java b/src/it/reyboz/bustorino/fragments/ResultListFragment.java
--- a/src/it/reyboz/bustorino/fragments/ResultListFragment.java
+++ b/src/it/reyboz/bustorino/fragments/ResultListFragment.java
@@ -1,294 +1,314 @@
-/*
- BusTO - Fragments components
- Copyright (C) 2016 Fabio Mazza
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-package it.reyboz.bustorino.fragments;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.support.annotation.Nullable;
-import android.support.v4.app.Fragment;
-import android.support.v4.widget.SwipeRefreshLayout;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import android.widget.*;
-import android.support.design.widget.FloatingActionButton;
-
-import it.reyboz.bustorino.R;
-import it.reyboz.bustorino.backend.FiveTNormalizer;
-import it.reyboz.bustorino.backend.Palina;
-import it.reyboz.bustorino.backend.Route;
-import it.reyboz.bustorino.backend.Stop;
-
-/**
- * This is a generalized fragment that can be used both for
- *
- *
- */
-public class ResultListFragment extends Fragment{
- // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
- static final String LIST_TYPE = "list-type";
- private static final String STOP_TITLE = "messageExtra";
- protected static final String LIST_STATE = "list_state";
-
-
- private static final String MESSAGE_TEXT_VIEW = "message_text_view";
- private FragmentKind adapterKind;
-
- private boolean adapterSet = false;
- protected FragmentListener mListener;
- private TextView messageTextView;
-
- private FloatingActionButton fabutton;
- private ListView resultsListView;
- private ListAdapter mListAdapter = null;
- boolean listShown;
- private Parcelable mListInstanceState = null;
-
- public ResultListFragment() {
- // Required empty public constructor
- }
-
- public ListView getResultsListView() {
- return resultsListView;
- }
-
- /**
- * Use this factory method to create a new instance of
- * this fragment using the provided parameters.
- *
- * @param listType whether the list is used for STOPS or LINES (Orari)
- * @return A new instance of fragment ResultListFragment.
- */
- public static ResultListFragment newInstance(FragmentKind listType, String eventualStopTitle) {
- ResultListFragment fragment = new ResultListFragment();
- Bundle args = new Bundle();
- args.putSerializable(LIST_TYPE, listType);
- if (eventualStopTitle != null) {
- args.putString(STOP_TITLE, eventualStopTitle);
- }
- fragment.setArguments(args);
- return fragment;
- }
-
- public static ResultListFragment newInstance(FragmentKind listType) {
- return newInstance(listType, null);
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (getArguments() != null) {
- adapterKind = (FragmentKind) getArguments().getSerializable(LIST_TYPE);
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View root = inflater.inflate(R.layout.fragment_list_view, container, false);
- messageTextView = (TextView) root.findViewById(R.id.messageTextView);
-
- if (adapterKind != null) {
- resultsListView = (ListView) root.findViewById(R.id.resultsListView);
- switch (adapterKind) {
- case STOPS:
- resultsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- /*
- * Casting because of Javamerda
- * @url http://stackoverflow.com/questions/30549485/androids-list-view-parameterized-type-in-adapterview-onitemclicklistener
- */
- Stop busStop = (Stop) parent.getItemAtPosition(position);
- mListener.createFragmentForStop(busStop.ID);
- }
- });
-
- //set the textviewMessage
- setTextViewMessage(getString(R.string.results));
- break;
- case ARRIVALS:
- resultsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- String routeName;
-
- Route r = (Route) parent.getItemAtPosition(position);
- routeName = FiveTNormalizer.routeInternalToDisplay(r.getNameForDisplay());
- if (routeName == null) {
- routeName = r.getNameForDisplay();
- }
- if (r.destinazione == null || r.destinazione.length() == 0) {
- Toast.makeText(getContext(),
- getString(R.string.route_towards_unknown, routeName), Toast.LENGTH_SHORT).show();
- } else {
- Toast.makeText(getContext(),
- getString(R.string.route_towards_destination, routeName, r.destinazione), Toast.LENGTH_SHORT).show();
- }
- }
- });
- String displayName = getArguments().getString(STOP_TITLE);
- setTextViewMessage(String.format(
- getString(R.string.passages), displayName));
- break;
- default:
- throw new IllegalStateException("Argument passed was not of a supported type");
- }
-
- String probablemessage = getArguments().getString(MESSAGE_TEXT_VIEW);
- if (probablemessage != null) {
- //Log.d("BusTO fragment " + this.getTag(), "We have a possible message here in the savedInstaceState: " + probablemessage);
- messageTextView.setText(probablemessage);
- messageTextView.setVisibility(View.VISIBLE);
- }
-
- } else
- Log.d(getString(R.string.list_fragment_debug), "No content root for fragment");
- return root;
- }
-
- public boolean isFragmentForTheSameStop(Palina p) {
- return adapterKind.equals(FragmentKind.ARRIVALS) && getTag().equals(getFragmentTag(p));
- }
-
- public static String getFragmentTag(Palina p) {
- return p.ID;
- }
-
-
- @Override
- public void onResume() {
- super.onResume();
- //Log.d(getString(R.string.list_fragment_debug),"Fragment restored, saved listAdapter is "+(mListAdapter));
- if (mListAdapter != null) {
-
- ListAdapter adapter = mListAdapter;
- mListAdapter = null;
- setListAdapter(adapter);
- }
- if (mListInstanceState != null) {
- Log.d("resultsListView", "trying to restore instance state");
- resultsListView.onRestoreInstanceState(mListInstanceState);
- }
- switch (adapterKind) {
- case ARRIVALS:
- resultsListView.setOnScrollListener(new CommonScrollListener(mListener, true));
- fabutton.show();
- break;
- case STOPS:
- resultsListView.setOnScrollListener(new CommonScrollListener(mListener, false));
- break;
- default:
- //NONE
- }
- mListener.readyGUIfor(adapterKind);
-
- }
-
- @Override
- public void onPause() {
- if (adapterKind.equals(FragmentKind.ARRIVALS)) {
- SwipeRefreshLayout reflay = (SwipeRefreshLayout) getActivity().findViewById(R.id.listRefreshLayout);
- reflay.setEnabled(false);
- Log.d("BusTO Fragment " + this.getTag(), "RefreshLayout disabled");
- }
- super.onPause();
- }
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- if (context instanceof FragmentListener) {
- mListener = (FragmentListener) context;
- fabutton = (FloatingActionButton) getActivity().findViewById(R.id.floatingActionButton);
- } else {
- throw new RuntimeException(context.toString()
- + " must implement ResultFragmentListener");
- }
-
- }
-
-
- @Override
- public void onDetach() {
- mListener = null;
- if (fabutton != null)
- fabutton.show();
- super.onDetach();
- }
-
-
- @Override
- public void onDestroyView() {
- resultsListView = null;
- //Log.d(getString(R.string.list_fragment_debug), "called onDestroyView");
- getArguments().putString(MESSAGE_TEXT_VIEW, messageTextView.getText().toString());
- super.onDestroyView();
- }
-
-
- @Override
- public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
- super.onViewStateRestored(savedInstanceState);
- Log.d("ResultListFragment", "onViewStateRestored");
- if (savedInstanceState != null) {
- mListInstanceState = savedInstanceState.getParcelable(LIST_STATE);
- Log.d("ResultListFragment", "listInstanceStatePresent :" + mListInstanceState);
- }
- }
-
- public void setListAdapter(ListAdapter adapter) {
- boolean hadAdapter = mListAdapter != null;
- mListAdapter = adapter;
- if (resultsListView != null) {
- resultsListView.setAdapter(adapter);
- resultsListView.setVisibility(View.VISIBLE);
- }
- }
-
- /**
- * Set the message textView
- * @param message the whole message to write in the textView
- */
- public void setTextViewMessage(String message) {
- messageTextView.setText(message);
- switch (adapterKind) {
- case ARRIVALS:
- messageTextView.setClickable(true);
- messageTextView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // add/remove the stop in the favorites
- mListener.toggleLastStopToFavorites();
- }
- });
- break;
- case STOPS:
- messageTextView.setClickable(false);
- break;
- }
-
- messageTextView.setVisibility(View.VISIBLE);
- }
-}
+/*
+ BusTO - Fragments components
+ Copyright (C) 2016 Fabio Mazza
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+package it.reyboz.bustorino.fragments;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import android.widget.*;
+import android.support.design.widget.FloatingActionButton;
+
+import it.reyboz.bustorino.R;
+import it.reyboz.bustorino.backend.FiveTNormalizer;
+import it.reyboz.bustorino.backend.Palina;
+import it.reyboz.bustorino.backend.Route;
+import it.reyboz.bustorino.backend.Stop;
+import it.reyboz.bustorino.middleware.UserDB;
+
+/**
+ * This is a generalized fragment that can be used both for
+ *
+ *
+ */
+public class ResultListFragment extends Fragment{
+ // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
+ static final String LIST_TYPE = "list-type";
+ private static final String STOP_TITLE = "messageExtra";
+ protected static final String LIST_STATE = "list_state";
+
+
+ private static final String MESSAGE_TEXT_VIEW = "message_text_view";
+ private FragmentKind adapterKind;
+
+ private boolean adapterSet = false;
+ protected FragmentListener mListener;
+ private TextView messageTextView;
+ private ImageButton addToFavorites;
+
+ private FloatingActionButton fabutton;
+ private ListView resultsListView;
+ private ListAdapter mListAdapter = null;
+ boolean listShown;
+ private Parcelable mListInstanceState = null;
+
+ public ResultListFragment() {
+ // Required empty public constructor
+ }
+
+ public ListView getResultsListView() {
+ return resultsListView;
+ }
+
+ /**
+ * Use this factory method to create a new instance of
+ * this fragment using the provided parameters.
+ *
+ * @param listType whether the list is used for STOPS or LINES (Orari)
+ * @return A new instance of fragment ResultListFragment.
+ */
+ public static ResultListFragment newInstance(FragmentKind listType, String eventualStopTitle) {
+ ResultListFragment fragment = new ResultListFragment();
+ Bundle args = new Bundle();
+ args.putSerializable(LIST_TYPE, listType);
+ if (eventualStopTitle != null) {
+ args.putString(STOP_TITLE, eventualStopTitle);
+ }
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ public static ResultListFragment newInstance(FragmentKind listType) {
+ return newInstance(listType, null);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getArguments() != null) {
+ adapterKind = (FragmentKind) getArguments().getSerializable(LIST_TYPE);
+ }
+ }
+
+ /**
+ * Check if the last Bus Stop is in the favorites
+ * @return
+ */
+ public boolean isStopInFavorites(String busStopId) {
+ boolean found = false;
+
+ // no stop no party
+ if(busStopId != null) {
+ SQLiteDatabase userDB = new UserDB(getContext()).getReadableDatabase();
+ found = UserDB.isStopInFavorites(userDB, busStopId);
+ }
+
+ return found;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View root = inflater.inflate(R.layout.fragment_list_view, container, false);
+ messageTextView = (TextView) root.findViewById(R.id.messageTextView);
+ addToFavorites = (ImageButton) root.findViewById(R.id.addToFavorites);
+ if (adapterKind != null) {
+ resultsListView = (ListView) root.findViewById(R.id.resultsListView);
+ switch (adapterKind) {
+ case STOPS:
+ resultsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ /*
+ * Casting because of Javamerda
+ * @url http://stackoverflow.com/questions/30549485/androids-list-view-parameterized-type-in-adapterview-onitemclicklistener
+ */
+ Stop busStop = (Stop) parent.getItemAtPosition(position);
+ mListener.createFragmentForStop(busStop.ID);
+ }
+ });
+
+ //set the textviewMessage
+ setTextViewMessage(getString(R.string.results));
+ break;
+ case ARRIVALS:
+ resultsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ String routeName;
+
+ Route r = (Route) parent.getItemAtPosition(position);
+ routeName = FiveTNormalizer.routeInternalToDisplay(r.getNameForDisplay());
+ if (routeName == null) {
+ routeName = r.getNameForDisplay();
+ }
+ if (r.destinazione == null || r.destinazione.length() == 0) {
+ Toast.makeText(getContext(),
+ getString(R.string.route_towards_unknown, routeName), Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(getContext(),
+ getString(R.string.route_towards_destination, routeName, r.destinazione), Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+ String displayName = getArguments().getString(STOP_TITLE);
+ setTextViewMessage(String.format(
+ getString(R.string.passages), displayName));
+ break;
+ default:
+ throw new IllegalStateException("Argument passed was not of a supported type");
+ }
+
+ String probablemessage = getArguments().getString(MESSAGE_TEXT_VIEW);
+ if (probablemessage != null) {
+ //Log.d("BusTO fragment " + this.getTag(), "We have a possible message here in the savedInstaceState: " + probablemessage);
+ messageTextView.setText(probablemessage);
+ messageTextView.setVisibility(View.VISIBLE);
+ }
+
+ } else
+ Log.d(getString(R.string.list_fragment_debug), "No content root for fragment");
+ return root;
+ }
+
+ public boolean isFragmentForTheSameStop(Palina p) {
+ return adapterKind.equals(FragmentKind.ARRIVALS) && getTag().equals(getFragmentTag(p));
+ }
+
+ public static String getFragmentTag(Palina p) {
+ return p.ID;
+ }
+
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ //Log.d(getString(R.string.list_fragment_debug),"Fragment restored, saved listAdapter is "+(mListAdapter));
+ if (mListAdapter != null) {
+
+ ListAdapter adapter = mListAdapter;
+ mListAdapter = null;
+ setListAdapter(adapter);
+ }
+ if (mListInstanceState != null) {
+ Log.d("resultsListView", "trying to restore instance state");
+ resultsListView.onRestoreInstanceState(mListInstanceState);
+ }
+ switch (adapterKind) {
+ case ARRIVALS:
+ resultsListView.setOnScrollListener(new CommonScrollListener(mListener, true));
+ fabutton.show();
+ break;
+ case STOPS:
+ resultsListView.setOnScrollListener(new CommonScrollListener(mListener, false));
+ break;
+ default:
+ //NONE
+ }
+ mListener.readyGUIfor(adapterKind);
+
+ }
+
+ @Override
+ public void onPause() {
+ if (adapterKind.equals(FragmentKind.ARRIVALS)) {
+ SwipeRefreshLayout reflay = (SwipeRefreshLayout) getActivity().findViewById(R.id.listRefreshLayout);
+ reflay.setEnabled(false);
+ Log.d("BusTO Fragment " + this.getTag(), "RefreshLayout disabled");
+ }
+ super.onPause();
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (context instanceof FragmentListener) {
+ mListener = (FragmentListener) context;
+ fabutton = (FloatingActionButton) getActivity().findViewById(R.id.floatingActionButton);
+ } else {
+ throw new RuntimeException(context.toString()
+ + " must implement ResultFragmentListener");
+ }
+
+ }
+
+
+ @Override
+ public void onDetach() {
+ mListener = null;
+ if (fabutton != null)
+ fabutton.show();
+ super.onDetach();
+ }
+
+
+ @Override
+ public void onDestroyView() {
+ resultsListView = null;
+ //Log.d(getString(R.string.list_fragment_debug), "called onDestroyView");
+ getArguments().putString(MESSAGE_TEXT_VIEW, messageTextView.getText().toString());
+ super.onDestroyView();
+ }
+
+
+ @Override
+ public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
+ super.onViewStateRestored(savedInstanceState);
+ Log.d("ResultListFragment", "onViewStateRestored");
+ if (savedInstanceState != null) {
+ mListInstanceState = savedInstanceState.getParcelable(LIST_STATE);
+ Log.d("ResultListFragment", "listInstanceStatePresent :" + mListInstanceState);
+ }
+ }
+
+ public void setListAdapter(ListAdapter adapter) {
+ boolean hadAdapter = mListAdapter != null;
+ mListAdapter = adapter;
+ if (resultsListView != null) {
+ resultsListView.setAdapter(adapter);
+ resultsListView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * Set the message textView
+ * @param message the whole message to write in the textView
+ */
+ public void setTextViewMessage(String message) {
+ messageTextView.setText(message);
+ switch (adapterKind) {
+ case ARRIVALS:
+ addToFavorites.setClickable(true);
+ addToFavorites.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // add/remove the stop in the favorites
+ mListener.toggleLastStopToFavorites();
+ }
+ });
+ break;
+ case STOPS:
+ addToFavorites.setClickable(false);
+ break;
+ }
+
+
+ messageTextView.setVisibility(View.VISIBLE);
+ }
+}
\ No newline at end of file
diff --git a/src/it/reyboz/bustorino/middleware/AsyncStopFavoriteAction.java b/src/it/reyboz/bustorino/middleware/AsyncStopFavoriteAction.java
--- a/src/it/reyboz/bustorino/middleware/AsyncStopFavoriteAction.java
+++ b/src/it/reyboz/bustorino/middleware/AsyncStopFavoriteAction.java
@@ -1,120 +1,120 @@
-/*
- BusTO - Middleware components
- Copyright (C) 2016 Fabio Mazza
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package it.reyboz.bustorino.middleware;
-
-import android.content.Context;
-import android.database.sqlite.SQLiteDatabase;
-import android.os.AsyncTask;
-import android.widget.Toast;
-import it.reyboz.bustorino.R;
-import it.reyboz.bustorino.backend.Stop;
-
-/**
- * Handler to add or remove or toggle a Stop in your favorites
- */
-public class AsyncStopFavoriteAction extends AsyncTask<Stop, Void, Boolean> {
- private Context context;
-
- /**
- * Kind of actions available
- */
- public enum Action { ADD, REMOVE, TOGGLE };
-
- /**
- * Action chosen
- *
- * Note that TOGGLE is not converted to ADD or REMOVE.
- */
- private Action action;
-
- /**
- * Constructor
- *
- * @param context
- * @param action
- */
- public AsyncStopFavoriteAction(Context context, Action action) {
- this.context = context.getApplicationContext();
- this.action = action;
- }
-
- @Override
- protected Boolean doInBackground(Stop... stops) {
- boolean result = false;
-
- Stop stop = stops[0];
-
- // check if the request has sense
- if(stop != null) {
-
- // get a writable database
- UserDB userDatabase = new UserDB(context);
- SQLiteDatabase db = userDatabase.getWritableDatabase();
-
- // eventually toggle the status
- if(Action.TOGGLE.equals(action)) {
- if(UserDB.isStopInFavorites(db, stop.ID)) {
- action = Action.REMOVE;
- } else {
- action = Action.ADD;
- }
- }
-
- // at this point the action is just ADD or REMOVE
-
- // add or remove?
- if(Action.ADD.equals(action)) {
- // add
- result = UserDB.addOrUpdateStop(stop, db);
- } else {
- // remove
- result = UserDB.deleteStop(stop, db);
- }
-
- // please sir, close the door
- db.close();
- }
-
- return result;
- }
-
- /**
- * Callback fired when everything was done
- *
- * @param result
- */
- @Override
- protected void onPostExecute(Boolean result) {
- super.onPostExecute(result);
-
- if(result) {
- // at this point the action should be just ADD or REMOVE
- if(Action.ADD.equals(action)) {
- // now added
- Toast.makeText(this.context, R.string.added_in_favorites, Toast.LENGTH_SHORT).show();
- } else {
- // now removed
- Toast.makeText(this.context, R.string.removed_from_favorites, Toast.LENGTH_SHORT).show();
- }
- } else {
- // wtf
- Toast.makeText(this.context, R.string.cant_add_to_favorites, Toast.LENGTH_SHORT).show();
- }
- }
-}
+/*
+ BusTO - Middleware components
+ Copyright (C) 2016 Fabio Mazza
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package it.reyboz.bustorino.middleware;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.AsyncTask;
+import android.widget.Toast;
+import it.reyboz.bustorino.R;
+import it.reyboz.bustorino.backend.Stop;
+
+/**
+ * Handler to add or remove or toggle a Stop in your favorites
+ */
+public class AsyncStopFavoriteAction extends AsyncTask<Stop, Void, Boolean> {
+ private Context context;
+
+ /**
+ * Kind of actions available
+ */
+ public enum Action { ADD, REMOVE, TOGGLE };
+
+ /**
+ * Action chosen
+ *
+ * Note that TOGGLE is not converted to ADD or REMOVE.
+ */
+ private Action action;
+
+ /**
+ * Constructor
+ *
+ * @param context
+ * @param action
+ */
+ public AsyncStopFavoriteAction(Context context, Action action) {
+ this.context = context.getApplicationContext();
+ this.action = action;
+ }
+
+ @Override
+ protected Boolean doInBackground(Stop... stops) {
+ boolean result = false;
+
+ Stop stop = stops[0];
+
+ // check if the request has sense
+ if(stop != null) {
+
+ // get a writable database
+ UserDB userDatabase = new UserDB(context);
+ SQLiteDatabase db = userDatabase.getWritableDatabase();
+
+ // eventually toggle the status
+ if(Action.TOGGLE.equals(action)) {
+ if(UserDB.isStopInFavorites(db, stop.ID)) {
+ action = Action.REMOVE;
+ } else {
+ action = Action.ADD;
+ }
+ }
+
+ // at this point the action is just ADD or REMOVE
+
+ // add or remove?
+ if(Action.ADD.equals(action)) {
+ // add
+ result = UserDB.addOrUpdateStop(stop, db);
+ } else {
+ // remove
+ result = UserDB.deleteStop(stop, db);
+ }
+
+ // please sir, close the door
+ db.close();
+ }
+
+ return result;
+ }
+
+ /**
+ * Callback fired when everything was done
+ *
+ * @param result
+ */
+ @Override
+ protected void onPostExecute(Boolean result) {
+ super.onPostExecute(result);
+
+ if(result) {
+ // at this point the action should be just ADD or REMOVE
+ if(Action.ADD.equals(action)) {
+ // now added
+ Toast.makeText(this.context, R.string.added_in_favorites, Toast.LENGTH_SHORT).show();
+ } else {
+ // now removed
+ Toast.makeText(this.context, R.string.removed_from_favorites, Toast.LENGTH_SHORT).show();
+ }
+ } else {
+ // wtf
+ Toast.makeText(this.context, R.string.cant_add_to_favorites, Toast.LENGTH_SHORT).show();
+ }
+ }
+}
diff --git a/src/it/reyboz/bustorino/middleware/UserDB.java b/src/it/reyboz/bustorino/middleware/UserDB.java
--- a/src/it/reyboz/bustorino/middleware/UserDB.java
+++ b/src/it/reyboz/bustorino/middleware/UserDB.java
@@ -1,274 +1,274 @@
-/*
- BusTO ("backend" components)
- Copyright (C) 2016 Ludovico Pavesi
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package it.reyboz.bustorino.middleware;
-
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteException;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.content.Context;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import it.reyboz.bustorino.backend.Stop;
-import it.reyboz.bustorino.backend.StopsDBInterface;
-
-public class UserDB extends SQLiteOpenHelper {
- public static final int DATABASE_VERSION = 1;
- private static final String DATABASE_NAME = "user.db";
- static final String TABLE_NAME = "favorites";
- private final Context c; // needed during upgrade
- private final static String[] usernameColumnNameAsArray = {"username"};
- public final static String[] getFavoritesColumnNamesAsArray = {"ID", "username"};
-
- public UserDB(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- this.c = context;
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- // exception intentionally left unhandled
- db.execSQL("CREATE TABLE favorites (ID TEXT PRIMARY KEY NOT NULL, username TEXT)");
-
- if(OldDB.doesItExist(this.c)) {
- upgradeFromOldDatabase(db);
- }
- }
-
- private void upgradeFromOldDatabase(SQLiteDatabase newdb) {
- OldDB old;
- try {
- old = new OldDB(this.c);
- } catch(IllegalStateException e) {
- // can't create database => it doesn't really exist, no matter what doesItExist() says
- return;
- }
-
- int ver = old.getOldVersion();
-
- /* version 8 was the previous version, OldDB "upgrades" itself to 1337 but unless the app
- * has crashed midway through the upgrade and the user is retrying, that should never show
- * up here. And if it does, try to recover favorites anyway.
- * Versions < 8 already got dropped during the update process, so let's do the same.
- *
- * Edit: Android runs getOldVersion() then, after a while, onUpgrade(). Just to make it
- * more complicated. Workaround added in OldDB.
- */
- if(ver >= 8) {
- ArrayList<String> ID = new ArrayList<>();
- ArrayList<String> username = new ArrayList<>();
- int len;
- int len2;
-
- try {
- Cursor c = old.getReadableDatabase().rawQuery("SELECT busstop_ID, busstop_username FROM busstop WHERE busstop_isfavorite = 1 ORDER BY busstop_name ASC", new String[] {});
-
- int zero = c.getColumnIndex("busstop_ID");
- int one = c.getColumnIndex("busstop_username");
-
- while(c.moveToNext()) {
- try {
- ID.add(c.getString(zero));
- } catch(Exception e) {
- // no ID = can't add this
- continue;
- }
-
- if(c.getString(one) == null || c.getString(one).length() <= 0) {
- username.add(null);
- } else {
- username.add(c.getString(one));
- }
- }
-
- c.close();
- old.close();
- } catch(Exception ignored) {
- // there's no hope, go ahead and nuke old database.
- }
-
- len = ID.size();
- len2 = username.size();
- if(len2 < len) {
- len = len2;
- }
-
-
- if (len > 0) {
-
- try {
- Stop stopStopStopStopStop;
- for (int i = 0; i < len; i++) {
- stopStopStopStopStop = new Stop(ID.get(i));
- stopStopStopStopStop.setStopUserName(username.get(i));
- addOrUpdateStop(stopStopStopStopStop, newdb);
- }
- } catch(Exception ignored) {
- // partial data is better than no data at all, no transactions here
- }
- }
- }
-
- if(!OldDB.destroy(this.c)) {
- // TODO: notify user somehow?
- Log.e("UserDB", "Failed to delete old database, you should really uninstall and reinstall the app. Unfortunately I have no way to tell the user.");
- }
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- // nothing to do yet
- }
-
- @Override
- public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- // nothing to do yet
- }
-
- /**
- * Check if a stop ID is in the favorites
- *
- * @param db readable database
- * @param stopId stop ID
- * @return boolean
- */
- public static boolean isStopInFavorites(SQLiteDatabase db, String stopId) {
- boolean found = false;
-
- try {
- Cursor c = db.query(TABLE_NAME, usernameColumnNameAsArray, "ID = ?", new String[] {stopId}, null, null, null);
-
- if(c.moveToNext()) {
- found = true;
- }
-
- c.close();
- } catch(SQLiteException ignored) {
- // don't care
- }
-
- return found;
- }
-
- /**
- * Gets stop name set by the user.
- *
- * @param db readable database
- * @param stopID stop ID
- * @return name set by user, or null if not set\not found
- */
- public static String getStopUserName(SQLiteDatabase db, String stopID) {
- String username = null;
-
- try {
- Cursor c = db.query(TABLE_NAME, usernameColumnNameAsArray, "ID = ?", new String[] {stopID}, null, null, null);
-
- if(c.moveToNext()) {
- username = c.getString(c.getColumnIndex("username"));
- }
- c.close();
- } catch(SQLiteException ignored) {}
-
- return username;
- }
-
- public static List<Stop> getFavorites(SQLiteDatabase db, StopsDBInterface dbi) {
- List<Stop> l = new ArrayList<>();
- Stop s;
- String stopID, stopUserName;
-
- try {
- Cursor c = db.query(TABLE_NAME, getFavoritesColumnNamesAsArray, null, null, null, null, null, null);
- int colID = c.getColumnIndex("ID");
- int colUser = c.getColumnIndex("username");
-
- while(c.moveToNext()) {
- stopUserName = c.getString(colUser);
- stopID = c.getString(colID);
-
- s = dbi.getAllFromID(stopID);
-
- if(s == null) {
- // can't find it in database
- l.add(new Stop(stopUserName, stopID, null, null, null));
- } else {
- // setStopName() already does sanity checks
- s.setStopUserName(stopUserName);
- l.add(s);
- }
- }
-
- c.close();
- } catch(SQLiteException ignored) {}
-
- // comparison rules are too complicated to let SQLite do this (e.g. it outputs: 3234, 34, 576, 67, 8222) and stop name is in another database
- Collections.sort(l);
-
- return l;
- }
-
- public static boolean addOrUpdateStop(Stop s, SQLiteDatabase db) {
- ContentValues cv = new ContentValues();
- long result = -1;
- String un = s.getStopUserName();
-
- cv.put("ID", s.ID);
- // is there an username?
- if(un == null) {
- // no: see if it's in the database
- cv.put("username", getStopUserName(db, s.ID));
- } else {
- // yes: use it
- cv.put("username", un);
- }
-
- try {
- //ignore and throw -1 if the row is already in the DB
- result = db.insertWithOnConflict(TABLE_NAME, null, cv,SQLiteDatabase.CONFLICT_IGNORE);
- } catch (SQLiteException ignored) {}
-
- // Android Studio suggested this unreadable replacement: return true if insert succeeded (!= -1), or try to update and return
- return (result != -1) || updateStop(s, db);
- }
-
- public static boolean updateStop(Stop s, SQLiteDatabase db) {
- try {
- ContentValues cv = new ContentValues();
- cv.put("username", s.getStopUserName());
- db.update(TABLE_NAME, cv, "ID = ?", new String[]{s.ID});
- return true;
- } catch(SQLiteException e) {
- return false;
- }
- }
-
- public static boolean deleteStop(Stop s, SQLiteDatabase db) {
- try {
- db.delete(TABLE_NAME, "ID = ?", new String[]{s.ID});
- return true;
- } catch(SQLiteException e) {
- return false;
- }
- }
-}
+/*
+ BusTO ("backend" components)
+ Copyright (C) 2016 Ludovico Pavesi
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package it.reyboz.bustorino.middleware;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.content.Context;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import it.reyboz.bustorino.backend.Stop;
+import it.reyboz.bustorino.backend.StopsDBInterface;
+
+public class UserDB extends SQLiteOpenHelper {
+ public static final int DATABASE_VERSION = 1;
+ private static final String DATABASE_NAME = "user.db";
+ static final String TABLE_NAME = "favorites";
+ private final Context c; // needed during upgrade
+ private final static String[] usernameColumnNameAsArray = {"username"};
+ public final static String[] getFavoritesColumnNamesAsArray = {"ID", "username"};
+
+ public UserDB(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ this.c = context;
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ // exception intentionally left unhandled
+ db.execSQL("CREATE TABLE favorites (ID TEXT PRIMARY KEY NOT NULL, username TEXT)");
+
+ if(OldDB.doesItExist(this.c)) {
+ upgradeFromOldDatabase(db);
+ }
+ }
+
+ private void upgradeFromOldDatabase(SQLiteDatabase newdb) {
+ OldDB old;
+ try {
+ old = new OldDB(this.c);
+ } catch(IllegalStateException e) {
+ // can't create database => it doesn't really exist, no matter what doesItExist() says
+ return;
+ }
+
+ int ver = old.getOldVersion();
+
+ /* version 8 was the previous version, OldDB "upgrades" itself to 1337 but unless the app
+ * has crashed midway through the upgrade and the user is retrying, that should never show
+ * up here. And if it does, try to recover favorites anyway.
+ * Versions < 8 already got dropped during the update process, so let's do the same.
+ *
+ * Edit: Android runs getOldVersion() then, after a while, onUpgrade(). Just to make it
+ * more complicated. Workaround added in OldDB.
+ */
+ if(ver >= 8) {
+ ArrayList<String> ID = new ArrayList<>();
+ ArrayList<String> username = new ArrayList<>();
+ int len;
+ int len2;
+
+ try {
+ Cursor c = old.getReadableDatabase().rawQuery("SELECT busstop_ID, busstop_username FROM busstop WHERE busstop_isfavorite = 1 ORDER BY busstop_name ASC", new String[] {});
+
+ int zero = c.getColumnIndex("busstop_ID");
+ int one = c.getColumnIndex("busstop_username");
+
+ while(c.moveToNext()) {
+ try {
+ ID.add(c.getString(zero));
+ } catch(Exception e) {
+ // no ID = can't add this
+ continue;
+ }
+
+ if(c.getString(one) == null || c.getString(one).length() <= 0) {
+ username.add(null);
+ } else {
+ username.add(c.getString(one));
+ }
+ }
+
+ c.close();
+ old.close();
+ } catch(Exception ignored) {
+ // there's no hope, go ahead and nuke old database.
+ }
+
+ len = ID.size();
+ len2 = username.size();
+ if(len2 < len) {
+ len = len2;
+ }
+
+
+ if (len > 0) {
+
+ try {
+ Stop stopStopStopStopStop;
+ for (int i = 0; i < len; i++) {
+ stopStopStopStopStop = new Stop(ID.get(i));
+ stopStopStopStopStop.setStopUserName(username.get(i));
+ addOrUpdateStop(stopStopStopStopStop, newdb);
+ }
+ } catch(Exception ignored) {
+ // partial data is better than no data at all, no transactions here
+ }
+ }
+ }
+
+ if(!OldDB.destroy(this.c)) {
+ // TODO: notify user somehow?
+ Log.e("UserDB", "Failed to delete old database, you should really uninstall and reinstall the app. Unfortunately I have no way to tell the user.");
+ }
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // nothing to do yet
+ }
+
+ @Override
+ public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // nothing to do yet
+ }
+
+ /**
+ * Check if a stop ID is in the favorites
+ *
+ * @param db readable database
+ * @param stopId stop ID
+ * @return boolean
+ */
+ public static boolean isStopInFavorites(SQLiteDatabase db, String stopId) {
+ boolean found = false;
+
+ try {
+ Cursor c = db.query(TABLE_NAME, usernameColumnNameAsArray, "ID = ?", new String[] {stopId}, null, null, null);
+
+ if(c.moveToNext()) {
+ found = true;
+ }
+
+ c.close();
+ } catch(SQLiteException ignored) {
+ // don't care
+ }
+
+ return found;
+ }
+
+ /**
+ * Gets stop name set by the user.
+ *
+ * @param db readable database
+ * @param stopID stop ID
+ * @return name set by user, or null if not set\not found
+ */
+ public static String getStopUserName(SQLiteDatabase db, String stopID) {
+ String username = null;
+
+ try {
+ Cursor c = db.query(TABLE_NAME, usernameColumnNameAsArray, "ID = ?", new String[] {stopID}, null, null, null);
+
+ if(c.moveToNext()) {
+ username = c.getString(c.getColumnIndex("username"));
+ }
+ c.close();
+ } catch(SQLiteException ignored) {}
+
+ return username;
+ }
+
+ public static List<Stop> getFavorites(SQLiteDatabase db, StopsDBInterface dbi) {
+ List<Stop> l = new ArrayList<>();
+ Stop s;
+ String stopID, stopUserName;
+
+ try {
+ Cursor c = db.query(TABLE_NAME, getFavoritesColumnNamesAsArray, null, null, null, null, null, null);
+ int colID = c.getColumnIndex("ID");
+ int colUser = c.getColumnIndex("username");
+
+ while(c.moveToNext()) {
+ stopUserName = c.getString(colUser);
+ stopID = c.getString(colID);
+
+ s = dbi.getAllFromID(stopID);
+
+ if(s == null) {
+ // can't find it in database
+ l.add(new Stop(stopUserName, stopID, null, null, null));
+ } else {
+ // setStopName() already does sanity checks
+ s.setStopUserName(stopUserName);
+ l.add(s);
+ }
+ }
+
+ c.close();
+ } catch(SQLiteException ignored) {}
+
+ // comparison rules are too complicated to let SQLite do this (e.g. it outputs: 3234, 34, 576, 67, 8222) and stop name is in another database
+ Collections.sort(l);
+
+ return l;
+ }
+
+ public static boolean addOrUpdateStop(Stop s, SQLiteDatabase db) {
+ ContentValues cv = new ContentValues();
+ long result = -1;
+ String un = s.getStopUserName();
+
+ cv.put("ID", s.ID);
+ // is there an username?
+ if(un == null) {
+ // no: see if it's in the database
+ cv.put("username", getStopUserName(db, s.ID));
+ } else {
+ // yes: use it
+ cv.put("username", un);
+ }
+
+ try {
+ //ignore and throw -1 if the row is already in the DB
+ result = db.insertWithOnConflict(TABLE_NAME, null, cv,SQLiteDatabase.CONFLICT_IGNORE);
+ } catch (SQLiteException ignored) {}
+
+ // Android Studio suggested this unreadable replacement: return true if insert succeeded (!= -1), or try to update and return
+ return (result != -1) || updateStop(s, db);
+ }
+
+ public static boolean updateStop(Stop s, SQLiteDatabase db) {
+ try {
+ ContentValues cv = new ContentValues();
+ cv.put("username", s.getStopUserName());
+ db.update(TABLE_NAME, cv, "ID = ?", new String[]{s.ID});
+ return true;
+ } catch(SQLiteException e) {
+ return false;
+ }
+ }
+
+ public static boolean deleteStop(Stop s, SQLiteDatabase db) {
+ try {
+ db.delete(TABLE_NAME, "ID = ?", new String[]{s.ID});
+ return true;
+ } catch(SQLiteException e) {
+ return false;
+ }
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Mon, May 25, 17:58 (15 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1920813
Default Alt Text
D17.1779724709.diff (224 KB)

Event Timeline