diff --git a/build.gradle b/build.gradle
index 3b4be30..c2a20dd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,144 +1,145 @@
 buildscript {
     repositories {
         jcenter()
         maven { url 'https://maven.google.com' }
         google()
 
     }
 
     ext {
         //multidex
         multidex_version = "2.0.1"
         //libraries versions
         fragment_version = "1.3.6"
         activity_version = "1.3.1"
         appcompat_version = "1.3.1"
         preference_version = "1.1.1"
         work_version = "2.5.0"
 
         acra_version = "5.7.0"
         lifecycle_version = "2.3.1"
         arch_version = "2.1.0"
         room_version = "2.3.0"
         //kotlin
         kotlin_version = '1.6.0'
         coroutines_version = "1.5.0"
 
     }
     dependencies {
 
         classpath 'com.android.tools.build:gradle:4.1.3'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
     }
 }
 allprojects {
     repositories {
         jcenter()
         maven { url 'https://maven.google.com' }
         google()
         mavenCentral()
 
     }
 }
 
 apply plugin: 'com.android.application'
 apply plugin: 'kotlin-android'
 apply plugin: 'kotlin-kapt'
 
 android {
     compileSdkVersion 30
     buildToolsVersion '30.0.3'
 
     defaultConfig {
         applicationId "it.reyboz.bustorino"
         minSdkVersion 16
         targetSdkVersion 30
         versionCode 36
         versionName "1.16.0"
         vectorDrawables.useSupportLibrary = true
         multiDexEnabled 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 {
         //new libraries
         implementation "androidx.fragment:fragment:$fragment_version"
         implementation "androidx.activity:activity:$activity_version"
         implementation "androidx.annotation:annotation:1.2.0"
         implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
         implementation "androidx.appcompat:appcompat:$appcompat_version"
         implementation "androidx.appcompat:appcompat-resources:$appcompat_version"
         implementation "androidx.preference:preference:$preference_version"
         implementation "androidx.work:work-runtime:$work_version"
 
         implementation "com.google.android.material:material:1.4.0"
         implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
+        implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
 
 
         implementation 'org.jsoup:jsoup:1.13.1'
         implementation 'com.readystatesoftware.sqliteasset:sqliteassethelper:2.0.1'
         implementation 'com.android.volley:volley:1.2.1'
 
         implementation 'org.osmdroid:osmdroid-android:6.1.10'
         // ACRA
         implementation "ch.acra:acra-mail:$acra_version"
         implementation "ch.acra:acra-dialog:$acra_version"
         // google transit realtime
         implementation 'com.google.protobuf:protobuf-java:3.14.0'
 
         // ViewModel
         implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
         // LiveData
         implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
         // Lifecycles only (without ViewModel or LiveData)
         implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
 
         // Room components
         implementation "androidx.room:room-ktx:$room_version"
         kapt "androidx.room:room-compiler:$room_version"
         androidTestImplementation "androidx.room:room-testing:$room_version"
         //multidex - we need this to build the app
         implementation "androidx.multidex:multidex:$multidex_version"
 
         implementation 'de.siegmar:fastcsv:2.0.0'
 
     }
 }
 
 dependencies {
 
     implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
     api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
     api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
 }
diff --git a/res/layout/fragment_main_screen.xml b/res/layout/fragment_main_screen.xml
index 746319c..b4357aa 100644
--- a/res/layout/fragment_main_screen.xml
+++ b/res/layout/fragment_main_screen.xml
@@ -1,164 +1,177 @@
 <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              tools:context=".fragments.MainScreenFragment"
              android:paddingTop="10dip"
     >
 
     <ImageButton
             android:id="@+id/QRButton"
             style="?android:attr/borderlessButtonStyle"
             android:layout_width="30dip"
             android:layout_height="30dip"
             android:layout_alignBottom="@+id/searchButton"
             android:layout_alignParentLeft="true"
             android:layout_alignParentStart="true"
             android:layout_marginLeft="16dp"
             android:layout_marginStart="16dp"
             android:background="@drawable/qrcode_button_custom"
             android:contentDescription="@string/qrcode"
         />
 
     <EditText
             android:id="@+id/busStopSearchByIDEditText"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginEnd="5dp"
             android:layout_marginLeft="5dip"
             android:layout_marginRight="5dip"
             android:layout_toEndOf="@+id/QRButton"
             android:layout_toLeftOf="@+id/searchButton"
             android:layout_toRightOf="@+id/QRButton"
             android:layout_toStartOf="@+id/searchButton"
             android:ems="10"
             android:hint="@string/insert_bus_stop_number"
             android:imeOptions="actionSearch"
             android:inputType="number"
             android:selectAllOnFocus="true"
             android:singleLine="true"
     >
 
         <requestFocus />
     </EditText>
 
     <!--android:layout_alignParentLeft="true"
     android:layout_alignParentStart="true"-->
     <EditText
         android:id="@+id/busStopSearchByNameEditText"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginEnd="5dp"
         android:layout_marginLeft="5dip"
         android:layout_marginRight="5dip"
         android:layout_toEndOf="@+id/QRButton"
         android:layout_toLeftOf="@+id/searchButton"
         android:layout_toRightOf="@+id/QRButton"
         android:layout_toStartOf="@+id/searchButton"
-
+        android:inputType="text"
         android:ems="10"
         android:hint="@string/insert_bus_stop_name"
         android:imeOptions="actionSearch"
         android:singleLine="true"
         android:visibility="gone">
 
         <requestFocus />
     </EditText>
 
     <ImageButton
             android:id="@+id/searchButton"
             style="?android:attr/borderlessButtonStyle"
             android:layout_width="40dip"
             android:layout_height="40dip"
             android:layout_alignParentEnd="true"
             android:layout_alignParentRight="true"
             android:layout_alignTop="@+id/busStopSearchByIDEditText"
             android:layout_marginEnd="16dp"
             android:layout_marginRight="16dp"
             android:background="@drawable/search_button_custom"
             android:contentDescription="@string/search"
             />
 
     <ProgressBar
             android:id="@+id/progressBar"
             style="?android:attr/progressBarStyleHorizontal"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_alignParentEnd="true"
             android:layout_alignParentLeft="true"
             android:layout_alignParentRight="true"
             android:layout_alignParentStart="true"
             android:layout_below="@+id/searchButton"
             android:layout_marginEnd="16dp"
             android:layout_marginLeft="16dip"
             android:layout_marginRight="16dp"
             android:layout_marginStart="16dip"
             android:indeterminateOnly="true"
             android:visibility="gone" />
 
     <TextView
             android:id="@+id/howDoesItWorkTextView"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginBottom="10dp"
+            android:layout_marginBottom="5dp"
             android:layout_marginEnd="16dp"
             android:layout_marginLeft="16dip"
             android:layout_marginRight="16dp"
             android:layout_marginStart="16dip"
+            android:layout_marginTop="10dp"
             android:layout_toLeftOf="@+id/hideHintButton"
             android:layout_toStartOf="@+id/hideHintButton"
             android:text="@string/howDoesItWork"
             android:textAppearance="?android:attr/textAppearanceSmall"
             android:textColor="@color/blue_500"
             android:visibility="gone" android:layout_below="@+id/searchButton"/>
 
     <Button
             android:id="@+id/hideHintButton"
             style="?android:attr/buttonStyleSmall"
             android:layout_width="85dip"
             android:layout_height="wrap_content"
             android:layout_alignBottom="@+id/howDoesItWorkTextView"
             android:layout_alignParentEnd="true"
             android:layout_alignParentRight="true"
             android:layout_marginEnd="16dp"
             android:layout_marginRight="16dp"
             android:background="@drawable/route_background_bus"
             android:text="@string/hint_button"
             android:textColor="@color/grey_100"
             android:textSize="19sp"
             android:visibility="gone" />
 
-    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
-            android:id="@+id/listRefreshLayout"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_alignParentEnd="true"
-            android:layout_alignParentRight="true"
-            android:layout_below="@+id/howDoesItWorkTextView"
-            android:animateLayoutChanges="true"
-            android:visibility="gone">
 
-        <FrameLayout
-                android:layout_width="match_parent"
-                android:id="@+id/resultFrame"
-                android:layout_height="fill_parent"
-                android:layout_alignParentLeft="true" android:layout_alignParentStart="true"/>
-    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
-    <com.google.android.material.floatingactionbutton.FloatingActionButton
-            android:id="@+id/floatingActionButton"
-            android:layout_width="wrap_content"
+    <androidx.coordinatorlayout.widget.CoordinatorLayout
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:id="@+id/coord_layout"
             android:layout_alignParentBottom="true"
             android:layout_alignParentEnd="true"
             android:layout_alignParentRight="true"
             android:layout_gravity="bottom|end"
-            android:layout_margin="16dp"
-            android:src="@drawable/alphabetical"
-            fabSize="normal"
-            backgroundTint="@color/teal_500"
-            rippleColor="@color/teal_300"
-            elevation="15dp"
+            android:layout_below="@+id/howDoesItWorkTextView"
 
-    />
+    >
+        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+                android:id="@+id/listRefreshLayout"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_alignParentEnd="true"
+                android:layout_alignParentRight="true"
+                android:animateLayoutChanges="true"
+                android:visibility="gone">
+
+            <FrameLayout
+                    android:layout_width="match_parent"
+                    android:id="@+id/resultFrame"
+                    android:layout_height="fill_parent"
+                    android:layout_alignParentLeft="true" android:layout_alignParentStart="true"/>
+        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
+        <com.google.android.material.floatingactionbutton.FloatingActionButton
+                android:id="@+id/floatingActionButton"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentBottom="true"
+                android:layout_alignParentEnd="true"
+                android:layout_alignParentRight="true"
+                android:layout_gravity="bottom|end"
+                android:layout_margin="13dp"
+                android:src="@drawable/alphabetical"
+                fabSize="normal"
+                backgroundTint="@color/teal_500"
+                rippleColor="@color/teal_300"
+                elevation="13dp"
+
+        />
+    </androidx.coordinatorlayout.widget.CoordinatorLayout>
 </RelativeLayout>
\ No newline at end of file
diff --git a/src/it/reyboz/bustorino/ActivityPrincipal.java b/src/it/reyboz/bustorino/ActivityPrincipal.java
index 2cca929..5913140 100644
--- a/src/it/reyboz/bustorino/ActivityPrincipal.java
+++ b/src/it/reyboz/bustorino/ActivityPrincipal.java
@@ -1,590 +1,595 @@
 /*
 	BusTO - Arrival times for Turin public transport.
     Copyright (C) 2021 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;
 
 import android.Manifest;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.net.Uri;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 import android.widget.Toast;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.appcompat.app.ActionBarDrawerToggle;
 import androidx.appcompat.widget.Toolbar;
 import androidx.core.view.GravityCompat;
 import androidx.drawerlayout.widget.DrawerLayout;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
 import androidx.fragment.app.FragmentTransaction;
 import androidx.preference.PreferenceManager;
 import androidx.work.BackoffPolicy;
 import androidx.work.Constraints;
 import androidx.work.ExistingPeriodicWorkPolicy;
 import androidx.work.NetworkType;
 import androidx.work.PeriodicWorkRequest;
 import androidx.work.WorkInfo;
 import androidx.work.WorkManager;
 
 import com.google.android.material.navigation.NavigationView;
 import com.google.android.material.snackbar.Snackbar;
 
 import java.util.Arrays;
 import java.util.concurrent.TimeUnit;
 
 import it.reyboz.bustorino.backend.Stop;
 import it.reyboz.bustorino.data.DBUpdateWorker;
 import it.reyboz.bustorino.data.DatabaseUpdate;
-import it.reyboz.bustorino.fragments.FavoritesFragment;
-import it.reyboz.bustorino.fragments.FragmentKind;
-import it.reyboz.bustorino.fragments.FragmentListenerMain;
-import it.reyboz.bustorino.fragments.MainScreenFragment;
-import it.reyboz.bustorino.fragments.MapFragment;
+import it.reyboz.bustorino.fragments.*;
 import it.reyboz.bustorino.middleware.GeneralActivity;
 
 import static it.reyboz.bustorino.backend.utils.getBusStopIDFromUri;
 import static it.reyboz.bustorino.backend.utils.openIceweasel;
 
 public class ActivityPrincipal extends GeneralActivity implements FragmentListenerMain {
     private DrawerLayout mDrawer;
     private NavigationView mNavView;
     private ActionBarDrawerToggle drawerToggle;
     private final static String DEBUG_TAG="BusTO Act Principal";
 
     private final static String TAG_FAVORITES="favorites_frag";
     private Snackbar snackbar;
 
     private boolean showingMainFragmentFromOther = false;
 
 
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_principal);
         final SharedPreferences theShPr = getMainSharedPreferences();
 
 
         Toolbar mToolbar = findViewById(R.id.default_toolbar);
         setSupportActionBar(mToolbar);
         if (getSupportActionBar()!=null)
         getSupportActionBar().setDisplayHomeAsUpEnabled(true);
         else Log.w(DEBUG_TAG, "NO ACTION BAR");
 
         mToolbar.setOnMenuItemClickListener(new ToolbarItemClickListener(this));
 
 
         mDrawer = findViewById(R.id.drawer_layout);
         drawerToggle = setupDrawerToggle(mToolbar);
 
         // Setup toggle to display hamburger icon with nice animation
         drawerToggle.setDrawerIndicatorEnabled(true);
 
         drawerToggle.syncState();
         mDrawer.addDrawerListener(drawerToggle);
 
         mDrawer.addDrawerListener(new DrawerLayout.DrawerListener() {
             @Override
             public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
 
             }
 
             @Override
             public void onDrawerOpened(@NonNull View drawerView) {
                 hideKeyboard();
             }
 
             @Override
             public void onDrawerClosed(@NonNull View drawerView) {
 
             }
 
             @Override
             public void onDrawerStateChanged(int newState) {
             }
         });
 
 
         mNavView = findViewById(R.id.nvView);
 
         setupDrawerContent(mNavView);
         /*View header = mNavView.getHeaderView(0);
 
         */
         //mNavView.getMenu().findItem(R.id.versionFooter).
 
         /// LEGACY CODE
         //---------------------------- START INTENT CHECK QUEUE ------------------------------------
 
         // Intercept calls from URL intent
         boolean tryedFromIntent = false;
 
         String busStopID = 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");
 
-                /**
+                /*
                  * 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
                 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);
 
             requestArrivalsForStopID(busStopID);
         }
         //Try (hopefully) database update
         DatabaseUpdate.requestDBUpdateWithWork(this, false);
         /*
         Watch for database update
          */
         final WorkManager workManager = WorkManager.getInstance(this);
         workManager.getWorkInfosForUniqueWorkLiveData(DBUpdateWorker.DEBUG_TAG)
                 .observe(this, workInfoList -> {
                     // If there are no matching work info, do nothing
                     if (workInfoList == null || workInfoList.isEmpty()) {
                         return;
                     }
                     Log.d(DEBUG_TAG, "WorkerInfo: "+workInfoList);
 
                     boolean showProgress = false;
                     for (WorkInfo workInfo : workInfoList) {
                         if (workInfo.getState() == WorkInfo.State.RUNNING) {
                             showProgress = true;
                             break;
                         }
                     }
 
                     if (showProgress) {
                         createDefaultSnackbar();
                     } else {
                         if(snackbar!=null) {
                             snackbar.dismiss();
                             snackbar = null;
                         }
                     }
 
                 });
         // show the main fragment
         showMainFragment();
 
 
     }
     private ActionBarDrawerToggle setupDrawerToggle(Toolbar toolbar) {
         // NOTE: Make sure you pass in a valid toolbar reference.  ActionBarDrawToggle() does not require it
         // and will not render the hamburger icon without it.
         return new ActionBarDrawerToggle(this, mDrawer, toolbar, R.string.drawer_open,  R.string.drawer_close);
 
     }
 
     /**
      * Setup drawer actions
      * @param navigationView the navigation view on which to set the callbacks
      */
     private void setupDrawerContent(NavigationView navigationView) {
         navigationView.setNavigationItemSelectedListener(
                 menuItem -> {
                     if (menuItem.getItemId() == R.id.drawer_action_settings) {
                         Log.d("MAINBusTO", "Pressed button preferences");
                         closeDrawerIfOpen();
                         startActivity(new Intent(ActivityPrincipal.this, ActivitySettings.class));
                         return true;
                     } else if(menuItem.getItemId() == R.id.nav_favorites_item){
                         closeDrawerIfOpen();
                         //get Fragment
                         FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
                         FavoritesFragment fragment = FavoritesFragment.newInstance();
                         ft.replace(R.id.mainActContentFrame,fragment, TAG_FAVORITES);
                         ft.addToBackStack(null);
                         ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
                         ft.commit();
                         return true;
                     } else if(menuItem.getItemId() == R.id.nav_arrivals){
                         closeDrawerIfOpen();
                         showMainFragment();
                         return true;
                     } else if(menuItem.getItemId() == R.id.nav_map_item){
                         closeDrawerIfOpen();
                         final String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
                         int result = askForPermissionIfNeeded(permission, STORAGE_PERMISSION_REQ);
                         switch (result) {
                             case PERMISSION_OK:
                                 createAndShowMapFragment(null);
                                 break;
                             case PERMISSION_ASKING:
                                 permissionDoneRunnables.put(permission,
                                         () -> createAndShowMapFragment(null));
                                 break;
                             case PERMISSION_NEG_CANNOT_ASK:
                                 String storage_perm = getString(R.string.storage_permission);
                                 String text = getString(R.string.too_many_permission_asks,  storage_perm);
                                 Toast.makeText(getApplicationContext(),text, Toast.LENGTH_LONG).show();
                         }
                         return true;
                     }
                     //selectDrawerItem(menuItem);
                     Log.d(DEBUG_TAG, "pressed item "+menuItem);
 
                     return true;
 
                 });
 
     }
 
     private void closeDrawerIfOpen(){
         if (mDrawer.isDrawerOpen(GravityCompat.START))
             mDrawer.closeDrawer(GravityCompat.START);
     }
 
 
     // `onPostCreate` called when activity start-up is complete after `onStart()`
     // NOTE 1: Make sure to override the method with only a single `Bundle` argument
     // Note 2: Make sure you implement the correct `onPostCreate(Bundle savedInstanceState)` method.
     // There are 2 signatures and only `onPostCreate(Bundle state)` shows the hamburger icon.
     @Override
     protected void onPostCreate(Bundle savedInstanceState) {
         super.onPostCreate(savedInstanceState);
         // Sync the toggle state after onRestoreInstanceState has occurred.
         drawerToggle.syncState();
     }
 
     @Override
     public void onConfigurationChanged(@NonNull Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         // Pass any configuration change to the drawer toggles
         drawerToggle.onConfigurationChanged(newConfig);
 
     }
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         getMenuInflater().inflate(R.menu.principal_menu, menu);
         MenuItem experimentsMenuItem = menu.findItem(R.id.action_experiments);
         SharedPreferences shPr = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
         boolean exper_On = shPr.getBoolean(getString(R.string.pref_key_experimental), false);
         experimentsMenuItem.setVisible(exper_On);
         return super.onCreateOptionsMenu(menu);
     }
 
     @Override
     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
         super.onRequestPermissionsResult(requestCode, permissions, grantResults);
         if (requestCode==STORAGE_PERMISSION_REQ){
             final String storagePerm = Manifest.permission.WRITE_EXTERNAL_STORAGE;
             if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                 Log.d(DEBUG_TAG, "Permissions check: " + Arrays.toString(permissions));
 
                 if (permissionDoneRunnables.containsKey(storagePerm)) {
                     Runnable toRun = permissionDoneRunnables.get(storagePerm);
                     if (toRun != null)
                         toRun.run();
                     permissionDoneRunnables.remove(storagePerm);
                 }
             } else {
                 //permission denied
                 showToastMessage(R.string.permission_storage_maps_msg, false);
             }
         }
     }
 
     @Override
     public boolean onOptionsItemSelected(@NonNull MenuItem item) {
 
         int[] cases = {R.id.nav_arrivals, R.id.nav_favorites_item};
         Log.d(DEBUG_TAG, "Item pressed");
 
 
         if (item.getItemId() == android.R.id.home) {
             mDrawer.openDrawer(GravityCompat.START);
             return true;
         }
 
         if (drawerToggle.onOptionsItemSelected(item)) {
 
             return true;
 
         }
         return super.onOptionsItemSelected(item);
 
     }
 
     @Override
     public void onBackPressed() {
         boolean foundFragment = false;
         Fragment shownFrag = getSupportFragmentManager().findFragmentById(R.id.mainActContentFrame);
         if (mDrawer.isDrawerOpen(GravityCompat.START))
             mDrawer.closeDrawer(GravityCompat.START);
         else if(shownFrag != null && shownFrag.isVisible() && shownFrag.getChildFragmentManager().getBackStackEntryCount() > 0){
             //if we have been asked to show a stop from another fragment, we should go back even in the main
             if(shownFrag instanceof MainScreenFragment){
                 //we have to stop the arrivals reload
                 ((MainScreenFragment) shownFrag).cancelReloadArrivalsIfNeeded();
             }
             shownFrag.getChildFragmentManager().popBackStackImmediate();
             if(showingMainFragmentFromOther && getSupportFragmentManager().getBackStackEntryCount() > 0){
                 getSupportFragmentManager().popBackStack();
             }
         }
         else if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
             getSupportFragmentManager().popBackStack();
         }
         else
             super.onBackPressed();
     }
 
+    /**
+     * Create and show the SnackBar with the message
+     */
     private void createDefaultSnackbar() {
-        if (snackbar == null) {
-            snackbar = Snackbar.make(findViewById(R.id.searchButton), R.string.database_update_message, Snackbar.LENGTH_INDEFINITE);
+
+        View baseView = null;
+        final Fragment frag = getSupportFragmentManager().findFragmentById(R.id.mainActContentFrame);
+        if (frag instanceof ScreenBaseFragment){
+            baseView = ((ScreenBaseFragment) frag).getBaseViewForSnackBar();
         }
+        if (baseView == null) baseView = findViewById(R.id.mainActContentFrame);
+        if (baseView == null) Log.e(DEBUG_TAG, "baseView null for default snackbar, probably exploding now");
+        snackbar = Snackbar.make(baseView, R.string.database_update_message, Snackbar.LENGTH_INDEFINITE);
         snackbar.show();
     }
 
     private MainScreenFragment createAndShowMainFragment(){
         FragmentManager fraMan = getSupportFragmentManager();
 
         MainScreenFragment fragment = MainScreenFragment.newInstance();
 
         FragmentTransaction transaction = fraMan.beginTransaction();
         transaction.replace(R.id.mainActContentFrame, fragment, MainScreenFragment.FRAGMENT_TAG);
         transaction.commit();
         return fragment;
     }
 
     /**
      * Show the fragment by adding it to the backstack
      * @param fraMan the fragmentManager
      * @param fragment the fragment
      */
     private static void showMainFragment(FragmentManager fraMan, MainScreenFragment fragment){
         fraMan.beginTransaction().replace(R.id.mainActContentFrame, fragment)
                 .setReorderingAllowed(true)
                 .addToBackStack(null)
                 /*.setCustomAnimations(
                         R.anim.slide_in,  // enter
                         R.anim.fade_out,  // exit
                         R.anim.fade_in,   // popEnter
                         R.anim.slide_out  // popExit
                 )*/
                 .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
                 .commit();
     }
 
     private MainScreenFragment showMainFragment(){
         FragmentManager fraMan = getSupportFragmentManager();
         Fragment fragment = fraMan.findFragmentByTag(MainScreenFragment.FRAGMENT_TAG);
         final MainScreenFragment mainScreenFragment;
         if (fragment==null | !(fragment instanceof MainScreenFragment)){
             mainScreenFragment = createAndShowMainFragment();
         }
         else if(!fragment.isVisible()){
 
 
             mainScreenFragment = (MainScreenFragment) fragment;
             showMainFragment(fraMan, mainScreenFragment);
             Log.d(DEBUG_TAG, "Found the main fragment");
         } else{
             mainScreenFragment = (MainScreenFragment) fragment;
         }
         return mainScreenFragment;
     }
     @Nullable
     private MainScreenFragment getMainFragmentIfVisible(){
         FragmentManager fraMan = getSupportFragmentManager();
         Fragment fragment = fraMan.findFragmentByTag(MainScreenFragment.FRAGMENT_TAG);
         if (fragment!= null && fragment.isVisible()) return (MainScreenFragment) fragment;
         else return null;
     }
 
 
     @Override
     public void showFloatingActionButton(boolean yes) {
         //TODO
     }
     /*
     public void setDrawerSelectedItem(String fragmentTag){
         switch (fragmentTag){
             case MainScreenFragment.FRAGMENT_TAG:
                 mNavView.setCheckedItem(R.id.nav_arrivals);
                 break;
             case MapFragment.FRAGMENT_TAG:
 
                 break;
 
             case FavoritesFragment.FRAGMENT_TAG:
                 mNavView.setCheckedItem(R.id.nav_favorites_item);
                 break;
         }
     }*/
 
     @Override
     public void readyGUIfor(FragmentKind fragmentType) {
         MainScreenFragment probableFragment = getMainFragmentIfVisible();
         if (probableFragment!=null){
             probableFragment.readyGUIfor(fragmentType);
         }
         int titleResId;
         switch (fragmentType){
             case MAP:
                 mNavView.setCheckedItem(R.id.nav_map_item);
                 titleResId = R.string.map;
                 break;
             case FAVORITES:
                 mNavView.setCheckedItem(R.id.nav_favorites_item);
                 titleResId = R.string.nav_favorites_text;
                 break;
             case ARRIVALS:
                 titleResId = R.string.nav_arrivals_text;
                 mNavView.setCheckedItem(R.id.nav_arrivals);
                 break;
             case STOPS:
                 titleResId = R.string.stop_search_view_title;
                 mNavView.setCheckedItem(R.id.nav_arrivals);
                 break;
             case MAIN_SCREEN_FRAGMENT:
             case NEARBY_STOPS:
             case NEARBY_ARRIVALS:
                 titleResId=R.string.app_name_full;
                 mNavView.setCheckedItem(R.id.nav_arrivals);
                 break;
             default:
                 titleResId = 0;
         }
         if(getSupportActionBar()!=null && titleResId!=0)
             getSupportActionBar().setTitle(titleResId);
     }
 
     @Override
     public void requestArrivalsForStopID(String ID) {
         //register if the request came from the main fragment or not
         MainScreenFragment probableFragment = getMainFragmentIfVisible();
         showingMainFragmentFromOther = (probableFragment==null);
 
         if (showingMainFragmentFromOther){
             FragmentManager fraMan = getSupportFragmentManager();
             Fragment fragment = fraMan.findFragmentByTag(MainScreenFragment.FRAGMENT_TAG);
             if(fragment!=null){
                 //the fragment is there but not shown
                 probableFragment = (MainScreenFragment) fragment;
                 // set the flag
                 probableFragment.setSuppressArrivalsReload(true);
                 showMainFragment(fraMan, probableFragment);
             } else {
                 // we have no fragment
                 probableFragment = createAndShowMainFragment();
             }
         }
         probableFragment.requestArrivalsForStopID(ID);
         mNavView.setCheckedItem(R.id.nav_arrivals);
     }
 
     @Override
     public void toggleSpinner(boolean state) {
         MainScreenFragment probableFragment = getMainFragmentIfVisible();
         if (probableFragment!=null){
             probableFragment.toggleSpinner(state);
         }
     }
 
     @Override
     public void enableRefreshLayout(boolean yes) {
         MainScreenFragment probableFragment = getMainFragmentIfVisible();
         if (probableFragment!=null){
             probableFragment.enableRefreshLayout(yes);
         }
     }
 
     @Override
     public void showMapCenteredOnStop(Stop stop) {
         createAndShowMapFragment(stop);
     }
 
     //Map Fragment stuff
     void createAndShowMapFragment(@Nullable Stop stop){
         FragmentManager fm = getSupportFragmentManager();
         FragmentTransaction ft = fm.beginTransaction();
         MapFragment fragment = stop == null? MapFragment.getInstance(): MapFragment.getInstance(stop);
         ft.replace(R.id.mainActContentFrame, fragment, MapFragment.FRAGMENT_TAG);
         ft.addToBackStack(null);
         ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
         ft.commit();
     }
 
     class ToolbarItemClickListener implements Toolbar.OnMenuItemClickListener{
         private final Context activityContext;
 
         public ToolbarItemClickListener(Context activityContext) {
             this.activityContext = activityContext;
         }
 
         @Override
         public boolean onMenuItemClick(MenuItem item) {
             switch (item.getItemId()) {
                 case R.id.action_about:
                     startActivity(new Intent(ActivityPrincipal.this, ActivityAbout.class));
                     return true;
                 case R.id.action_hack:
                     openIceweasel(getString(R.string.hack_url), activityContext);
                     return true;
                 case R.id.action_source:
                     openIceweasel("https://gitpull.it/source/libre-busto/", activityContext);
                     return true;
                 case R.id.action_licence:
                     openIceweasel("https://www.gnu.org/licenses/gpl-3.0.html", activityContext);
                     return true;
                 case R.id.action_experiments:
                     startActivity(new Intent(ActivityPrincipal.this, ActivityExperiments.class));
                 default:
             }
             return false;
         }
     }
 }
diff --git a/src/it/reyboz/bustorino/backend/mato/MatoAPIFetcher.kt b/src/it/reyboz/bustorino/backend/mato/MatoAPIFetcher.kt
index 057400f..7f2152f 100644
--- a/src/it/reyboz/bustorino/backend/mato/MatoAPIFetcher.kt
+++ b/src/it/reyboz/bustorino/backend/mato/MatoAPIFetcher.kt
@@ -1,268 +1,268 @@
 /*
 	BusTO  - Backend components
     Copyright (C) 2021 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.backend.mato
 
 import android.content.Context
 import android.util.Log
 import com.android.volley.toolbox.RequestFuture
 import it.reyboz.bustorino.BuildConfig
 import it.reyboz.bustorino.backend.*
 import org.json.JSONObject
 import java.util.*
 import java.util.concurrent.ExecutionException
 import java.util.concurrent.TimeUnit
 import java.util.concurrent.TimeoutException
 import java.util.concurrent.atomic.AtomicReference
 
 
 open class MatoAPIFetcher(val minNumPassaggi: Int) : ArrivalsFetcher {
     var appContext: Context? = null
         set(value) {
             field = value!!.applicationContext
         }
     constructor(): this(2)
 
 
     override fun ReadArrivalTimesAll(stopID: String?, res: AtomicReference<Fetcher.Result>?): Palina {
         stopID!!
 
         val now = Calendar.getInstance().time
         var numMinutes = 0
         var palina = Palina(stopID)
         var numPassaggi = 0
         var trials = 0
         val numDepartures = 4
         while (numPassaggi < minNumPassaggi && trials < 4) {
 
             //numDepartures+=2
             numMinutes += 20
             val future = RequestFuture.newFuture<Palina>()
             val request = MapiArrivalRequest(stopID, now, numMinutes * 60, numDepartures, res, future, future)
             if (appContext == null || res == null) {
                 Log.e("BusTO:MatoAPIFetcher", "ERROR: Given null context or null result ref")
                 return Palina(stopID)
             }
             val requestQueue = NetworkVolleyManager.getInstance(appContext).requestQueue
             request.setTag(getVolleyReqTag(QueryType.ARRIVALS))
             requestQueue.add(request)
 
             try {
                 val palinaResult =  future.get(5, TimeUnit.SECONDS)
                 if (palinaResult!=null) {
                     if (BuildConfig.DEBUG)
                     for (r in palinaResult.queryAllRoutes()){
                         Log.d(DEBUG_TAG, "route " + r.gtfsId + " has " + r.passaggi.size + " passaggi: "+ r.passaggiToString)
                     }
                     palina = palinaResult
                     numPassaggi = palina.minNumberOfPassages
                 } else{
                     Log.d(DEBUG_TAG, "Result palina is null")
                 }
             } catch (e: InterruptedException) {
                 e.printStackTrace()
                 res.set(Fetcher.Result.PARSER_ERROR)
             } catch (e: ExecutionException) {
                 e.printStackTrace()
                 if (res.get() == Fetcher.Result.OK)
                 res.set(Fetcher.Result.SERVER_ERROR)
             } catch (e: TimeoutException) {
                 res.set(Fetcher.Result.CONNECTION_ERROR)
                 e.printStackTrace()
             }
             trials++
 
         }
 
         return palina
     }
 
     override fun getSourceForFetcher(): Passaggio.Source {
         return Passaggio.Source.MatoAPI
     }
 
     companion object{
         const val VOLLEY_TAG = "MatoAPIFetcher"
 
         const val DEBUG_TAG = "BusTO:MatoAPIFetcher"
 
         val REQ_PARAMETERS = mapOf(
             "Content-Type" to "application/json; charset=utf-8",
             "DNT" to "1",
             "Host" to "mapi.5t.torino.it")
 
         fun getVolleyReqTag(type: QueryType): String{
             return when (type){
                 QueryType.ALL_STOPS -> VOLLEY_TAG +"_AllStops"
                 QueryType.ARRIVALS -> VOLLEY_TAG+"_Arrivals"
             }
         }
 
         /**
          * Get stops from the MatoAPI, set [res] accordingly
          */
         fun getAllStopsGTT(context: Context, res: AtomicReference<Fetcher.Result>?): List<Palina>{
             val requestQueue = NetworkVolleyManager.getInstance(context).requestQueue
             val future = RequestFuture.newFuture<List<Palina>>()
 
             val request = VolleyAllStopsRequest(future, future)
             request.tag = getVolleyReqTag(QueryType.ALL_STOPS)
 
             requestQueue.add(request)
 
-            var palinaList:List<Palina> = mutableListOf<Palina>()
+            var palinaList:List<Palina> = mutableListOf()
 
             try {
-                palinaList = future.get(30, TimeUnit.SECONDS)
+                palinaList = future.get(60, TimeUnit.SECONDS)
 
                 res?.set(Fetcher.Result.OK)
             }catch (e: InterruptedException) {
                 e.printStackTrace()
                 res?.set(Fetcher.Result.PARSER_ERROR)
             } catch (e: ExecutionException) {
                 e.printStackTrace()
                 res?.set(Fetcher.Result.SERVER_ERROR)
             } catch (e: TimeoutException) {
                 res?.set(Fetcher.Result.CONNECTION_ERROR)
                 e.printStackTrace()
             }
             return palinaList
         }
         /*
         fun makeRequest(type: QueryType?, variables: JSONObject) : String{
             type.let {
                 val requestData = JSONObject()
                 when (it){
                     QueryType.ARRIVALS ->{
                         requestData.put("operationName","AllStopsDirect")
                         requestData.put("variables", variables)
                         requestData.put("query", MatoQueries.QUERY_ARRIVALS)
                     }
                     else -> {
                         //TODO all other cases
                     }
                 }
 
 
                 //todo make the request...
                 //https://pablobaxter.github.io/volley-docs/com/android/volley/toolbox/RequestFuture.html
                 //https://stackoverflow.com/questions/16904741/can-i-do-a-synchronous-request-with-volley
 
             }
             return ""
         }
          */
         fun parseStopJSON(jsonStop: JSONObject): Palina{
             val latitude = jsonStop.getDouble("lat")
             val longitude = jsonStop.getDouble("lon")
             val palina = Palina(
                 jsonStop.getString("code"),
                 jsonStop.getString("name"),
                 null, null, latitude, longitude
             )
             palina.gtfsID = jsonStop.getString("gtfsId")
 
             val routesStoppingJSON = jsonStop.getJSONArray("routes")
             val baseRoutes = mutableListOf<Route>()
             // get all the possible routes
             for (i in 0 until routesStoppingJSON.length()){
                 val routeBaseInfo = routesStoppingJSON.getJSONObject(i)
                 val r = Route(routeBaseInfo.getString("shortName"), Route.Type.UNKNOWN,"")
                 r.setGtfsId(routeBaseInfo.getString("gtfsId").trim())
                 baseRoutes.add(r)
 
             }
             if (jsonStop.has("desc")){
                 palina.location = jsonStop.getString("desc")
             }
             //there is also "zoneId" which is the zone of the stop (0-> city, etc)
 
             if(jsonStop.has("stoptimesForPatterns")) {
                 val routesStopTimes = jsonStop.getJSONArray("stoptimesForPatterns")
 
                 for (i in 0 until routesStopTimes.length()) {
                     val patternJSON = routesStopTimes.getJSONObject(i)
                     val mRoute = parseRouteStoptimesJSON(patternJSON)
 
                     //Log.d("BusTO-MapiFetcher")
                     //val directionId = patternJSON.getJSONObject("pattern").getInt("directionId")
                     //TODO: use directionId
                     palina.addRoute(mRoute)
                     for (r in baseRoutes) {
                         if (mRoute.gtfsId != null && r.gtfsId.equals(mRoute.gtfsId)) {
                             baseRoutes.remove(r)
                             break
                         }
                     }
                 }
             }
             for (noArrivalRoute in baseRoutes){
                 palina.addRoute(noArrivalRoute)
             }
             //val gtfsRoutes = mutableListOf<>()
             return palina
         }
         fun parseRouteStoptimesJSON(jsonPatternWithStops: JSONObject): Route{
             val patternJSON = jsonPatternWithStops.getJSONObject("pattern")
             val routeJSON = patternJSON.getJSONObject("route")
 
             val passaggiJSON = jsonPatternWithStops.getJSONArray("stoptimes")
             val gtfsId = routeJSON.getString("gtfsId").trim()
             val passages = mutableListOf<Passaggio>()
             for( i in 0 until passaggiJSON.length()){
                 val stoptime = passaggiJSON.getJSONObject(i)
                 val scheduledTime = stoptime.getInt("scheduledArrival")
                 val realtimeTime = stoptime.getInt("realtimeArrival")
                 val realtime = stoptime.getBoolean("realtime")
                 passages.add(
                     Passaggio(realtimeTime,realtime, realtimeTime-scheduledTime,
                         Passaggio.Source.MatoAPI)
                 )
             }
             var routeType = Route.Type.UNKNOWN
             if (gtfsId[gtfsId.length-1] == 'E')
                 routeType = Route.Type.LONG_DISTANCE_BUS
             else when( routeJSON.getString("mode").trim()){
                 "BUS" -> routeType = Route.Type.BUS
                 "TRAM" -> routeType = Route.Type.TRAM
             }
             val route = Route(
                 routeJSON.getString("shortName"),
                 patternJSON.getString("headsign"),
                 routeType,
                 passages,
             )
             route.setGtfsId(gtfsId)
             return route
         }
 
 
         fun makeRequestParameters(requestName:String, variables: JSONObject, query: String): JSONObject{
             val data = JSONObject()
             data.put("operationName", requestName)
             data.put("variables", variables)
             data.put("query", query)
             return  data
         }
 
     }
 
     enum class QueryType {
         ARRIVALS, ALL_STOPS
     }
 
 }
\ No newline at end of file
diff --git a/src/it/reyboz/bustorino/fragments/FavoritesFragment.java b/src/it/reyboz/bustorino/fragments/FavoritesFragment.java
index 3c45a71..d44a58e 100644
--- a/src/it/reyboz/bustorino/fragments/FavoritesFragment.java
+++ b/src/it/reyboz/bustorino/fragments/FavoritesFragment.java
@@ -1,310 +1,299 @@
 /*
 	BusTO  - Fragments components
     Copyright (C) 2021 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.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.ContextMenu;
 import android.view.LayoutInflater;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.EditText;
 import android.widget.ImageView;
-import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.Toast;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.lifecycle.ViewModelProvider;
 import androidx.recyclerview.widget.DividerItemDecoration;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
 import it.reyboz.bustorino.*;
 import it.reyboz.bustorino.adapters.AdapterListener;
-import it.reyboz.bustorino.adapters.StopAdapter;
 import it.reyboz.bustorino.adapters.StopRecyclerAdapter;
 import it.reyboz.bustorino.backend.Stop;
 import it.reyboz.bustorino.data.FavoritesViewModel;
 import it.reyboz.bustorino.middleware.AsyncStopFavoriteAction;
 
-public class FavoritesFragment extends BaseFragment {
+public class FavoritesFragment extends ScreenBaseFragment {
 
     private RecyclerView favoriteRecyclerView;
     private EditText busStopNameText;
     private TextView favoriteTipTextView;
     private ImageView angeryBusImageView;
-    private LinearLayoutManager llManager;
 
     @Nullable
     private CommonFragmentListener mListener;
 
     public static final String FRAGMENT_TAG = "BusTOFavFragment";
 
     private final AdapterListener adapterListener = new AdapterListener() {
         @Override
         public void onTappedStop(Stop stop) {
             mListener.requestArrivalsForStopID(stop.ID);
         }
     };
 
 
     public static FavoritesFragment newInstance() {
         FavoritesFragment fragment = new FavoritesFragment();
         Bundle args = new Bundle();
         //args.putString(ARG_PARAM1, param1);
         //args.putString(ARG_PARAM2, param2);
         fragment.setArguments(args);
         return fragment;
     }
     public FavoritesFragment(){
 
     }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         if (getArguments() != null) {
             //do nothing
         }
     }
 
     @Nullable
     @Override
     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
         View root = inflater.inflate(R.layout.fragment_favorites, container, false);
         favoriteRecyclerView = root.findViewById(R.id.favoritesRecyclerView);
         //favoriteListView = root.findViewById(R.id.favoriteListView);
         /*favoriteRecyclerView.setOn((parent, view, position, 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);
 
             if(mListener!=null){
                 mListener.requestArrivalsForStopID(busStop.ID);
             }
 
         });
 
          */
 
-        llManager = new LinearLayoutManager(getContext());
+        LinearLayoutManager llManager = new LinearLayoutManager(getContext());
         llManager.setOrientation(LinearLayoutManager.VERTICAL);
         favoriteRecyclerView.setLayoutManager(llManager);
         DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(favoriteRecyclerView.getContext(),
                 llManager.getOrientation());
         favoriteRecyclerView.addItemDecoration(dividerItemDecoration);
 
         angeryBusImageView = root.findViewById(R.id.angeryBusImageView);
         favoriteTipTextView = root.findViewById(R.id.favoriteTipTextView);
         registerForContextMenu(favoriteRecyclerView);
 
         FavoritesViewModel model = new ViewModelProvider(this).get(FavoritesViewModel.class);
         model.getFavorites().observe(getViewLifecycleOwner(), this::showStops);
 
         showStops(new ArrayList<>());
         return root;
     }
     @Override
     public void onAttach(@NonNull Context context) {
         super.onAttach(context);
         if (context instanceof CommonFragmentListener) {
             mListener = (CommonFragmentListener) context;
         } else {
-            throw new RuntimeException(context.toString()
+            throw new RuntimeException(context
                     + " must implement CommonFragmentListener");
         }
 
     }
 
     @Override
     public void onDetach() {
         super.onDetach();
         mListener = null;
     }
     /*
     This method is apparently NOT CALLED ANYMORE
      */
     @Override
     public void onCreateContextMenu(@NonNull ContextMenu menu, @NonNull View v,
                                     ContextMenu.ContextMenuInfo menuInfo) {
         super.onCreateContextMenu(menu, v, menuInfo);
         Log.d("Favorites Fragment", "Creating context menu on "+v);
         if (v.getId() == R.id.favoritesRecyclerView) {
             // if we aren't attached to activity, return null
             if (getActivity()==null) return;
 
             MenuInflater inflater = getActivity().getMenuInflater();
             inflater.inflate(R.menu.menu_favourites_entry, menu);
         }
     }
 
     @Override
     public void onResume() {
         super.onResume();
         if (mListener!=null) mListener.readyGUIfor(FragmentKind.FAVORITES);
     }
 
     @Override
     public boolean onContextItemSelected(MenuItem item) {
         AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item
                 .getMenuInfo();
 
         if(!(favoriteRecyclerView.getAdapter() instanceof StopRecyclerAdapter))
             return false;
 
         StopRecyclerAdapter adapter = (StopRecyclerAdapter) favoriteRecyclerView.getAdapter();
-        Stop busStop = (Stop) adapter.getStops().get(adapter.getPosition());
+        Stop busStop = adapter.getStops().get(adapter.getPosition());
 
         switch (item.getItemId()) {
             case R.id.action_favourite_entry_delete:
                 if (getContext()!=null)
                 new AsyncStopFavoriteAction(getContext().getApplicationContext(), AsyncStopFavoriteAction.Action.REMOVE,
                         result -> {
 
                         }).execute(busStop);
 
                 return true;
 
             case R.id.action_rename_bus_stop_username:
                 showBusStopUsernameInputDialog(busStop);
                 return true;
             case R.id.action_view_on_map:
                 if (busStop.getLatitude() == null | busStop.getLongitude() == null |
                         mListener==null
                 ) {
                     Toast.makeText(getContext(), R.string.cannot_show_on_map_no_position, Toast.LENGTH_SHORT).show();
                     return true;
                 }
 
                 //GeoPoint point = new GeoPoint(busStop.getLatitude(), busStop.getLongitude());
 
                 mListener.showMapCenteredOnStop(busStop);
                 return true;
             default:
                 return super.onContextItemSelected(item);
         }
     }
 
+    @Nullable
+    @Override
+    public View getBaseViewForSnackBar() {
+        return null;
+    }
 
     void showStops(List<Stop> busStops){
         // If no data is found show a friendly message
         if(BuildConfig.DEBUG)
             Log.d("BusTO - Favorites", "We have "+busStops.size()+" favorites in the list");
         if (busStops.size() == 0) {
             favoriteRecyclerView.setVisibility(View.INVISIBLE);
            // TextView favoriteTipTextView = (TextView) findViewById(R.id.favoriteTipTextView);
             //assert favoriteTipTextView != null;
             favoriteTipTextView.setVisibility(View.VISIBLE);
             //ImageView angeryBusImageView = (ImageView) findViewById(R.id.angeryBusImageView);
             angeryBusImageView.setVisibility(View.VISIBLE);
         } else {
             favoriteRecyclerView.setVisibility(View.VISIBLE);
             favoriteTipTextView.setVisibility(View.INVISIBLE);
             angeryBusImageView.setVisibility(View.INVISIBLE);
         }
         /* 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
         favoriteRecyclerView.setAdapter(new StopRecyclerAdapter(busStops,adapterListener));
     }
 
     public void showBusStopUsernameInputDialog(final Stop busStop) {
         AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
 
         LayoutInflater inflater = this.getLayoutInflater();
         View renameDialogLayout = inflater.inflate(R.layout.rename_dialog, null);
 
         busStopNameText = (EditText) renameDialogLayout.findViewById(R.id.rename_dialog_bus_stop_name);
         busStopNameText.setText(busStop.getStopDisplayName());
         busStopNameText.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 = busStopNameText.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);
-
-                    }
-                } else { // changed to something
-                    // something different?
-                    if(!busStopUsername.equals(oldUserName)) {
-                        busStop.setStopUserName(busStopUsername);
-
-                    }
+        builder.setPositiveButton(getString(android.R.string.ok), (dialog, which) -> {
+            String busStopUsername = busStopNameText.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);
+
+                }
+            } else { // changed to something
+                // something different?
+                if(!busStopUsername.equals(oldUserName)) {
+                    busStop.setStopUserName(busStopUsername);
+
                 }
-                launchUpdate(busStop);
-            }
-        });
-        builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
-            @Override
-            public void onClick(DialogInterface dialog, int which) {
-                dialog.cancel();
             }
+            launchUpdate(busStop);
         });
-        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);
-                launchUpdate(busStop);
+        builder.setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.cancel());
+        builder.setNeutralButton(R.string.dialog_rename_bus_stop_username_reset_button, (dialog, which) -> {
+            // delete user name from database
+            busStop.setStopUserName(null);
+            launchUpdate(busStop);
 
-            }
         });
         builder.show();
     }
 
     private void launchUpdate(Stop busStop){
         if (getContext()!=null)
             new AsyncStopFavoriteAction(getContext().getApplicationContext(), AsyncStopFavoriteAction.Action.UPDATE,
-                    new AsyncStopFavoriteAction.ResultListener() {
-                        @Override
-                        public void doStuffWithResult(Boolean result) {
-                            //Toast.makeText(getApplicationContext(), R.string.tip_add_favorite, Toast.LENGTH_SHORT).show();
-                        }
+                    result -> {
+                        //Toast.makeText(getApplicationContext(), R.string.tip_add_favorite, Toast.LENGTH_SHORT).show();
                     }).execute(busStop);
     }
 }
diff --git a/src/it/reyboz/bustorino/fragments/MainScreenFragment.java b/src/it/reyboz/bustorino/fragments/MainScreenFragment.java
index d7d3a68..71f227e 100644
--- a/src/it/reyboz/bustorino/fragments/MainScreenFragment.java
+++ b/src/it/reyboz/bustorino/fragments/MainScreenFragment.java
@@ -1,740 +1,752 @@
 
 package it.reyboz.bustorino.fragments;
 
 import android.Manifest;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.location.Criteria;
 import android.location.Location;
 import android.os.Build;
 import android.os.Bundle;
 
 import androidx.activity.result.ActivityResultCallback;
 import androidx.activity.result.ActivityResultLauncher;
 import androidx.activity.result.contract.ActivityResultContracts;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.appcompat.widget.AppCompatImageButton;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
 import androidx.core.app.ActivityCompat;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentManager;
 import androidx.fragment.app.FragmentTransaction;
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 
 import android.os.Handler;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.ImageButton;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 import android.widget.Toast;
 
 import com.google.android.material.floatingactionbutton.FloatingActionButton;
 import com.google.zxing.integration.android.IntentIntegrator;
 
 import java.util.Map;
 
 import it.reyboz.bustorino.R;
 import it.reyboz.bustorino.backend.*;
 import it.reyboz.bustorino.middleware.AppLocationManager;
 import it.reyboz.bustorino.middleware.AsyncArrivalsSearcher;
 import it.reyboz.bustorino.middleware.AsyncStopsSearcher;
 import it.reyboz.bustorino.util.LocationCriteria;
 import it.reyboz.bustorino.util.Permissions;
 
 import static it.reyboz.bustorino.util.Permissions.LOCATION_PERMISSIONS;
 import static it.reyboz.bustorino.util.Permissions.LOCATION_PERMISSION_GIVEN;
 
 
 /**
  * A simple {@link Fragment} subclass.
  * Use the {@link MainScreenFragment#newInstance} factory method to
  * create an instance of this fragment.
  */
-public class MainScreenFragment extends BaseFragment implements  FragmentListenerMain{
+public class MainScreenFragment extends ScreenBaseFragment implements  FragmentListenerMain{
 
 
     private static final String OPTION_SHOW_LEGEND = "show_legend";
     private static final String SAVED_FRAGMENT="saved_fragment";
 
     private static final String DEBUG_TAG = "BusTO - MainFragment";
 
     public final static String FRAGMENT_TAG = "MainScreenFragment";
 
     /// UI ELEMENTS //
     private ImageButton addToFavorites;
     private FragmentHelper fragmentHelper;
     private SwipeRefreshLayout swipeRefreshLayout;
     private EditText busStopSearchByIDEditText;
     private EditText busStopSearchByNameEditText;
     private ProgressBar progressBar;
     private TextView howDoesItWorkTextView;
     private Button hideHintButton;
     private MenuItem actionHelpMenuItem;
     private FloatingActionButton floatingActionButton;
 
     private boolean setupOnAttached = true;
     private boolean suppressArrivalsReload = false;
     //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;
     private final ArrivalsFetcher[] arrivalsFetchers = utils.getDefaultArrivalsFetchers();
     //// HIDDEN BUT IMPORTANT ELEMENTS ////
     FragmentManager fragMan;
     Handler mainHandler;
     private final Runnable refreshStop = new Runnable() {
         public void run() {
             if(getContext() == null) return;
             if (fragMan.findFragmentById(R.id.resultFrame) instanceof ArrivalsFragment) {
                 ArrivalsFragment fragment = (ArrivalsFragment) fragMan.findFragmentById(R.id.resultFrame);
                 if (fragment == null){
                     //we create a new fragment, which is WRONG
                     Log.e("BusTO-RefreshStop", "Asking for refresh when there is no fragment");
                     // AsyncDataDownload(fragmentHelper, arrivalsFetchers,getContext()).execute();
                 } else{
                     String stopName = fragment.getStopID();
 
                     new AsyncArrivalsSearcher(fragmentHelper, fragment.getCurrentFetchersAsArray(), getContext()).execute(stopName);
                 }
             } else //we create a new fragment, which is WRONG
                 new AsyncArrivalsSearcher(fragmentHelper, arrivalsFetchers, getContext()).execute();
         }
     };
 
     /// LOCATION STUFF ///
     boolean pendingNearbyStopsRequest = false;
     boolean locationPermissionGranted, locationPermissionAsked = false;
     AppLocationManager locationManager;
 
 
     private final LocationCriteria cr = new LocationCriteria(2000, 10000);
     //Location
     private AppLocationManager.LocationRequester requester = new AppLocationManager.LocationRequester() {
         @Override
         public void onLocationChanged(Location loc) {
 
         }
 
         @Override
         public void onLocationStatusChanged(int status) {
 
             if(status == AppLocationManager.LOCATION_GPS_AVAILABLE && !isNearbyFragmentShown()){
                 //request Stops
                 pendingNearbyStopsRequest = false;
                 if (getContext()!= null)
                     mainHandler.post(new NearbyStopsRequester(getContext(), cr));
             }
         }
 
         @Override
         public long getLastUpdateTimeMillis() {
             return 50;
         }
 
         @Override
         public LocationCriteria getLocationCriteria() {
             return cr;
         }
 
         @Override
         public void onLocationProviderAvailable() {
             //Log.w(DEBUG_TAG, "pendingNearbyStopRequest: "+pendingNearbyStopsRequest);
             if(!isNearbyFragmentShown() && getContext()!=null){
                 pendingNearbyStopsRequest = false;
                 mainHandler.post(new NearbyStopsRequester(getContext(), cr));
             }
         }
 
         @Override
         public void onLocationDisabled() {
 
         }
     };
     private final ActivityResultLauncher<String[]> requestPermissionLauncher =
             registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
                 @Override
                 public void onActivityResult(Map<String, Boolean> result) {
                     if(result==null || result.get(Manifest.permission.ACCESS_COARSE_LOCATION) == null
                     ||result.get(Manifest.permission.ACCESS_FINE_LOCATION) ) return;
 
                     if(result.get(Manifest.permission.ACCESS_COARSE_LOCATION) == null ||
                             result.get(Manifest.permission.ACCESS_FINE_LOCATION) == null)
                         return;
 
                     if(result.get(Manifest.permission.ACCESS_COARSE_LOCATION) && result.get(Manifest.permission.ACCESS_FINE_LOCATION)){
                         locationPermissionGranted = true;
                         Log.w(DEBUG_TAG, "Starting position");
                         if (mListener!= null && getContext()!=null){
                             if (locationManager==null)
                                 locationManager = AppLocationManager.getInstance(getContext());
                             locationManager.addLocationRequestFor(requester);
                         }
                     }
                 }
             });
 
 
     //// ACTIVITY ATTACHED (LISTENER ///
     private CommonFragmentListener mListener;
 
     private String pendingStopID = null;
+    private CoordinatorLayout coordLayout;
 
     public MainScreenFragment() {
         // Required empty public constructor
     }
 
 
     public static MainScreenFragment newInstance() {
         MainScreenFragment fragment = new MainScreenFragment();
         Bundle args = new Bundle();
         //args.putString(ARG_PARAM1, param1);
         //args.putString(ARG_PARAM2, param2);
         fragment.setArguments(args);
         return fragment;
     }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         if (getArguments() != null) {
             //do nothing
         }
     }
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
                              Bundle savedInstanceState) {
         // Inflate the layout for this fragment
         View root = inflater.inflate(R.layout.fragment_main_screen, container, false);
-        addToFavorites = (ImageButton) root.findViewById(R.id.addToFavorites);
+        addToFavorites = root.findViewById(R.id.addToFavorites);
         busStopSearchByIDEditText = root.findViewById(R.id.busStopSearchByIDEditText);
         busStopSearchByNameEditText = root.findViewById(R.id.busStopSearchByNameEditText);
         progressBar = root.findViewById(R.id.progressBar);
         howDoesItWorkTextView = root.findViewById(R.id.howDoesItWorkTextView);
         hideHintButton = root.findViewById(R.id.hideHintButton);
         swipeRefreshLayout = root.findViewById(R.id.listRefreshLayout);
         floatingActionButton = root.findViewById(R.id.floatingActionButton);
         busStopSearchByIDEditText.setSelectAllOnFocus(true);
         busStopSearchByIDEditText
                 .setOnEditorActionListener((v, actionId, event) -> {
                     // IME_ACTION_SEARCH alphabetical option
                     if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                         onSearchClick(v);
                         return true;
                     }
                     return false;
                 });
         busStopSearchByNameEditText
                 .setOnEditorActionListener((v, actionId, event) -> {
                     // IME_ACTION_SEARCH alphabetical option
                     if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                         onSearchClick(v);
                         return true;
                     }
                     return false;
                 });
 
         swipeRefreshLayout
                 .setOnRefreshListener(() -> mainHandler.post(refreshStop));
         swipeRefreshLayout.setColorSchemeResources(R.color.blue_500, R.color.orange_500);
 
+        coordLayout = root.findViewById(R.id.coord_layout);
+
         floatingActionButton.setOnClickListener((this::onToggleKeyboardLayout));
         hideHintButton.setOnClickListener(this::onHideHint);
 
         AppCompatImageButton qrButton = root.findViewById(R.id.QRButton);
         qrButton.setOnClickListener(this::onQRButtonClick);
 
         AppCompatImageButton searchButton = root.findViewById(R.id.searchButton);
         searchButton.setOnClickListener(this::onSearchClick);
 
         // Fragment stuff
         fragMan = getChildFragmentManager();
         fragMan.addOnBackStackChangedListener(() -> Log.d("BusTO Main Fragment", "BACK STACK CHANGED"));
 
         fragmentHelper = new FragmentHelper(this, getChildFragmentManager(), getContext(), R.id.resultFrame);
         setSearchModeBusStopID();
 
 
         cr.setAccuracy(Criteria.ACCURACY_FINE);
         cr.setAltitudeRequired(false);
         cr.setBearingRequired(false);
         cr.setCostAllowed(true);
         cr.setPowerRequirement(Criteria.NO_REQUIREMENT);
 
-       locationManager = AppLocationManager.getInstance(getContext());
+        locationManager = AppLocationManager.getInstance(getContext());
 
         Log.d(DEBUG_TAG, "OnCreateView, savedInstanceState null: "+(savedInstanceState==null));
 
 
 
         return root;
     }
 
     @Override
     public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         Log.d(DEBUG_TAG, "onViewCreated, SwipeRefreshLayout visible: "+(swipeRefreshLayout.getVisibility()==View.VISIBLE));
         Log.d(DEBUG_TAG, "Setup on attached: "+setupOnAttached);
         //Restore instance state
         if (savedInstanceState!=null){
             Fragment fragment = getChildFragmentManager().getFragment(savedInstanceState, SAVED_FRAGMENT);
             if (fragment!=null){
                 getChildFragmentManager().beginTransaction().add(R.id.resultFrame, fragment).commit();
                 setupOnAttached = false;
             }
         }
         if (getChildFragmentManager().findFragmentById(R.id.resultFrame)!= null){
             swipeRefreshLayout.setVisibility(View.VISIBLE);
         }
     }
 
     @Override
     public void onSaveInstanceState(@NonNull Bundle outState) {
         super.onSaveInstanceState(outState);
         Fragment fragment = getChildFragmentManager().findFragmentById(R.id.resultFrame);
         if (fragment!=null)
         getChildFragmentManager().putFragment(outState, SAVED_FRAGMENT, fragment);
         fragmentHelper.setBlockAllActivities(true);
     }
 
     public void setSuppressArrivalsReload(boolean value){
        suppressArrivalsReload = value;
         // we have to suppress the reloading of the (possible) ArrivalsFragment
         /*if(value) {
             Fragment fragment = getChildFragmentManager().findFragmentById(R.id.resultFrame);
             if (fragment instanceof ArrivalsFragment) {
                 ArrivalsFragment frag = (ArrivalsFragment) fragment;
                 frag.setReloadOnResume(false);
             }
         }
 
          */
     }
 
+
     /**
      * Cancel the reload of the arrival times
      * because we are going to pop the fragment
      */
     public void cancelReloadArrivalsIfNeeded(){
         if(getContext()==null) return; //we are not attached
 
         //Fragment fr = getChildFragmentManager().findFragmentById(R.id.resultFrame);
         fragmentHelper.stopLastRequestIfNeeded(true);
         toggleSpinner(false);
     }
 
 
     @Override
     public void onAttach(@NonNull Context context) {
         super.onAttach(context);
 
         Log.d(DEBUG_TAG, "OnAttach called, setupOnAttach: "+setupOnAttached);
         mainHandler = new Handler();
         if (context instanceof CommonFragmentListener) {
             mListener = (CommonFragmentListener) context;
         } else {
             throw new RuntimeException(context
                     + " must implement CommonFragmentListener");
         }
         if (setupOnAttached) {
             if (pendingStopID==null)
             //We want the nearby bus stops!
             mainHandler.post(new NearbyStopsRequester(context, cr));
             else{
                 ///TODO: if there is a stop displayed, we need to hold the update
             }
 
             setupOnAttached = false;
         }
 
 
     }
     @Override
     public void onDetach() {
         super.onDetach();
         mListener = null;
     //    setupOnAttached = true;
     }
 
 
     @Override
     public void onResume() {
 
         final Context con = getContext();
         Log.w(DEBUG_TAG, "OnResume called");
         if (con != null) {
             if(locationManager==null)
                 locationManager = AppLocationManager.getInstance(con);
 
             if(Permissions.locationPermissionGranted(con)){
                 Log.d(DEBUG_TAG, "Location permission OK");
                 if(!locationManager.isRequesterRegistered(requester))
                     locationManager.addLocationRequestFor(requester);
             } else if(shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)){
                 //we have already asked for the location, and we should show an explanation in order
                 // to ask again (TODO)
                 //do nothing
             } else{
                 //request permission
                 requestPermissionLauncher.launch(Permissions.LOCATION_PERMISSIONS);
             }
         }
         else {
             Log.w(DEBUG_TAG, "Context is null at onResume");
         }
         super.onResume();
         // if we have a pending stopID request, do it
         Log.d(DEBUG_TAG, "Pending stop ID for arrivals: "+pendingStopID);
         //this is the second time we are attaching this fragment
         Log.d(DEBUG_TAG, "Waiting for new stop request: "+ suppressArrivalsReload);
         if (suppressArrivalsReload){
             // we have to suppress the reloading of the (possible) ArrivalsFragment
             Fragment fragment = getChildFragmentManager().findFragmentById(R.id.resultFrame);
             if (fragment instanceof ArrivalsFragment){
                 ArrivalsFragment frag = (ArrivalsFragment) fragment;
                 frag.setReloadOnResume(false);
             }
             suppressArrivalsReload = false;
         }
         if(pendingStopID!=null){
             requestArrivalsForStopID(pendingStopID);
             pendingStopID = null;
         }
         mListener.readyGUIfor(FragmentKind.MAIN_SCREEN_FRAGMENT);
 
         fragmentHelper.setBlockAllActivities(false);
     }
 
     @Override
     public void onPause() {
         //mainHandler = null;
         locationManager.removeLocationRequestFor(requester);
         super.onPause();
         fragmentHelper.setBlockAllActivities(true);
         fragmentHelper.stopLastRequestIfNeeded(true);
     }
 
 
     /*
     GUI METHODS
      */
     /**
      * QR scan button clicked
      *
      * @param v View QRButton clicked
      */
     public void onQRButtonClick(View v) {
         IntentIntegrator integrator = new IntentIntegrator(getActivity());
         integrator.initiateScan();
     }
     public void onHideHint(View v) {
 
         hideHints();
         setOption(OPTION_SHOW_LEGEND, false);
     }
     /**
      * OK this is pure shit
      *
      * @param v View clicked
      */
     public void onSearchClick(View v) {
         final StopsFinderByName[] stopsFinderByNames = new StopsFinderByName[]{new GTTStopsFetcher(), new FiveTStopsFetcher()};
         if (searchMode == SEARCH_BY_ID) {
             String busStopID = busStopSearchByIDEditText.getText().toString();
             fragmentHelper.stopLastRequestIfNeeded(true);
             requestArrivalsForStopID(busStopID);
         } else { // searchMode == SEARCH_BY_NAME
             String query = busStopSearchByNameEditText.getText().toString();
             query = query.trim();
             if(getContext()!=null) {
                 if (query.length() < 1) {
                     Toast.makeText(getContext(), R.string.insert_bus_stop_name_error, Toast.LENGTH_SHORT).show();
                 } else if(query.length()< 3){
                     Toast.makeText(getContext(), R.string.query_too_short, Toast.LENGTH_SHORT).show();
                 }
                 else {
                     fragmentHelper.stopLastRequestIfNeeded(true);
                     new AsyncStopsSearcher(fragmentHelper, stopsFinderByNames).execute(query);
                 }
             }
         }
     }
 
     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();
             }
         }
 
     }
     @Override
     public void enableRefreshLayout(boolean yes) {
         swipeRefreshLayout.setEnabled(yes);
     }
 
     ////////////////////////////////////// GUI HELPERS /////////////////////////////////////////////
     public void showKeyboard() {
         if(getActivity() == null) return;
         InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
         View view = searchMode == SEARCH_BY_ID ? busStopSearchByIDEditText : busStopSearchByNameEditText;
         imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
     }
 
     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);
     }
     protected boolean isNearbyFragmentShown(){
         Fragment fragment = getChildFragmentManager().findFragmentByTag(NearbyStopsFragment.FRAGMENT_TAG);
         return (fragment!= null && fragment.isVisible());
     }
 
     /**
      * 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);
     }
 
+    @Nullable
+    @org.jetbrains.annotations.Nullable
+    @Override
+    public View getBaseViewForSnackBar() {
+        return coordLayout;
+    }
+
     @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);
     }
 
     void showNearbyStopsFragment(){
         swipeRefreshLayout.setVisibility(View.VISIBLE);
         final Fragment existingFrag = fragMan.findFragmentById(R.id.resultFrame);
         NearbyStopsFragment fragment;
         if (!(existingFrag instanceof NearbyStopsFragment)){
             //there is no fragment showing
             fragment = NearbyStopsFragment.newInstance(NearbyStopsFragment.TYPE_STOPS);
 
             FragmentTransaction ft = fragMan.beginTransaction();
             //if (oldFrag != null)
             //    ft.remove(oldFrag);
 
             ft.replace(R.id.resultFrame, fragment, NearbyStopsFragment.FRAGMENT_TAG);
             ft.commit();
         }
     }
 
 
     @Override
     public void showFloatingActionButton(boolean yes) {
         mListener.showFloatingActionButton(yes);
     }
 
     /**
      * 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)) {
             locationManager.removeLocationRequestFor(requester);
             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.d(DEBUG_TAG, "Fragment type is unknown");
                     return;
             }
         // Shows hints
 
 
     }
 
     @Override
     public void showMapCenteredOnStop(Stop stop) {
         if(mListener!=null) mListener.showMapCenteredOnStop(stop);
     }
 
     /**
      * Main method for stops requests
      * @param ID the Stop ID
      */
     @Override
     public void requestArrivalsForStopID(String ID) {
         if (!isResumed()){
             //defer request
             pendingStopID = ID;
             Log.d(DEBUG_TAG, "Deferring update for stop "+ID);
             return;
         }
         final boolean delayedRequest = !(pendingStopID==null);
         final FragmentManager framan = getChildFragmentManager();
         if (getContext()==null){
             Log.e(DEBUG_TAG, "Asked for arrivals with null context");
             return;
         }
         if (ID == null || ID.length() <= 0) {
             // we're still in UI thread, no need to mess with Progress
             showToastMessage(R.string.insert_bus_stop_number_error, true);
             toggleSpinner(false);
         } else  if (framan.findFragmentById(R.id.resultFrame) instanceof ArrivalsFragment) {
             ArrivalsFragment fragment = (ArrivalsFragment) framan.findFragmentById(R.id.resultFrame);
             if (fragment != null && fragment.getStopID() != null && fragment.getStopID().equals(ID)){
                 // Run with previous fetchers
                 //fragment.getCurrentFetchers().toArray()
                 new AsyncArrivalsSearcher(fragmentHelper,fragment.getCurrentFetchersAsArray(), getContext()).execute(ID);
             } else{
                 new AsyncArrivalsSearcher(fragmentHelper, arrivalsFetchers, getContext()).execute(ID);
             }
         }
         else {
             new AsyncArrivalsSearcher(fragmentHelper,arrivalsFetchers, getContext()).execute(ID);
             Log.d(DEBUG_TAG, "Started search for arrivals of stop " + ID);
         }
     }
     /////////// LOCATION METHODS //////////
 
     /*
     private void startStopRequest(String provider) {
         Log.d(DEBUG_TAG, "Provider " + provider + " got enabled");
         if (locmgr != null && mainHandler != null && pendingNearbyStopsRequest && locmgr.getProvider(provider).meetsCriteria(cr)) {
 
         }
     }
 
      */
 
     /**
      * Run location requests separately and asynchronously
      */
     class NearbyStopsRequester implements Runnable {
         Context appContext;
         Criteria cr;
 
         public NearbyStopsRequester(Context appContext, Criteria criteria) {
             this.appContext = appContext.getApplicationContext();
             this.cr = criteria;
         }
 
         @Override
         public void run() {
             if(isNearbyFragmentShown()) {
                 //nothing to do
                 Log.w(DEBUG_TAG, "launched nearby fragment request but we already are showing");
                 return;
             }
 
             final boolean isOldVersion = Build.VERSION.SDK_INT < Build.VERSION_CODES.M;
             final boolean noPermission = ActivityCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                     ActivityCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED;
 
             //if we don't have the permission, we have to ask for it, if we haven't
             // asked too many times before
             if (noPermission) {
                 if (!isOldVersion) {
                     pendingNearbyStopsRequest = true;
                     //Permissions.assertLocationPermissions(appContext,getActivity());
                     requestPermissionLauncher.launch(LOCATION_PERMISSIONS);
                     Log.w(DEBUG_TAG, "Cannot get position: Asking permission, noPositionFromSys: " + noPermission);
                     return;
                 } else {
                     Toast.makeText(appContext, "Asked for permission position too many times", Toast.LENGTH_LONG).show();
                 }
             } else setOption(LOCATION_PERMISSION_GIVEN, true);
 
             AppLocationManager appLocationManager = AppLocationManager.getInstance(appContext);
             final boolean haveProviders = appLocationManager.anyLocationProviderMatchesCriteria(cr);
             if (haveProviders
                     && fragmentHelper.getLastSuccessfullySearchedBusStop() == null
                     && !fragMan.isDestroyed()) {
                 //Go ahead with the request
                 Log.d("mainActivity", "Recreating stop fragment");
                 showNearbyStopsFragment();
                 pendingNearbyStopsRequest = false;
             } else if(!haveProviders){
                 Log.e(DEBUG_TAG, "NO PROVIDERS FOR POSITION");
             }
 
         }
     }
 
 }
\ No newline at end of file
diff --git a/src/it/reyboz/bustorino/fragments/MapFragment.java b/src/it/reyboz/bustorino/fragments/MapFragment.java
index 81fc88e..13b1cae 100644
--- a/src/it/reyboz/bustorino/fragments/MapFragment.java
+++ b/src/it/reyboz/bustorino/fragments/MapFragment.java
@@ -1,640 +1,644 @@
 /*
 	BusTO  - Fragments components
     Copyright (C) 2020 Andrea Ugo
     Copyright (C) 2021 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.Manifest;
 import android.annotation.SuppressLint;
 import android.content.Context;
 
 import android.location.Location;
 import android.location.LocationManager;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageButton;
 import android.widget.Toast;
 
 import androidx.activity.result.ActivityResultCallback;
 import androidx.activity.result.ActivityResultLauncher;
 import androidx.activity.result.contract.ActivityResultContracts;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.core.content.res.ResourcesCompat;
 import androidx.preference.PreferenceManager;
 
 import it.reyboz.bustorino.backend.utils;
 import org.osmdroid.api.IGeoPoint;
 import org.osmdroid.api.IMapController;
 import org.osmdroid.config.Configuration;
 import org.osmdroid.events.DelayedMapListener;
 import org.osmdroid.events.MapListener;
 import org.osmdroid.events.ScrollEvent;
 import org.osmdroid.events.ZoomEvent;
 import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
 import org.osmdroid.util.BoundingBox;
 import org.osmdroid.util.GeoPoint;
 import org.osmdroid.views.MapView;
 import org.osmdroid.views.overlay.FolderOverlay;
 import org.osmdroid.views.overlay.Marker;
 import org.osmdroid.views.overlay.infowindow.InfoWindow;
 import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider;
 
 import java.lang.ref.WeakReference;
 import java.util.*;
 
 import it.reyboz.bustorino.R;
 import it.reyboz.bustorino.backend.Stop;
 import it.reyboz.bustorino.data.NextGenDB;
 import it.reyboz.bustorino.map.CustomInfoWindow;
 import it.reyboz.bustorino.map.LocationOverlay;
 import it.reyboz.bustorino.middleware.GeneralActivity;
 import it.reyboz.bustorino.util.Permissions;
 
-public class MapFragment extends BaseFragment {
+public class MapFragment extends ScreenBaseFragment {
 
     private static final String TAG = "Busto-MapActivity";
     private static final String MAP_CURRENT_ZOOM_KEY = "map-current-zoom";
     private static final String MAP_CENTER_LAT_KEY = "map-center-lat";
     private static final String MAP_CENTER_LON_KEY = "map-center-lon";
     private static final String FOLLOWING_LOCAT_KEY ="following";
 
     public static final String BUNDLE_LATIT = "lat";
     public static final String BUNDLE_LONGIT = "lon";
     public static final String BUNDLE_NAME = "name";
     public static final String BUNDLE_ID = "ID";
 
     public static final String FRAGMENT_TAG="BusTOMapFragment";
 
 
     private static final double DEFAULT_CENTER_LAT = 45.0708;
     private static final double DEFAULT_CENTER_LON = 7.6858;
     private static final double POSITION_FOUND_ZOOM = 18.3;
     public static final double NO_POSITION_ZOOM = 17.1;
 
     private static final String DEBUG_TAG=FRAGMENT_TAG;
 
     protected FragmentListenerMain listenerMain;
 
     private HashSet<String> shownStops = null;
     //the asynctask used to get the stops from the database
     private AsyncStopFetcher stopFetcher = null;
 
 
     private MapView map = null;
     public Context ctx;
     private LocationOverlay mLocationOverlay = null;
     private FolderOverlay stopsFolderOverlay = null;
     private Bundle savedMapState = null;
     protected ImageButton btCenterMap;
     protected ImageButton btFollowMe;
     private boolean followingLocation = false;
 
     protected final CustomInfoWindow.TouchResponder responder = new CustomInfoWindow.TouchResponder() {
         @Override
         public void onActionUp(@NonNull String stopID, @Nullable String stopName) {
             if (listenerMain!= null){
                 listenerMain.requestArrivalsForStopID(stopID);
             }
         }
     };
     protected final LocationOverlay.OverlayCallbacks locationCallbacks = new LocationOverlay.OverlayCallbacks() {
         @Override
         public void onDisableFollowMyLocation() {
             updateGUIForLocationFollowing(false);
             followingLocation=false;
         }
 
         @Override
         public void onEnableFollowMyLocation() {
             updateGUIForLocationFollowing(true);
             followingLocation=true;
         }
     };
 
     private final ActivityResultLauncher<String[]> positionRequestLauncher =
-            registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
-                @Override
-                @SuppressLint("MissingPermission")
-                public void onActivityResult(Map<String, Boolean> result) {
-                    if(result.get(Manifest.permission.ACCESS_COARSE_LOCATION) && result.get(Manifest.permission.ACCESS_FINE_LOCATION)){
-
-                        map.getOverlays().remove(mLocationOverlay);
-                        startLocationOverlay(true, map);
-                        if(getContext()==null || getContext().getSystemService(Context.LOCATION_SERVICE)==null)
-                            return;
-                        LocationManager locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
-                        Location userLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
-                        if (userLocation != null) {
-                            map.getController().setZoom(POSITION_FOUND_ZOOM);
-                            GeoPoint startPoint = new GeoPoint(userLocation);
-                            setLocationFollowing(true);
-                            map.getController().setCenter(startPoint);
-                        }
+            registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> {
+                if(result.get(Manifest.permission.ACCESS_COARSE_LOCATION) && result.get(Manifest.permission.ACCESS_FINE_LOCATION)){
+
+                    map.getOverlays().remove(mLocationOverlay);
+                    startLocationOverlay(true, map);
+                    if(getContext()==null || getContext().getSystemService(Context.LOCATION_SERVICE)==null)
+                        return;
+                    LocationManager locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
+                    @SuppressLint("MissingPermission")
+                    Location userLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
+                    if (userLocation != null) {
+                        map.getController().setZoom(POSITION_FOUND_ZOOM);
+                        GeoPoint startPoint = new GeoPoint(userLocation);
+                        setLocationFollowing(true);
+                        map.getController().setCenter(startPoint);
                     }
-                    else Log.w(DEBUG_TAG,"No location permission");
                 }
+                else Log.w(DEBUG_TAG,"No location permission");
             });
 
     public MapFragment() {
     }
     public static MapFragment getInstance(){
         return new MapFragment();
     }
     public static MapFragment getInstance(double stopLatit, double stopLong, String stopName, String stopID){
         MapFragment fragment= new MapFragment();
         Bundle args = new Bundle();
         args.putDouble(BUNDLE_LATIT, stopLatit);
         args.putDouble(BUNDLE_LONGIT, stopLong);
         args.putString(BUNDLE_NAME, stopName);
         args.putString(BUNDLE_ID, stopID);
         fragment.setArguments(args);
 
         return fragment;
     }
     public static MapFragment getInstance(@NonNull Stop stop){
         return getInstance(stop.getLatitude(), stop.getLongitude(), stop.getStopDisplayName(), stop.ID);
     }
 
 
     @Nullable
     @Override
     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
         //use the same layout as the activity
         View root = inflater.inflate(R.layout.activity_map, container, false);
         if (getContext() == null){
             throw new IllegalStateException();
         }
         ctx = getContext().getApplicationContext();
         Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(ctx));
         map = root.findViewById(R.id.map);
         map.setTileSource(TileSourceFactory.MAPNIK);
         //map.setTilesScaledToDpi(true);
         map.setFlingEnabled(true);
 
         // add ability to zoom with 2 fingers
         map.setMultiTouchControls(true);
 
         btCenterMap = root.findViewById(R.id.ic_center_map);
         btFollowMe = root.findViewById(R.id.ic_follow_me);
 
         //setup FolderOverlay
         stopsFolderOverlay = new FolderOverlay();
 
 
         //Start map from bundle
         if (savedInstanceState !=null)
             startMap(getArguments(), savedInstanceState);
         else startMap(getArguments(), savedMapState);
         //set listeners
         map.addMapListener(new DelayedMapListener(new MapListener() {
 
             @Override
             public boolean onScroll(ScrollEvent paramScrollEvent) {
                 requestStopsToShow();
                 //Log.d(DEBUG_TAG, "Scrolling");
                 //if (moveTriggeredByCode) moveTriggeredByCode =false;
                 //else setLocationFollowing(false);
                 return true;
             }
 
             @Override
             public boolean onZoom(ZoomEvent event) {
                 requestStopsToShow();
                 return true;
             }
 
         }));
 
 
         btCenterMap.setOnClickListener(v -> {
             //Log.i(TAG, "centerMap clicked ");
             if(Permissions.locationPermissionGranted(getContext())) {
                 final GeoPoint myPosition = mLocationOverlay.getMyLocation();
                 map.getController().animateTo(myPosition);
             } else
                 Toast.makeText(getContext(), R.string.enable_position_message_map, Toast.LENGTH_SHORT)
                         .show();
         });
 
         btFollowMe.setOnClickListener(v -> {
             //Log.i(TAG, "btFollowMe clicked ");
             if(Permissions.locationPermissionGranted(getContext()))
                 setLocationFollowing(!followingLocation);
             else
                 Toast.makeText(getContext(), R.string.enable_position_message_map, Toast.LENGTH_SHORT)
                     .show();
         });
 
         return root;
     }
 
     @Override
     public void onAttach(@NonNull Context context) {
         super.onAttach(context);
 
         if (context instanceof FragmentListenerMain) {
             listenerMain = (FragmentListenerMain) context;
         } else {
             throw new RuntimeException(context.toString()
                     + " must implement FragmentListenerMain");
         }
     }
     @Override
     public void onDetach() {
         super.onDetach();
         listenerMain = null;
         //    setupOnAttached = true;
         Log.w(DEBUG_TAG, "Fragment detached");
     }
 
     @Override
     public void onPause() {
         super.onPause();
         saveMapState();
         //cancel asynctask
         Log.w(DEBUG_TAG, "On pause called");
         if (stopFetcher!= null)
             stopFetcher.cancel(true);
     }
 
     /**
      * Save the map state inside the fragment
      * (calls saveMapState(bundle))
      */
     private void saveMapState(){
         savedMapState = new Bundle();
         saveMapState(savedMapState);
 
     }
 
     /**
      * Save the state of the map to restore it to a later time
      * @param bundle the bundle in which to save the data
      */
     private void saveMapState(Bundle bundle){
         final IGeoPoint loc = map.getMapCenter();
         bundle.putDouble(MAP_CENTER_LAT_KEY, loc.getLatitude());
         bundle.putDouble(MAP_CENTER_LON_KEY, loc.getLongitude());
         bundle.putDouble(MAP_CURRENT_ZOOM_KEY, map.getZoomLevelDouble());
         Log.d(DEBUG_TAG, "Saving state, location following: "+followingLocation);
         bundle.putBoolean(FOLLOWING_LOCAT_KEY, followingLocation);
 
     }
 
     @Override
     public void onResume() {
         super.onResume();
         if(listenerMain!=null) listenerMain.readyGUIfor(FragmentKind.MAP);
     }
 
     @Override
     public void onSaveInstanceState(@NonNull Bundle outState) {
         saveMapState(outState);
 
         super.onSaveInstanceState(outState);
     }
 
     //own methods
 
     /**
      * Switch following the location on and off
      * @param value true if we want to follow location
      */
     public void setLocationFollowing(Boolean value){
         followingLocation = value;
         if(mLocationOverlay==null || getContext() == null || map ==null)
             //nothing else to do
             return;
         if (value){
             mLocationOverlay.enableFollowLocation();
         } else {
             mLocationOverlay.disableFollowLocation();
         }
     }
 
     /**
      * Do all the stuff you need to do on the gui, when parameter is changed to value
      * @param following value
      */
     protected void updateGUIForLocationFollowing(boolean following){
         if (following)
             btFollowMe.setImageResource(R.drawable.ic_follow_me_on);
         else
             btFollowMe.setImageResource(R.drawable.ic_follow_me);
 
     }
 
     /**
      * Build the location overlay. Enable only when
      * a) we know we have the permission
      * b) the location map is set
      */
     private void startLocationOverlay(boolean enableLocation, MapView map){
         if(getActivity()== null) throw new IllegalStateException("Cannot enable LocationOverlay now");
         // Location Overlay
         // from OpenBikeSharing (THANK GOD)
         Log.d(DEBUG_TAG, "Starting position overlay");
         GpsMyLocationProvider imlp = new GpsMyLocationProvider(getActivity().getBaseContext());
         imlp.setLocationUpdateMinDistance(5);
         imlp.setLocationUpdateMinTime(2000);
 
         final LocationOverlay overlay = new LocationOverlay(imlp,map, locationCallbacks);
         if (enableLocation) overlay.enableMyLocation();
         overlay.setOptionsMenuEnabled(true);
 
         //map.getOverlays().add(this.mLocationOverlay);
         this.mLocationOverlay = overlay;
         map.getOverlays().add(mLocationOverlay);
     }
 
     public void startMap(Bundle incoming, Bundle savedInstanceState) {
         //Check that we're attached
         GeneralActivity activity = getActivity() instanceof GeneralActivity ? (GeneralActivity) getActivity() : null;
         if(getContext()==null|| activity==null){
             //we are not attached
             Log.e(DEBUG_TAG, "Calling startMap when not attached");
             return;
         }else{
             Log.d(DEBUG_TAG, "Starting map from scratch");
         }
         //clear previous overlays
         map.getOverlays().clear();
 
 
         //parse incoming bundle
         GeoPoint marker = null;
         String name = null;
         String ID = null;
         if (incoming != null) {
             double lat = incoming.getDouble(BUNDLE_LATIT);
             double lon = incoming.getDouble(BUNDLE_LONGIT);
             marker = new GeoPoint(lat, lon);
             name = incoming.getString(BUNDLE_NAME);
             ID = incoming.getString(BUNDLE_ID);
         }
 
 
        //ask for location permission
         if(!Permissions.locationPermissionGranted(activity)){
             if(shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)){
                 //TODO: show dialog for permission rationale
                 Toast.makeText(activity, R.string.enable_position_message_map, Toast.LENGTH_SHORT).show();
             }
             positionRequestLauncher.launch(Permissions.LOCATION_PERMISSIONS);
 
         }
 
         shownStops = new HashSet<>();
         // move the map on the marker position or on a default view point: Turin, Piazza Castello
         // and set the start zoom
         IMapController mapController = map.getController();
         GeoPoint startPoint = null;
         startLocationOverlay(Permissions.locationPermissionGranted(activity),
                 map);
         // set the center point
         if (marker != null) {
             //startPoint = marker;
             mapController.setZoom(POSITION_FOUND_ZOOM);
             setLocationFollowing(false);
             // put the center a little bit off (animate later)
             startPoint = new GeoPoint(marker);
             startPoint.setLatitude(marker.getLatitude()+ utils.angleRawDifferenceFromMeters(20));
             startPoint.setLongitude(marker.getLongitude()-utils.angleRawDifferenceFromMeters(20));
             //don't need to do all the rest since we want to show a point
         } else if (savedInstanceState != null && savedInstanceState.containsKey(MAP_CURRENT_ZOOM_KEY)) {
             mapController.setZoom(savedInstanceState.getDouble(MAP_CURRENT_ZOOM_KEY));
             mapController.setCenter(new GeoPoint(savedInstanceState.getDouble(MAP_CENTER_LAT_KEY),
                     savedInstanceState.getDouble(MAP_CENTER_LON_KEY)));
             Log.d(DEBUG_TAG, "Location following from savedInstanceState: "+savedInstanceState.getBoolean(FOLLOWING_LOCAT_KEY));
             setLocationFollowing(savedInstanceState.getBoolean(FOLLOWING_LOCAT_KEY));
         } else {
             Log.d(DEBUG_TAG, "No position found from intent or saved state");
             boolean found = false;
             LocationManager locationManager =
                     (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
             //check for permission
             if (locationManager != null && Permissions.locationPermissionGranted(activity)) {
 
                 @SuppressLint("MissingPermission")
                 Location userLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                 if (userLocation != null) {
                     mapController.setZoom(POSITION_FOUND_ZOOM);
                     startPoint = new GeoPoint(userLocation);
                     found = true;
                     setLocationFollowing(true);
                 }
             }
             if(!found){
                 startPoint = new GeoPoint(DEFAULT_CENTER_LAT, DEFAULT_CENTER_LON);
                 mapController.setZoom(NO_POSITION_ZOOM);
                 setLocationFollowing(false);
             }
         }
 
         // set the minimum zoom level
         map.setMinZoomLevel(15.0);
         //add contingency check (shouldn't happen..., but)
 
         if (startPoint != null) {
             mapController.setCenter(startPoint);
         }
 
 
         //add stops overlay
         //map.getOverlays().add(mLocationOverlay);
         map.getOverlays().add(this.stopsFolderOverlay);
 
         Log.d(DEBUG_TAG, "Requesting stops load");
         // This is not necessary, by setting the center we already move
         // the map and we trigger a stop request
         //requestStopsToShow();
         if (marker != null) {
             // make a marker with the info window open for the searched marker
             Marker stopMarker = makeMarker(marker, name , ID, true);
             map.getController().animateTo(marker);
         }
 
     }
 
     /**
      * Start a request to load the stops that are in the current view
      * from the database
      */
     private void requestStopsToShow(){
         // get the top, bottom, left and right screen's coordinate
         BoundingBox bb = map.getBoundingBox();
         double latFrom = bb.getLatSouth();
         double latTo = bb.getLatNorth();
         double lngFrom = bb.getLonWest();
         double lngTo = bb.getLonEast();
         if (stopFetcher!= null && stopFetcher.getStatus()!= AsyncTask.Status.FINISHED)
             stopFetcher.cancel(true);
         stopFetcher = new AsyncStopFetcher(this);
         stopFetcher.execute(
                 new AsyncStopFetcher.BoundingBoxLimit(lngFrom,lngTo,latFrom, latTo));
     }
 
     /**
      * Add stops as Markers on the map
      * @param stops the list of stops that must be included
      */
     protected void showStopsMarkers(List<Stop> stops){
         if (getContext() == null){
             //we are not attached
             return;
         }
         boolean good = true;
 
         for (Stop stop : stops) {
             if (shownStops.contains(stop.ID)){
                 continue;
             }
             if(stop.getLongitude()==null || stop.getLatitude()==null)
                 continue;
 
             shownStops.add(stop.ID);
             if(!map.isShown()){
                 if(good)
                 Log.d(DEBUG_TAG, "Need to show stop but map is not shown, probably detached already");
                 good = false;
                 continue;
             } else if(map.getRepository() == null){
                 Log.e(DEBUG_TAG, "Map view repository is null");
             }
             GeoPoint marker = new GeoPoint(stop.getLatitude(), stop.getLongitude());
 
             Marker stopMarker = makeMarker(marker, stop.getStopDefaultName(), stop.ID, false);
             stopsFolderOverlay.add(stopMarker);
             if (!map.getOverlays().contains(stopsFolderOverlay)) {
                 Log.w(DEBUG_TAG, "Map doesn't have folder overlay");
             }
             good=true;
         }
         //Log.d(DEBUG_TAG,"We have " +stopsFolderOverlay.getItems().size()+" stops in the folderOverlay");
         //force redraw of markers
         map.invalidate();
     }
 
     public Marker makeMarker(GeoPoint geoPoint, String stopName, String ID, boolean isStartMarker) {
 
         // add a marker
         final Marker marker = new Marker(map);
 
         // set custom info window as info window
         CustomInfoWindow popup = new CustomInfoWindow(map, ID, stopName, responder);
         marker.setInfoWindow(popup);
 
         // make the marker clickable
         marker.setOnMarkerClickListener((thisMarker, mapView) -> {
             if (thisMarker.isInfoWindowOpen()) {
                 // on second click
                 Log.w(DEBUG_TAG, "Pressed on the click marker");
             } else {
                 // on first click
 
                 // hide all opened info window
                 InfoWindow.closeAllInfoWindowsOn(map);
                 // show this particular info window
                 thisMarker.showInfoWindow();
                 // move the map to its position
                 map.getController().animateTo(thisMarker.getPosition());
             }
 
             return true;
         });
 
         // set its position
         marker.setPosition(geoPoint);
         marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
         // add to it an icon
         //marker.setIcon(getResources().getDrawable(R.drawable.bus_marker));
 
         marker.setIcon(ResourcesCompat.getDrawable(getResources(), R.drawable.bus_marker, ctx.getTheme()));
         // add to it a title
         marker.setTitle(stopName);
         // set the description as the ID
         marker.setSnippet(ID);
 
         // show popup info window of the searched marker
         if (isStartMarker) {
             marker.showInfoWindow();
             //map.getController().animateTo(marker.getPosition());
         }
 
         return marker;
     }
 
+    @Nullable
+    @org.jetbrains.annotations.Nullable
+    @Override
+    public View getBaseViewForSnackBar() {
+        return null;
+    }
+
     /**
      * Simple asyncTask class to load the stops in the background
      * Holds a weak reference to the fragment to do callbacks
      */
     static class AsyncStopFetcher extends AsyncTask<AsyncStopFetcher.BoundingBoxLimit,Void, List<Stop>>{
 
         final WeakReference<MapFragment> fragmentWeakReference;
 
         public AsyncStopFetcher(MapFragment fragment) {
             this.fragmentWeakReference = new WeakReference<>(fragment);
         }
 
         @Override
         protected List<Stop> doInBackground(BoundingBoxLimit... limits) {
             if(fragmentWeakReference.get()==null || fragmentWeakReference.get().getContext() == null){
                 Log.w(DEBUG_TAG, "AsyncLoad fragmentWeakreference null");
 
                 return null;
 
             }
             final BoundingBoxLimit limit = limits[0];
             //Log.d(DEBUG_TAG, "Async Stop Fetcher started working");
 
             NextGenDB dbHelper = new NextGenDB(fragmentWeakReference.get().getContext());
             Stop[] stops = dbHelper.queryAllInsideMapView(limit.latitFrom, limit.latitTo,
                     limit.longFrom, limit.latitTo);
             dbHelper.close();
             return Arrays.asList(stops);
         }
 
         @Override
         protected void onPostExecute(List<Stop> stops) {
             super.onPostExecute(stops);
             //Log.d(DEBUG_TAG, "Async Stop Fetcher has finished working");
             if(fragmentWeakReference.get()==null) {
                 Log.w(DEBUG_TAG, "AsyncLoad fragmentWeakreference null");
                 return;
             }
             Log.d(DEBUG_TAG, "AsyncLoad number of stops: "+stops.size());
             fragmentWeakReference.get().showStopsMarkers(stops);
         }
 
         private static class BoundingBoxLimit{
             final double longFrom, longTo, latitFrom, latitTo;
 
             public BoundingBoxLimit(double longFrom, double longTo, double latitFrom, double latitTo) {
                 this.longFrom = longFrom;
                 this.longTo = longTo;
                 this.latitFrom = latitFrom;
                 this.latitTo = latitTo;
             }
         }
 
     }
 }
diff --git a/src/it/reyboz/bustorino/fragments/BaseFragment.java b/src/it/reyboz/bustorino/fragments/ScreenBaseFragment.java
similarity index 81%
rename from src/it/reyboz/bustorino/fragments/BaseFragment.java
rename to src/it/reyboz/bustorino/fragments/ScreenBaseFragment.java
index c1359ab..e8e6d86 100644
--- a/src/it/reyboz/bustorino/fragments/BaseFragment.java
+++ b/src/it/reyboz/bustorino/fragments/ScreenBaseFragment.java
@@ -1,45 +1,55 @@
 package it.reyboz.bustorino.fragments;
 
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Toast;
 
+import androidx.annotation.Nullable;
 import androidx.fragment.app.Fragment;
 
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
 import it.reyboz.bustorino.BuildConfig;
 
 import static android.content.Context.MODE_PRIVATE;
 
-public abstract class BaseFragment extends Fragment {
+public abstract class ScreenBaseFragment extends Fragment {
 
     protected String PREF_FILE= BuildConfig.APPLICATION_ID+".fragment_prefs";
 
     protected void setOption(String optionName, boolean value) {
         Context mContext = getContext();
         SharedPreferences.Editor editor = mContext.getSharedPreferences(PREF_FILE, MODE_PRIVATE).edit();
         editor.putBoolean(optionName, value);
         editor.commit();
     }
 
     protected boolean getOption(String optionName, boolean optDefault) {
         Context mContext = getContext();
         SharedPreferences preferences = mContext.getSharedPreferences(PREF_FILE, MODE_PRIVATE);
         return preferences.getBoolean(optionName, optDefault);
     }
 
     protected void showToastMessage(int messageID, boolean short_lenght) {
         final int length = short_lenght ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG;
         Toast.makeText(getContext(), messageID, length).show();
     }
 
     public void hideKeyboard() {
+        if (getActivity()==null) return;
         View view = getActivity().getCurrentFocus();
         if (view != null) {
             ((InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE))
                     .hideSoftInputFromWindow(view.getWindowToken(),
                             InputMethodManager.HIDE_NOT_ALWAYS);
         }
     }
+
+    /**
+     * Find the view on which the snackbar should be shown
+     * @return
+     */
+    @Nullable
+    public abstract View getBaseViewForSnackBar();
 }
diff --git a/src/it/reyboz/bustorino/middleware/AsyncStopsSearcher.java b/src/it/reyboz/bustorino/middleware/AsyncStopsSearcher.java
index 4f65a23..ed60ed8 100644
--- a/src/it/reyboz/bustorino/middleware/AsyncStopsSearcher.java
+++ b/src/it/reyboz/bustorino/middleware/AsyncStopsSearcher.java
@@ -1,131 +1,131 @@
 /*
 	BusTO (middleware)
     Copyright (C) 2021 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.os.AsyncTask;
 import android.util.Log;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 
 import it.reyboz.bustorino.backend.Fetcher;
 import it.reyboz.bustorino.backend.Stop;
 import it.reyboz.bustorino.backend.StopsFinderByName;
 import it.reyboz.bustorino.fragments.FragmentHelper;
 
 public class AsyncStopsSearcher extends AsyncTask<String, Fetcher.Result, List<Stop>> {
 
     private static final String TAG = "BusTO-StopsSearcher";
     private static final String DEBUG_TAG = TAG;
     private final StopsFinderByName[] fetchers;
     private final AtomicReference<Fetcher.Result> res;
 
     private WeakReference<FragmentHelper> helperWR;
 
     private String theQuery;
 
     public AsyncStopsSearcher(FragmentHelper fh, StopsFinderByName[] fetchers) {
         this.fetchers = fetchers;
         if (fetchers.length < 1){
             throw new IllegalArgumentException("You have to put at least one Fetcher, idiot!");
         }
 
         this.res = new AtomicReference<>();
         this.helperWR = new WeakReference<>(fh);
         fh.setLastTaskRef(this);
 
     }
 
     @Override
     protected List<Stop> doInBackground(String... strings) {
         RecursionHelper<StopsFinderByName> r = new RecursionHelper<>(fetchers);
         if (helperWR.get()==null || strings.length == 0)
             return null;
         Log.d(DEBUG_TAG,"Running with query "+strings[0]);
 
         ArrayList<Fetcher.Result> results = new ArrayList<>();
         List<Stop> resultsList;
         while (r.valid()){
             if (this.isCancelled()) return null;
 
             final StopsFinderByName finder = r.getAndMoveForward();
             theQuery = strings[0].trim();
             resultsList = finder.FindByName(theQuery, res);
             Log.d(DEBUG_TAG, "Result: "+res.get()+", "+resultsList.size()+" stops");
 
             if (res.get()== Fetcher.Result.OK){
                 return resultsList;
             }
             results.add(res.get());
         }
         boolean emptyResults = true;
         for (Fetcher.Result re: results){
             if (!re.equals(Fetcher.Result.EMPTY_RESULT_SET)) {
                 emptyResults = false;
                 break;
             }
         }
         if(emptyResults){
             publishProgress(Fetcher.Result.EMPTY_RESULT_SET);
         }
         return new ArrayList<>();
     }
 
     @Override
     protected void onProgressUpdate(Fetcher.Result... values) {
         FragmentHelper fh = helperWR.get();
         if (fh!=null)
             for (Fetcher.Result r : values){
                 fh.showErrorMessage(r, SearchRequestType.STOPS);
             }
         else {
             Log.w(TAG,"We had to show some progress but activity was destroyed");
         }
     }
     @Override
     protected void onCancelled() {
         FragmentHelper fh = helperWR.get();
         if (fh!=null) fh.toggleSpinner(false);
     }
 
     @Override
     protected void onPreExecute() {
         FragmentHelper fh = helperWR.get();
         if (fh!=null) fh.toggleSpinner(true);
     }
 
     @Override
     protected void onPostExecute(List<Stop> stops) {
         final FragmentHelper fh = helperWR.get();
 
-        if (stops==null || fh==null || theQuery==null) {
+        if (stops==null || stops.size() == 0 || fh==null || theQuery==null) {
             if (fh!=null) fh.toggleSpinner(false);
             cancel(true);
             return;
         }
         if(isCancelled()){
             fh.toggleSpinner(false);
             return;
         }
         fh.createStopListFragment(stops, theQuery, true);
 
 
     }
 }