diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -13,10 +13,12 @@
     <queries>
         <intent>
             <action android:name="android.intent.action.VIEW"/>
+
             <data android:scheme="http"/>
         </intent>
         <intent>
             <action android:name="android.intent.action.VIEW"/>
+
             <data android:scheme="https"/>
         </intent>
         <intent>
@@ -35,6 +37,9 @@
             android:networkSecurityConfig="@xml/networks_security_config"
             android:roundIcon="@mipmap/ic_launcher_round"
             android:theme="@style/AppTheme.NoActionBar">
+        <activity
+                android:name=".ActivityIntro"
+                android:exported="false"/>
         <activity
                 android:name=".ActivityExperiments"
                 android:label="@string/experiments"
@@ -87,7 +92,7 @@
         </activity>
         <activity
                 android:name=".ActivityAbout"
-                android:label="@string/about"
+                android:label="@string/about_activity"
                 android:parentActivityName=".ActivityPrincipal"
                 android:theme="@style/AboutTheme">
 
@@ -102,8 +107,7 @@
                 android:authorities="it.reyboz.bustorino.provider"
                 android:enabled="true"
                 android:exported="false">
-        </provider>
-        <!-- Don't show the additional frame on samsung phones -->
+        </provider> <!-- Don't show the additional frame on samsung phones -->
         <meta-data
                 android:name="com.samsung.android.icon_container.has_icon_container"
                 android:value="true"/>
diff --git a/app/src/main/java/it/reyboz/bustorino/ActivityAbout.java b/app/src/main/java/it/reyboz/bustorino/ActivityAbout.java
--- a/app/src/main/java/it/reyboz/bustorino/ActivityAbout.java
+++ b/app/src/main/java/it/reyboz/bustorino/ActivityAbout.java
@@ -32,6 +32,7 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import it.reyboz.bustorino.backend.utils;
 import it.reyboz.bustorino.middleware.BarcodeScanUtils;
 
 public class ActivityAbout extends AppCompatActivity {
@@ -40,7 +41,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_about);
-        Spanned htmlText = Html.fromHtml(getResources().getString(
+        Spanned htmlText = utils.convertHtml(getResources().getString(
                 R.string.about_history));
         TextView aboutTextView = findViewById(R.id.aboutTextView);
         assert aboutTextView != null;
diff --git a/app/src/main/java/it/reyboz/bustorino/ActivityExperiments.java b/app/src/main/java/it/reyboz/bustorino/ActivityExperiments.java
--- a/app/src/main/java/it/reyboz/bustorino/ActivityExperiments.java
+++ b/app/src/main/java/it/reyboz/bustorino/ActivityExperiments.java
@@ -36,7 +36,7 @@
 
         ActionBar actionBar = getSupportActionBar();
         if (actionBar != null) {
-            actionBar.setDisplayHomeAsUpEnabled(true);
+            actionBar.setDisplayHomeAsUpEnabled(false);
             actionBar.setIcon(R.drawable.ic_launcher);
         }
         if (savedInstanceState==null) {
@@ -48,13 +48,14 @@
                             LinesDetailFragment.Companion.makeArgs("gtt:4U"))
 
                     */
-                    .add(R.id.fragment_container_view, LinesGridShowingFragment.class, null)
-                    .commit();
+                    //.add(R.id.fragment_container_view, LinesGridShowingFragment.class, null)
+                    //.add(R.id.fragment_container_view, IntroFragment.class, IntroFragment.makeArguments(0))
+                    //.commit();
 
                     //.add(R.id.fragment_container_view, LinesDetailFragment.class,
                     //        LinesDetailFragment.Companion.makeArgs("gtt:4U"))
-                    //.add(R.id.fragment_container_view, TestRealtimeGtfsFragment.class, null)
-                    //.commit();
+                    .add(R.id.fragment_container_view, TestRealtimeGtfsFragment.class, null)
+                    .commit();
         }
     }
 
diff --git a/app/src/main/java/it/reyboz/bustorino/ActivityIntro.kt b/app/src/main/java/it/reyboz/bustorino/ActivityIntro.kt
new file mode 100644
--- /dev/null
+++ b/app/src/main/java/it/reyboz/bustorino/ActivityIntro.kt
@@ -0,0 +1,107 @@
+package it.reyboz.bustorino
+
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import android.widget.ImageButton
+import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentActivity
+import androidx.viewpager2.adapter.FragmentStateAdapter
+import androidx.viewpager2.widget.ViewPager2
+import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
+import com.google.android.material.tabs.TabLayout
+import com.google.android.material.tabs.TabLayoutMediator
+import it.reyboz.bustorino.data.PreferencesHolder
+import it.reyboz.bustorino.fragments.IntroFragment
+
+class ActivityIntro : AppCompatActivity(), IntroFragment.IntroListener {
+
+    private lateinit var viewPager : ViewPager2
+    private lateinit var btnForward: ImageButton
+    private lateinit var btnBackward: ImageButton
+
+    private var restartMain = true
+
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_intro)
+
+        viewPager = findViewById(R.id.viewPager)
+        btnBackward = findViewById(R.id.btnPrevious)
+        btnForward = findViewById(R.id.btnNext)
+
+        val extras = intent.extras
+        if(extras!=null){
+            restartMain = extras.getBoolean(RESTART_MAIN)
+        }
+
+
+        val adapter = IntroPagerAdapter(this)
+        viewPager.adapter = adapter
+
+        val tabLayout = findViewById<TabLayout>(R.id.tab_layout)
+        val tabLayoutMediator = TabLayoutMediator(tabLayout, viewPager) { tab, pos ->
+            Log.d(DEBUG_TAG, "tabview on position $pos")
+
+        }
+        tabLayoutMediator.attach()
+
+
+        btnForward.setOnClickListener {
+            viewPager.setCurrentItem(viewPager.currentItem+1,true)
+        }
+        btnBackward.setOnClickListener {
+            viewPager.setCurrentItem(viewPager.currentItem-1, true)
+        }
+
+        viewPager.registerOnPageChangeCallback(object : OnPageChangeCallback() {
+
+            override fun onPageSelected(position: Int) {
+                if(position == 0){
+                    btnBackward.visibility = View.INVISIBLE
+                } else{
+                    btnBackward.visibility = View.VISIBLE
+                }
+                if(position == NUM_ITEMS-1){
+                    btnForward.visibility = View.INVISIBLE
+                } else{
+                    btnForward.visibility = View.VISIBLE
+                }
+            }
+
+        })
+    }
+
+
+
+    /**
+     * A simple pager adapter that represents 5 ScreenSlidePageFragment objects, in
+     * sequence.
+     */
+    private inner class IntroPagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
+        override fun getItemCount(): Int = NUM_ITEMS
+
+        override fun createFragment(position: Int): Fragment = IntroFragment.newInstance(position)
+    }
+
+    companion object{
+        const private val DEBUG_TAG = "BusTO-IntroActivity"
+        const val RESTART_MAIN = "restartMainActivity"
+
+        const val NUM_ITEMS = 7
+    }
+
+    override fun closeIntroduction() {
+        if(restartMain) startActivity(Intent(this, ActivityPrincipal::class.java))
+        val pref = PreferencesHolder.getMainSharedPreferences(this)
+        val editor = pref.edit()
+        editor.putBoolean(PreferencesHolder.PREF_INTRO_ACTIVITY_RUN, true)
+        //use commit so we don't "lose" info
+        editor.commit()
+        finish()
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/it/reyboz/bustorino/ActivityPrincipal.java b/app/src/main/java/it/reyboz/bustorino/ActivityPrincipal.java
--- a/app/src/main/java/it/reyboz/bustorino/ActivityPrincipal.java
+++ b/app/src/main/java/it/reyboz/bustorino/ActivityPrincipal.java
@@ -82,26 +82,8 @@
         super.onCreate(savedInstanceState);
         Log.d(DEBUG_TAG, "onCreate, savedInstanceState is: "+savedInstanceState);
         setContentView(R.layout.activity_principal);
-        final SharedPreferences theShPr = getMainSharedPreferences();
         boolean showingArrivalsFromIntent = false;
 
-        //database check
-        GtfsDatabase gtfsDB = GtfsDatabase.Companion.getGtfsDatabase(this);
-
-        final int db_version = gtfsDB.getOpenHelper().getReadableDatabase().getVersion();
-        boolean dataUpdateRequested = false;
-        final int old_version = PreferencesHolder.getGtfsDBVersion(theShPr);
-        Log.d(DEBUG_TAG, "GTFS Database: old version is "+old_version+ ", new version is "+db_version);
-        if (old_version < db_version){
-            //decide update conditions in the future
-            if(old_version < 2 && db_version >= 2) {
-                dataUpdateRequested = true;
-                DatabaseUpdate.requestDBUpdateWithWork(this, true, true);
-            }
-            PreferencesHolder.setGtfsDBVersion(theShPr, db_version);
-        }
-
-
         Toolbar mToolbar = findViewById(R.id.default_toolbar);
         setSupportActionBar(mToolbar);
         if (getSupportActionBar()!=null)
@@ -200,6 +182,23 @@
             requestArrivalsForStopID(busStopID); //this shows the fragment, too
             showingArrivalsFromIntent = true;
         }
+        //database check
+        GtfsDatabase gtfsDB = GtfsDatabase.Companion.getGtfsDatabase(this);
+
+        final int db_version = gtfsDB.getOpenHelper().getReadableDatabase().getVersion();
+        boolean dataUpdateRequested = false;
+        final SharedPreferences theShPr = getMainSharedPreferences();
+
+        final int old_version = PreferencesHolder.getGtfsDBVersion(theShPr);
+        Log.d(DEBUG_TAG, "GTFS Database: old version is "+old_version+ ", new version is "+db_version);
+        if (old_version < db_version){
+            //decide update conditions in the future
+            if(old_version < 2 && db_version >= 2) {
+                dataUpdateRequested = true;
+                DatabaseUpdate.requestDBUpdateWithWork(this, true, true);
+            }
+            PreferencesHolder.setGtfsDBVersion(theShPr, db_version);
+        }
         //Try (hopefully) database update
         if(!dataUpdateRequested)
             DatabaseUpdate.requestDBUpdateWithWork(this, false, false);
@@ -259,6 +258,12 @@
 
         //last but not least, set the good default values
         manageDefaultValuesForSettings();
+
+        //check if first run activity (IntroActivity) has been started once or not
+        boolean hasIntroRun = theShPr.getBoolean(PreferencesHolder.PREF_INTRO_ACTIVITY_RUN,false);
+        if(!hasIntroRun){
+            startIntroductionActivity();
+        }
     }
     private ActionBarDrawerToggle setupDrawerToggle(Toolbar toolbar) {
         // NOTE: Make sure you pass in a valid toolbar reference.  ActionBarDrawToggle() does not require it
@@ -703,6 +708,12 @@
         ft.commit();
     }
 
+    void startIntroductionActivity(){
+        Intent intent = new Intent(ActivityPrincipal.this, ActivityIntro.class);
+        intent.putExtra(ActivityIntro.RESTART_MAIN, false);
+        startActivity(intent);
+    }
+
     class ToolbarItemClickListener implements Toolbar.OnMenuItemClickListener{
         private final Context activityContext;
 
@@ -712,23 +723,27 @@
 
         @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:
+            final int id = item.getItemId();
+            if(id == R.id.action_about){
+                startActivity(new Intent(ActivityPrincipal.this, ActivityAbout.class));
+                return true;
+            } else if (id == R.id.action_hack) {
+                openIceweasel(getString(R.string.hack_url), activityContext);
+                return true;
+            } else if (id == R.id.action_source){
+                openIceweasel("https://gitpull.it/source/libre-busto/", activityContext);
+                return true;
+            } else if (id == R.id.action_licence){
+                openIceweasel("https://www.gnu.org/licenses/gpl-3.0.html", activityContext);
+                return true;
+            } else if (id == R.id.action_experiments) {
+                startActivity(new Intent(ActivityPrincipal.this, ActivityExperiments.class));
+                return true;
+            } else if (id == R.id.action_tutorial) {
+                startIntroductionActivity();
+                return true;
             }
+
             return false;
         }
     }
diff --git a/app/src/main/java/it/reyboz/bustorino/BustoApp.java b/app/src/main/java/it/reyboz/bustorino/BustoApp.java
--- a/app/src/main/java/it/reyboz/bustorino/BustoApp.java
+++ b/app/src/main/java/it/reyboz/bustorino/BustoApp.java
@@ -56,4 +56,5 @@
             ACRA.init(this, builder);
 
     }
+
 }
diff --git a/app/src/main/java/it/reyboz/bustorino/backend/utils.java b/app/src/main/java/it/reyboz/bustorino/backend/utils.java
--- a/app/src/main/java/it/reyboz/bustorino/backend/utils.java
+++ b/app/src/main/java/it/reyboz/bustorino/backend/utils.java
@@ -20,9 +20,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.Uri;
+import android.os.Build;
+import android.text.Html;
+import android.text.Spanned;
 import android.util.Log;
 import android.util.TypedValue;
 import androidx.annotation.Nullable;
@@ -91,7 +95,10 @@
     }
 
     public static float convertDipToPixels(Context con, float dp){
-        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,con.getResources().getDisplayMetrics());
+        return convertDipToPixels(con.getResources(), dp);
+    }
+    public static float convertDipToPixels(Resources res, float dp){
+        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,res.getDisplayMetrics());
     }
 
     /*
@@ -372,4 +379,12 @@
         }
         return sb.toString();
     }
+
+    public static Spanned convertHtml(String text) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            return Html.fromHtml(text, Html.FROM_HTML_MODE_COMPACT);
+        } else {
+            return Html.fromHtml(text);
+        }
+    }
 }
diff --git a/app/src/main/java/it/reyboz/bustorino/data/PreferencesHolder.java b/app/src/main/java/it/reyboz/bustorino/data/PreferencesHolder.java
--- a/app/src/main/java/it/reyboz/bustorino/data/PreferencesHolder.java
+++ b/app/src/main/java/it/reyboz/bustorino/data/PreferencesHolder.java
@@ -31,6 +31,7 @@
 public abstract class PreferencesHolder {
 
     public static final String PREF_GTFS_DB_VERSION = "gtfs_db_version";
+    public static final String PREF_INTRO_ACTIVITY_RUN ="pref_intro_activity_run";
 
     public static SharedPreferences getMainSharedPreferences(Context context){
         return context.getSharedPreferences(context.getString(R.string.mainSharedPreferences), MODE_PRIVATE);
@@ -48,4 +49,14 @@
         ed.putInt(PREF_GTFS_DB_VERSION,version);
         ed.apply();
     }
+
+    /**
+     * Check if the introduction activity has been run at least one
+     * @param con the context needed
+     * @return true if it has been run
+     */
+    public static boolean hasIntroFinishedOneShot(Context con){
+        final SharedPreferences pref = getMainSharedPreferences(con);
+        return pref.getBoolean(PREF_INTRO_ACTIVITY_RUN, false);
+    }
 }
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/IntroFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/IntroFragment.kt
new file mode 100644
--- /dev/null
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/IntroFragment.kt
@@ -0,0 +1,151 @@
+package it.reyboz.bustorino.fragments
+
+import android.content.Context
+import android.graphics.BitmapFactory
+import android.graphics.text.LineBreaker
+import android.os.Build
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.fragment.app.Fragment
+import it.reyboz.bustorino.R
+import it.reyboz.bustorino.backend.utils
+import java.lang.IllegalStateException
+
+
+// TODO: Rename parameter arguments, choose names that match
+// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
+private const val SCREEN_INDEX = "screenindex"
+
+/**
+ * A simple [Fragment] subclass.
+ * Use the [IntroFragment.newInstance] factory method to
+ * create an instance of this fragment.
+ */
+class IntroFragment : Fragment() {
+    // TODO: Rename and change types of parameters
+    private var screenIndex = 1
+    private lateinit var imageHolder: ImageView
+    private lateinit var textView: TextView
+
+
+    private lateinit var listener: IntroListener
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        arguments?.let {
+            screenIndex = it.getInt(SCREEN_INDEX)
+        }
+    }
+
+    override fun onAttach(context: Context) {
+        super.onAttach(context)
+        if(context !is IntroListener){
+            throw IllegalStateException("Context must implement IntroListener")
+        }
+        listener = context
+    }
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        // Inflate the layout for this fragment
+        val root=  inflater.inflate(R.layout.fragment_intro, container, false)
+        imageHolder = root.findViewById(R.id.image_tutorial)
+        textView = root.findViewById(R.id.tutorialTextView)
+
+
+        when(screenIndex){
+            0 -> {
+                setImageBitmap(imageHolder, R.drawable.tuto_busto, 300f)
+                textView.text = utils.convertHtml(getString(R.string.tutorial_first))
+            }
+
+            1->{
+                setImageBitmap(imageHolder, R.drawable.tuto_search)
+                setTextHtmlDescription(R.string.tutorial_search)
+            }
+            2 ->{
+                setImageBitmap(imageHolder, R.drawable.tuto_arrivals)
+                textView.text = utils.convertHtml(getString(R.string.tutorial_arrivals))
+            }
+            3 ->{
+                setImageBitmap(imageHolder, R.drawable.tuto_stops)
+                textView.text = utils.convertHtml(getString(R.string.tutorial_stops))
+            }
+            4 ->{
+                setImageBitmap(imageHolder, R.drawable.tuto_map)
+                textView.text = utils.convertHtml(getString(R.string.tutorial_map))
+            }
+            5 ->{
+                setImageBitmap(imageHolder, R.drawable.tuto_line_det)
+                textView.text = utils.convertHtml(getString(R.string.tutorial_line))
+            }
+            6-> {
+                setImageBitmap(imageHolder,R.drawable.tuto_menu)
+                setTextHtmlDescription(R.string.tutorial_menu)
+                val closeButton = root.findViewById<Button>(R.id.closeAllButton)
+                closeButton.visibility = View.VISIBLE
+                closeButton.setOnClickListener {
+                    listener.closeIntroduction()
+                }
+            }
+        }
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+            textView.breakStrategy = LineBreaker.BREAK_STRATEGY_HIGH_QUALITY
+        }
+
+        return root
+    }
+
+    private fun setTextHtmlDescription(resId: Int){
+        textView.text = utils.convertHtml(getString(resId))
+    }
+
+
+    private fun setImageBitmap(imageView: ImageView, resId: Int, maxDpToScale:Float = DP_LIM_IMAGE){
+        val bitmap = BitmapFactory.decodeResource(resources,resId)
+        /*val limPix = utils.convertDipToPixels(resources, maxDpToScale)
+        if (bitmap.width > limPix) {
+            val rescFac = limPix/bitmap.width
+            val rescaledBitmap = Bitmap.createScaledBitmap(bitmap,(limPix).toInt(), (bitmap.height*rescFac).toInt(),false)
+            imageView.setImageBitmap(rescaledBitmap)
+        }
+        else
+        */
+        imageView.setImageBitmap(bitmap)
+
+    }
+
+    companion object {
+
+        const val DP_LIM_IMAGE = 1000f
+        /**
+         * Use this factory method to create a new instance of
+         * this fragment using the provided parameters.
+         *
+         * @param index the screen index
+         * @return A new instance of fragment IntroFragment.
+         */
+        @JvmStatic
+        fun newInstance(index: Int) =
+            IntroFragment().apply {
+                arguments = Bundle().apply {
+                    putInt(SCREEN_INDEX, index)
+                }
+            }
+        @JvmStatic
+        fun makeArguments(index: Int) = Bundle().apply {
+            putInt(SCREEN_INDEX, index) }
+
+    }
+
+    interface IntroListener{
+        fun closeIntroduction()
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java
--- a/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java
@@ -4,6 +4,7 @@
 import android.Manifest;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.location.Criteria;
 import android.location.Location;
@@ -32,12 +33,9 @@
 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.FrameLayout;
-import android.widget.ImageButton;
 import android.widget.ProgressBar;
-import android.widget.TextView;
 import android.widget.Toast;
 
 import com.google.android.material.floatingactionbutton.FloatingActionButton;
@@ -47,6 +45,7 @@
 
 import it.reyboz.bustorino.R;
 import it.reyboz.bustorino.backend.*;
+import it.reyboz.bustorino.data.PreferencesHolder;
 import it.reyboz.bustorino.middleware.AppLocationManager;
 import it.reyboz.bustorino.middleware.AsyncArrivalsSearcher;
 import it.reyboz.bustorino.middleware.AsyncStopsSearcher;
@@ -88,7 +87,6 @@
 
     private boolean setupOnStart = true;
     private boolean suppressArrivalsReload = false;
-    private boolean instanceStateSaved = false;
     //private Snackbar snackbar;
     /*
      * Search mode
@@ -153,7 +151,8 @@
             });
 
     /// LOCATION STUFF ///
-    boolean pendingNearbyStopsRequest = false;
+    boolean pendingIntroRun = false;
+    boolean pendingNearbyStopsFragmentRequest = false;
     boolean locationPermissionGranted, locationPermissionAsked = false;
     AppLocationManager locationManager;
     private final ActivityResultLauncher<String[]> requestPermissionLauncher =
@@ -169,7 +168,8 @@
                     boolean resCoarse = result.get(Manifest.permission.ACCESS_COARSE_LOCATION);
                     boolean resFine = result.get(Manifest.permission.ACCESS_FINE_LOCATION);
                     Log.d(DEBUG_TAG, "Permissions for location are: "+result);
-                    if(result.get(Manifest.permission.ACCESS_COARSE_LOCATION) && result.get(Manifest.permission.ACCESS_FINE_LOCATION)){
+                    if(Boolean.TRUE.equals(result.get(Manifest.permission.ACCESS_COARSE_LOCATION))
+                            && Boolean.TRUE.equals(result.get(Manifest.permission.ACCESS_FINE_LOCATION))){
                         locationPermissionGranted = true;
                         Log.w(DEBUG_TAG, "Starting position");
                         if (mListener!= null && getContext()!=null){
@@ -180,12 +180,12 @@
                         // show nearby fragment
                         //showNearbyStopsFragment();
                         Log.d(DEBUG_TAG, "We have location permission");
-                        if(pendingNearbyStopsRequest){
+                        if(pendingNearbyStopsFragmentRequest){
                             showNearbyFragmentIfNeeded(cr);
-                            pendingNearbyStopsRequest = false;
+                            pendingNearbyStopsFragmentRequest = false;
                         }
                     }
-                    if(pendingNearbyStopsRequest) pendingNearbyStopsRequest=false;
+                    if(pendingNearbyStopsFragmentRequest) pendingNearbyStopsFragmentRequest =false;
                 }
             });
 
@@ -228,7 +228,7 @@
                 if(!checkLocationPermission())
                     Log.e(DEBUG_TAG, "Asking to show nearbystopfragment when " +
                             "we have no location permission");
-                pendingNearbyStopsRequest = true;
+                pendingNearbyStopsFragmentRequest = true;
                 //mainHandler.post(new NearbyStopsRequester(getContext(), cr));
                 showNearbyFragmentIfNeeded(cr);
             }
@@ -335,7 +335,6 @@
         Log.d(DEBUG_TAG, "OnCreateView, savedInstanceState null: "+(savedInstanceState==null));
 
 
-
         return root;
     }
 
@@ -357,7 +356,6 @@
         if (getChildFragmentManager().findFragmentById(R.id.resultFrame)!= null){
             swipeRefreshLayout.setVisibility(View.VISIBLE);
         }
-        instanceStateSaved = false;
 
     }
 
@@ -370,7 +368,6 @@
             getChildFragmentManager().putFragment(outState, SAVED_FRAGMENT, fragment);
         if (fragmentHelper!=null) fragmentHelper.setBlockAllActivities(true);
 
-        instanceStateSaved = true;
     }
 
     public void setSuppressArrivalsReload(boolean value){
@@ -428,16 +425,21 @@
         Log.d(DEBUG_TAG, "onStart called, setupOnStart: "+setupOnStart);
         if (setupOnStart) {
             if (pendingStopID==null){
-                //We want the nearby bus stops!
-                //mainHandler.post(new NearbyStopsRequester(getContext(), cr));
-                Log.d(DEBUG_TAG, "Showing nearby stops");
-                if(!checkLocationPermission()){
-                    requestLocationPermission();
-                    pendingNearbyStopsRequest = true;
-                }
-                else {
-                    showNearbyFragmentIfNeeded(cr);
+
+                if(PreferencesHolder.hasIntroFinishedOneShot(requireContext())){
+                    Log.d(DEBUG_TAG, "Showing nearby stops");
+                    if(!checkLocationPermission()){
+                        requestLocationPermission();
+                        pendingNearbyStopsFragmentRequest = true;
+                    }
+                    else {
+                        showNearbyFragmentIfNeeded(cr);
+                    }
+                } else {
+                    //The Introductory Activity is about to be started, hence pause the request and show later
+                    pendingIntroRun = true;
                 }
+
             }
             else{
                 ///TODO: if there is a stop displayed, we need to hold the update
@@ -449,23 +451,30 @@
 
     @Override
     public void onResume() {
+        super.onResume();
 
-        final Context con = getContext();
+        final Context con = requireContext();
         Log.w(DEBUG_TAG, "OnResume called, setupOnStart: "+ setupOnStart);
-        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);
-            } //don't request permission
-        }
-        else {
-            Log.w(DEBUG_TAG, "Context is null at onResume");
-        }
-        super.onResume();
+        if (locationManager == null)
+            locationManager = AppLocationManager.getInstance(con);
+        //recheck the introduction activity has been run
+        if(pendingIntroRun && PreferencesHolder.hasIntroFinishedOneShot(con)){
+            //request position permission if needed
+            if(!checkLocationPermission()){
+                requestLocationPermission();
+                pendingNearbyStopsFragmentRequest = true;
+            }
+            else {
+                showNearbyFragmentIfNeeded(cr);
+            }
+            //deactivate flag
+            pendingIntroRun = false;
+        }
+        if(Permissions.locationPermissionGranted(con)){
+            Log.d(DEBUG_TAG, "Location permission OK");
+            if(!locationManager.isRequesterRegistered(requester))
+                locationManager.addLocationRequestFor(requester);
+        } //don't request permission
         // 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
@@ -654,9 +663,9 @@
             FragmentTransaction ft = fragMan.beginTransaction();
 
             ft.replace(R.id.resultFrame, fragment, NearbyStopsFragment.FRAGMENT_TAG);
-            if (getActivity()!=null && !getActivity().isFinishing() &&!instanceStateSaved)
+            if (getActivity()!=null && !getActivity().isFinishing())
             ft.commit();
-            else Log.e(DEBUG_TAG, "Not showing nearby fragment because we saved instanceState");
+            else Log.e(DEBUG_TAG, "Not showing nearby fragment because activity null or is finishing");
         }
     }
 
@@ -680,9 +689,9 @@
         if (fragmentType == FragmentKind.ARRIVALS || fragmentType == FragmentKind.STOPS) {
             hideKeyboard();
 
-            if (pendingNearbyStopsRequest) {
+            if (pendingNearbyStopsFragmentRequest) {
                 locationManager.removeLocationRequestFor(requester);
-                pendingNearbyStopsRequest = false;
+                pendingNearbyStopsFragmentRequest = false;
             }
         }
 
@@ -788,9 +797,9 @@
                 && fragmentHelper.getLastSuccessfullySearchedBusStop() == null
                 && !fragMan.isDestroyed()) {
             //Go ahead with the request
-            Log.d("mainActivity", "Recreating stop fragment");
+
             actuallyShowNearbyStopsFragment();
-            pendingNearbyStopsRequest = false;
+            pendingNearbyStopsFragmentRequest = false;
         } else if(!haveProviders){
             Log.e(DEBUG_TAG, "NO PROVIDERS FOR POSITION");
         }
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/MapFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/MapFragment.java
--- a/app/src/main/java/it/reyboz/bustorino/fragments/MapFragment.java
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/MapFragment.java
@@ -390,6 +390,9 @@
         }
         */
         else Log.e(DEBUG_TAG, "livePositionsViewModel is null at onResume");
+
+        //rerequest stop
+        stopsViewModel.requestStopsInBoundingBox(map.getBoundingBox());
     }
 
     private void startRequestsPositions(){
diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/NearbyStopsFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/NearbyStopsFragment.java
--- a/app/src/main/java/it/reyboz/bustorino/fragments/NearbyStopsFragment.java
+++ b/app/src/main/java/it/reyboz/bustorino/fragments/NearbyStopsFragment.java
@@ -20,9 +20,7 @@
 import android.content.Context;
 
 import android.content.SharedPreferences;
-import android.database.Cursor;
 import android.location.Location;
-import android.net.Uri;
 import android.os.Bundle;
 
 import androidx.annotation.NonNull;
@@ -30,9 +28,6 @@
 import androidx.fragment.app.Fragment;
 import androidx.lifecycle.Observer;
 import androidx.lifecycle.ViewModelProvider;
-import androidx.loader.app.LoaderManager;
-import androidx.loader.content.CursorLoader;
-import androidx.loader.content.Loader;
 import androidx.core.util.Pair;
 import androidx.preference.PreferenceManager;
 import androidx.appcompat.widget.AppCompatButton;
@@ -53,9 +48,7 @@
 import it.reyboz.bustorino.backend.*;
 import it.reyboz.bustorino.backend.mato.MapiArrivalRequest;
 import it.reyboz.bustorino.data.DatabaseUpdate;
-import it.reyboz.bustorino.data.NextGenDB;
 import it.reyboz.bustorino.middleware.AppLocationManager;
-import it.reyboz.bustorino.data.AppDataProvider;
 import it.reyboz.bustorino.adapters.SquareStopAdapter;
 import it.reyboz.bustorino.middleware.AutoFitGridLayoutManager;
 import it.reyboz.bustorino.util.LocationCriteria;
@@ -105,7 +98,7 @@
     private int distance = 10;
     protected SharedPreferences globalSharedPref;
     private SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener;
-    private TextView messageTextView,titleTextView;
+    private TextView messageTextView,titleTextView, loadingTextView;
     private CommonScrollListener scrollListener;
     private AppCompatButton switchButton;
     private boolean firstLocForStops = true,firstLocForArrivals = true;
@@ -175,10 +168,11 @@
         gridLayoutManager = new AutoFitGridLayoutManager(getContext().getApplicationContext(), Float.valueOf(utils.convertDipToPixels(getContext(),COLUMN_WIDTH_DP)).intValue());
         gridRecyclerView.setLayoutManager(gridLayoutManager);
         gridRecyclerView.setHasFixedSize(false);
-        circlingProgressBar = root.findViewById(R.id.loadingBar);
+        circlingProgressBar = root.findViewById(R.id.circularProgressBar);
         flatProgressBar = root.findViewById(R.id.horizontalProgressBar);
         messageTextView = root.findViewById(R.id.messageTextView);
         titleTextView = root.findViewById(R.id.titleTextView);
+        loadingTextView = root.findViewById(R.id.positionLoadingTextView);
         switchButton = root.findViewById(R.id.switchButton);
 
         scrollListener = new CommonScrollListener(mListener,false);
@@ -276,12 +270,14 @@
                 if(dataAdapter!=null){
                     gridRecyclerView.setAdapter(dataAdapter);
                     circlingProgressBar.setVisibility(View.GONE);
+                    loadingTextView.setVisibility(View.GONE);
                 }
                 break;
             case ARRIVALS:
                 if(arrivalsStopAdapter!=null){
                     gridRecyclerView.setAdapter(arrivalsStopAdapter);
                     circlingProgressBar.setVisibility(View.GONE);
+                    loadingTextView.setVisibility(View.GONE);
                 }
         }
 
@@ -413,6 +409,7 @@
         //showRecyclerHidingLoadMessage();
         if (gridRecyclerView.getVisibility() != View.VISIBLE) {
             circlingProgressBar.setVisibility(View.GONE);
+            loadingTextView.setVisibility(View.GONE);
             gridRecyclerView.setVisibility(View.VISIBLE);
         }
         messageTextView.setVisibility(View.GONE);
@@ -457,6 +454,7 @@
         messageTextView.setVisibility(View.VISIBLE);
         messageTextView.setText(R.string.no_stops_nearby);
         circlingProgressBar.setVisibility(View.GONE);
+        loadingTextView.setVisibility(View.GONE);
     }
 
     /**
@@ -465,6 +463,7 @@
     private void showRecyclerHidingLoadMessage(){
         if (gridRecyclerView.getVisibility() != View.VISIBLE) {
             circlingProgressBar.setVisibility(View.GONE);
+            loadingTextView.setVisibility(View.GONE);
             gridRecyclerView.setVisibility(View.VISIBLE);
         }
         messageTextView.setVisibility(View.GONE);
diff --git a/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt b/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt
--- a/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt
+++ b/app/src/main/java/it/reyboz/bustorino/util/ViewUtils.kt
@@ -1,6 +1,9 @@
 package it.reyboz.bustorino.util
 
 import android.graphics.Rect
+import android.os.Build
+import android.text.Html
+import android.text.Spanned
 import android.util.Log
 import android.view.View
 import android.view.WindowManager
@@ -91,5 +94,7 @@
         }
 
         const val DEF_DURATION: Long = -2
+
+
     }
 }
\ No newline at end of file
diff --git a/app/src/main/res/drawable-it-xhdpi/tuto_line_det.webp b/app/src/main/res/drawable-it-xhdpi/tuto_line_det.webp
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/drawable-it-xhdpi/tuto_map.webp b/app/src/main/res/drawable-it-xhdpi/tuto_map.webp
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/drawable-it-xhdpi/tuto_menu.webp b/app/src/main/res/drawable-it-xhdpi/tuto_menu.webp
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/drawable-it-xhdpi/tuto_stops.webp b/app/src/main/res/drawable-it-xhdpi/tuto_stops.webp
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/drawable-xhdpi/tuto_arrivals.webp b/app/src/main/res/drawable-xhdpi/tuto_arrivals.webp
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/drawable-xhdpi/tuto_busto.webp b/app/src/main/res/drawable-xhdpi/tuto_busto.webp
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/drawable-xhdpi/tuto_line_det.webp b/app/src/main/res/drawable-xhdpi/tuto_line_det.webp
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/drawable-xhdpi/tuto_map.webp b/app/src/main/res/drawable-xhdpi/tuto_map.webp
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/drawable-xhdpi/tuto_menu.webp b/app/src/main/res/drawable-xhdpi/tuto_menu.webp
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/drawable-xhdpi/tuto_search.webp b/app/src/main/res/drawable-xhdpi/tuto_search.webp
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/drawable-xhdpi/tuto_stops.webp b/app/src/main/res/drawable-xhdpi/tuto_stops.webp
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/drawable/arrow_forward.xml b/app/src/main/res/drawable/arrow_forward.xml
new file mode 100644
--- /dev/null
+++ b/app/src/main/res/drawable/arrow_forward.xml
@@ -0,0 +1,7 @@
+<vector  android:height="32dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24" android:width="32dp"
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@color/black"
+          android:pathData="M12,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/>
+</vector>
diff --git a/app/src/main/res/drawable/arrow_forward_white.xml b/app/src/main/res/drawable/arrow_forward_white.xml
new file mode 100644
--- /dev/null
+++ b/app/src/main/res/drawable/arrow_forward_white.xml
@@ -0,0 +1,7 @@
+<vector  android:height="32dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24" android:width="32dp"
+        xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@color/white"
+          android:pathData="M12,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/>
+</vector>
diff --git a/app/src/main/res/drawable/dot_default.xml b/app/src/main/res/drawable/dot_default.xml
new file mode 100644
--- /dev/null
+++ b/app/src/main/res/drawable/dot_default.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape
+                android:innerRadius="0dp"
+                android:shape="ring"
+                android:thickness="6dp"
+                android:useLevel="false">
+            <solid android:color="@color/grey_600"/>
+        </shape>
+    </item>
+</layer-list>
diff --git a/app/src/main/res/drawable/dot_selected.xml b/app/src/main/res/drawable/dot_selected.xml
new file mode 100644
--- /dev/null
+++ b/app/src/main/res/drawable/dot_selected.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape
+                android:innerRadius="0dp"
+                android:shape="ring"
+                android:thickness="6dp"
+                android:useLevel="false">
+            <solid android:color="?colorAccent"/>
+        </shape>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/app/src/main/res/drawable/tab_selector.xml b/app/src/main/res/drawable/tab_selector.xml
new file mode 100644
--- /dev/null
+++ b/app/src/main/res/drawable/tab_selector.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:drawable="@drawable/dot_selected"
+          android:state_selected="true"/>
+
+    <item android:drawable="@drawable/dot_default"/>
+</selector>
\ No newline at end of file
diff --git a/app/src/main/res/font/nevermind_compact.ttf b/app/src/main/res/font/nevermind_compact.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/font/pitagon_medium.ttf b/app/src/main/res/font/pitagon_medium.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/font/pitagon_regular.ttf b/app/src/main/res/font/pitagon_regular.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/font/pitagon_semibold.ttf b/app/src/main/res/font/pitagon_semibold.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001

literal 0
Hc$@<O00001

diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml
--- a/app/src/main/res/layout/activity_about.xml
+++ b/app/src/main/res/layout/activity_about.xml
@@ -20,6 +20,8 @@
             android:layout_marginRight="@dimen/activity_horizontal_margin"
             android:textAppearance="?android:attr/textAppearanceMedium"
             android:layout_weight="0.85"
+            android:fontFamily="@font/nevermind_compact"
+            android:textColor="@color/grey_700"
     />
     <View
             android:layout_width="match_parent"
@@ -39,7 +41,8 @@
             android:paddingLeft="10dp"
             android:id="@+id/openTelegramButton"
             android:drawableLeft = "@drawable/telegram_logo_50"
-            android:drawableStart="@drawable/telegram_logo_50" />
+            android:drawableStart="@drawable/telegram_logo_50"
+            android:fontFamily="@font/pitagon_semibold"/>
 
     <TextView
             android:text="@string/app_version"
diff --git a/app/src/main/res/layout/activity_intro.xml b/app/src/main/res/layout/activity_intro.xml
new file mode 100644
--- /dev/null
+++ b/app/src/main/res/layout/activity_intro.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools"
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        tools:context=".ActivityIntro">
+
+    <ImageButton
+            android:src="@drawable/arrow_forward_white"
+            android:rotation="180"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:id="@+id/btnPrevious"
+            android:backgroundTint="?colorAccent"
+            android:textColor="@color/white"
+            android:contentDescription="@string/previous"
+            app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent"/>
+    <ImageButton
+            android:src="@drawable/arrow_forward_white"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:id="@+id/btnNext"
+            android:backgroundTint="?colorAccent"
+            android:textColor="@color/white"
+            app:circularflow_radiusInDP="5dp"
+            android:contentDescription="@string/next"
+
+            app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent"/>
+    <androidx.viewpager2.widget.ViewPager2
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:id="@+id/viewPager"
+            app:layout_constraintBottom_toTopOf="@+id/btnPrevious" android:layout_marginBottom="8dp"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"/>
+    <com.google.android.material.tabs.TabLayout
+            android:id="@+id/tab_layout"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            app:tabBackground="@drawable/tab_selector"
+            app:tabGravity="center"
+            app:tabIndicatorHeight="0dp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintLeft_toRightOf="@id/btnPrevious"
+            app:layout_constraintRight_toLeftOf="@id/btnNext"
+    />
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_intro.xml b/app/src/main/res/layout/fragment_intro.xml
new file mode 100644
--- /dev/null
+++ b/app/src/main/res/layout/fragment_intro.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent"
+             tools:context=".fragments.IntroFragment">
+
+
+    <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/image_tutorial"
+            app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toTopOf="@+id/tutorialTextView"
+        app:layout_constraintVertical_chainStyle="packed"/>
+    <TextView
+            android:text="Blabla"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" android:id="@+id/tutorialTextView"
+            app:layout_constraintTop_toBottomOf="@+id/image_tutorial"
+            android:layout_marginTop="60dp"
+            android:maxWidth="280dp"
+            android:textSize="18sp"
+            android:textAlignment="center"
+            android:textColor="@color/grey_900"
+            android:fontFamily="@font/pitagon_medium"
+            app:layout_constraintBottom_toTopOf="@id/closeAllButton" app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"/>
+    <Button
+            android:text="@string/close_tutorial"
+            android:layout_width="wrap_content"
+            android:visibility="gone"
+            android:layout_height="wrap_content" android:id="@+id/closeAllButton"
+            app:layout_constraintTop_toBottomOf="@id/tutorialTextView"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toStartOf="@id/tutorialTextView"
+            android:backgroundTint="?colorPrimaryDark"
+            android:textColor="@color/white"
+            app:layout_constraintEnd_toEndOf="@id/tutorialTextView" android:layout_marginTop="12dp"/>
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_main_screen.xml b/app/src/main/res/layout/fragment_main_screen.xml
--- a/app/src/main/res/layout/fragment_main_screen.xml
+++ b/app/src/main/res/layout/fragment_main_screen.xml
@@ -10,8 +10,8 @@
     <ImageButton
             android:id="@+id/QRButton"
             style="?android:attr/borderlessButtonStyle"
-            android:layout_width="30dip"
-            android:layout_height="30dip"
+            android:layout_width="40dip"
+            android:layout_height="40dip"
             android:layout_alignBottom="@+id/searchButton"
             android:layout_alignParentLeft="true"
             android:layout_alignParentStart="true"
diff --git a/app/src/main/res/layout/fragment_nearby_stops.xml b/app/src/main/res/layout/fragment_nearby_stops.xml
--- a/app/src/main/res/layout/fragment_nearby_stops.xml
+++ b/app/src/main/res/layout/fragment_nearby_stops.xml
@@ -9,8 +9,11 @@
             android:layout_height="wrap_content"
             android:text="@string/nearby_stops_message" android:id="@+id/titleTextView"
             android:textAppearance="@android:style/TextAppearance.Medium"
-            android:layout_marginBottom="15dp" android:layout_marginTop="15dp"
-            android:gravity="center_horizontal" android:textSize="23sp"
+            android:layout_marginBottom="6dp"
+            android:layout_marginTop="15dp"
+            android:paddingTop="3dp"
+            android:gravity="center_horizontal"
+            android:textSize="23sp"
             android:layout_toLeftOf="@id/switchButton" android:layout_marginLeft="10dp"
             android:layout_marginStart="10dp" android:layout_marginRight="10dp" android:layout_marginEnd="10dp"
     />
@@ -38,7 +41,7 @@
             android:verticalSpacing="10dp"/>
     <ProgressBar
             style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"
-            android:layout_width="wrap_content"
+            android:layout_width="3dp"
             android:layout_height="wrap_content"
             android:id="@+id/horizontalProgressBar"
             android:layout_alignParentRight="true"
@@ -53,12 +56,20 @@
             style="?android:attr/progressBarStyle"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:id="@+id/loadingBar"
-            android:paddingTop="10dp"
-            android:progressDrawable="@color/blue_700"
+            android:id="@+id/circularProgressBar"
+            android:layout_marginTop="25dp"
+            android:progressDrawable="@color/blue_620"
             android:indeterminate="true"
-            android:indeterminateTint="@color/blue_700"
+            android:indeterminateTint="@color/blue_620"
             android:layout_below="@+id/titleTextView" android:layout_centerHorizontal="true"/>
+    <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
+              android:id="@+id/positionLoadingTextView"
+              android:layout_below="@id/circularProgressBar"
+              android:text="@string/position_searching_message"
+              android:layout_marginTop="8dp"
+              android:textSize="15sp"
+              android:layout_centerHorizontal="true"
+              />
     <TextView
             android:text="@string/enableGpsText"
             android:layout_width="wrap_content"
diff --git a/app/src/main/res/layout/nav_header.xml b/app/src/main/res/layout/nav_header.xml
--- a/app/src/main/res/layout/nav_header.xml
+++ b/app/src/main/res/layout/nav_header.xml
@@ -27,8 +27,9 @@
         android:text="@string/app_name_full"
 
         android:textAppearance="@style/TextAppearance.AppCompat.Title"
+        android:fontFamily="@font/pitagon_medium"
         android:textColor="@color/white"
-        android:textSize="20sp" />
+        android:textSize="22sp" />
 
     <!--<TextView
             android:text="@string/app_version"
diff --git a/app/src/main/res/menu/principal_menu.xml b/app/src/main/res/menu/principal_menu.xml
--- a/app/src/main/res/menu/principal_menu.xml
+++ b/app/src/main/res/menu/principal_menu.xml
@@ -21,9 +21,15 @@
             android:orderInCategory="8"
             android:title="@string/action_licence"
             app:showAsAction="never" />
+    <item
+            android:id="@+id/action_tutorial"
+            android:title="@string/tutorial_action"
+            android:orderInCategory="9"
+    />
     <item
             android:id="@+id/action_experiments"
             android:title="@string/experiments"
             android:orderInCategory="10"
     />
+
 </menu>
\ No newline at end of file
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -7,6 +7,8 @@
     <string name="qrcode">QR Code</string>
     <string name="yes">Si</string>
     <string name="no">No</string>
+    <string name="next">Prossimo</string>
+    <string name="previous">Precedente</string>
     <string name="title_barcode_scanner_install">Installare Barcode Scanner?</string>
     <string name="message_install_barcode_scanner">Questa azione richiede un\'altra app per scansionare i codici QR. Vuoi installare Barcode Scanner?</string>
     <string name="insert_bus_stop_number">Numero fermata</string>
@@ -49,7 +51,7 @@
     <string name="action_rename_bus_stop_username">Rinomina</string>
     <string name="dialog_rename_bus_stop_username_title">Rinomina fermata</string>
     <string name="dialog_rename_bus_stop_username_reset_button">Reset</string>
-    <string name="about">Informazioni</string>
+    <string name="about_activity">Informazioni</string>
     <string name="howDoesItWork"><b>Tocca la stella</b> per aggiungere la fermata ai preferiti\n\n<b>Come leggere gli orari:</b>
         \n<b>&#160;&#160;&#160;12:56*</b> Orario in tempo reale\n<b>&#160;&#160;&#160;12:56</b> &#160; Orario programmato\n\n<b>Trascina giù per aggiornare</b> l\'orario.
         \n<b>Tocca a lungo</b> su <b>Fonte Orari</b> per cambiare sorgente degli orari di arrivo.
@@ -60,7 +62,7 @@
         <h1>Benvenuto!</h1>
         
         <p>Grazie per aver scelto BusTO, un\'app <b>indipendente</b> da GTT/5T, per spostarsi a Torino attraverso <b>software libero</b>:</p>
-		
+		<br>
 		<p>Perché usare BusTO?</p>
 		<p>
         - Non sei <b>monitorato</b><br>
@@ -68,10 +70,10 @@
         - La tua <b>privacy</b> è al sicuro<br>
         - Inoltre l\'app è molto leggera!<br>
         </p>
-
-        <h2>Come Funziona?</h2>
-        <p>Quest\'app ottiene i passaggi dei bus in tempo reale filtrando i dati forniti pubblicamente sul sito <b>www.gtt.to.it</b> o <i>www.5t.torino.it</i> "per uso personale".</p>
-
+        <br>
+        <h2>Come funziona?</h2>
+        <p>Quest\'app ottiene i passaggi dei bus, le fermate e altre informazioni utili unendo dati forniti dal sito <b>www.gtt.to.it</b>, <i>www.5t.torino.it</i>, <b>muoversiatorino.it</b> "per uso personale" e altre fonti Open Data (aperto.comune.torino.it).</p>
+        <br>
 		<p>Ingredienti:<br>
 		- <b>Fabio Mazza</b> attuale rockstar developer anziano.<br>
 		- <b>Andrea Ugo</b> attuale rockstar developer in formazione.<br>
@@ -82,16 +84,18 @@
 		- <b>Marco Gagino</b> apprezzato ex collaboratore, ideatore icona e grafica.<br>
 		- <b>JSoup</b> libreria per "<i>web scaping</i>".<br>
 		- <b>Google</b> icone e libreria di supporto per il Material Design.<br>
-		- Tutti i contributori!
+		- Tutti i contributori e i beta tester!
 		</p>
-
+        <br>
 		<h2>Licenze</h2>
 		<p>L\'app e il relativo codice sorgente sono distribuiti sotto la licenza <i>GNU General Public License v3+</i>.
 		Ciò <b>significa</b> che puoi usare, studiare, migliorare e ricondividere quest\'app con <b>qualunque mezzo</b> e per <b>qualsiasi scopo</b>: a patto di mantenere sempre questi diritti a tua volta e di dare credito a Valerio Bozzolan.
 		</p>
-		
+
+		<br>
 		<h2>Note</h2>
-		<p>Quest\'applicazione è rilasciata <b>nella speranza che sia utile a tutti</b> ma senza NESSUNA garanzia.</p>
+		<p>Quest\'applicazione è rilasciata <b>nella speranza che sia utile a tutti</b> ma senza NESSUNA garanzia sul suo funzionamento attuale e/o futuro.</p>
+		<p>Tutti i dati utilizzati dall\'app provengono <b>direttamente</b> da GTT o da simili agenzie pubbliche: se trovi che sono inesatti per qualche motivo, ti invitiamo a rivolgerti a loro.</p>
 		<p>Buon utilizzo! :)</p>
     ]]>
     </string>
@@ -105,7 +109,7 @@
 
 
     <string name="nearby_stops_message">Fermate vicine</string>
-    <string name="position_searching_message">Ricerca della posizione in corso&#8230;</string>
+    <string name="position_searching_message">Ricerca della posizione</string>
     <string name="no_stops_nearby">Nessuna fermata nei dintorni</string>
     <string name="main_menu_pref">Preferenze</string>
     <string name="database_update_msg_inapp">Aggiornamento del database&#8230;</string>
@@ -137,7 +141,7 @@
     <!--
     Mixed button strings
     !-->
-    <string name="open_telegram">Entra nel canale Telegram</string>
+    <string name="open_telegram"> Canale Telegram</string>
 
     <!--
     Map view buttons strings
@@ -218,5 +222,31 @@
     <string name="remove_all_trips">Rimuovi tutti i trip GTFS</string>
     <string name="all_trips_removed">Tutti i trip GTFS sono rimossi dal database</string>
 
+    <!-- tutorial -->
+    <string name="tutorial_action">Mostra tutorial</string>
+    <string name="tutorial_first">
+        <![CDATA[Grazie per aver installato BusTO, l\'app gratuita, libera e <b>open source</b> per il trasporto pubblico di Torino. Stai usando un\'app <b>indipendente</b>, senza pubblicità e senza nessun tracciamento.
+]]> </string>
+    <string name="tutorial_search"><![CDATA[Puoi cercare gli orari d\'arrivo ad una fermata inserendo il numero nella casella di ricerca.<br>
+Se ti trovi a una fermata, puoi scansionare il codice QR presente sulla palina toccando l\'icona a sinistra della barra di ricerca.]]>
+    </string>
+    <string name="tutorial_arrivals">
+        <![CDATA[Una volta trovata una fermata, puoi aggiungerla ai <b>preferiti</b> toccando la stella a fianco del nome.]]>
+    </string>
+    <string name="tutorial_stops">
+        <![CDATA[Con la posizione abilitata, puoi vedere le <b>fermate più vicine</b> a te direttamente nella schermata principale...]]>
+    </string>
+    <string name="tutorial_map">
+        <![CDATA[...oppure puoi trovarle sulla mappa, assieme alle <b>posizioni in tempo reale</b> dei bus e tram (in <font color="#2F59CC">blu</font>)]]>
+    </string>
+    <string name="tutorial_line">
+        <![CDATA[Scopri il percorso e le fermate della linea che preferisci, insieme alle posizioni in tempo reale dei bus/tram che la servono. Ricorda di scegliere la direzione che ti interessa!]]>
+    </string>
+    <string name="tutorial_menu">
+        <![CDATA[Tutte queste funzioni si trovano nel menu laterale.<br>
+Guarda nelle <b>Impostazioni</b> per personalizzare l\'app come preferisci, e su <b>Informazioni</b> per sapere di più sull\'app e il team di sviluppo.]]>
+    </string>
+    <string name="close_tutorial">Chiudi</string>
+
 
 </resources>
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -26,6 +26,9 @@
     <color name="grey_200">#dddddd</color>
     <color name="grey_050">#f8f8f8</color>
     <color name="grey_600">#757575</color>
+    <color name="grey_700">#444</color>
+    <color name="grey_800">#353535</color>
+    <color name="grey_900">#303030</color>
 
     <!--<color name="white">#FFFFFF</color>
     <color name="accent">#009688</color>-->
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -11,6 +11,9 @@
     <string name="qrcode">Scan QR Code</string>
     <string name="yes">Yes</string>
     <string name="no">No</string>
+    <string name="next">Next</string>
+    <string name="previous">Previous</string>
+
     <string name="title_barcode_scanner_install">Install Barcode Scanner?</string>
     <string name="message_install_barcode_scanner">This application requires an app to scan the QR codes. Would you like
         to install Barcode Scanner now?
@@ -43,7 +46,7 @@
     <string name="no_qrcode">No QR code found, try using another app to scan</string>
     <string name="internal_error">Unexpected internal error, cannot extract data from GTT/5T website</string>
     <string name="action_help">Help</string>
-    <string name="action_about">About</string>
+    <string name="action_about">About the app</string>
     <string name="action_about_more">More about</string>
     <string name="action_wiki">Contribute</string>
     <string name="hack_url">https://gitpull.it/w/librebusto/en/</string>
@@ -60,7 +63,7 @@
     <string name="action_rename_bus_stop_username">Rename</string>
     <string name="dialog_rename_bus_stop_username_title">Rename the bus stop</string>
     <string name="dialog_rename_bus_stop_username_reset_button">Reset</string>
-    <string name="about">About</string>
+    <string name="about_activity">About the app</string>
     <string name="howDoesItWork">
         <b>Tap the star</b>
         to add the bus stop to the favourites\n\n<b>How to read timelines:</b>\n<b>&#160;&#160;&#160;12:56*</b> Real-time
@@ -75,7 +78,7 @@
         <h1>Welcome!</h1>
 
         <p>Thanks for using BusTO, a "politically" <b>independent</b> app useful to move around Torino using a <b>Free/Libre software</b>.</p>
-
+        <br>
         <p>Why use this app?</p>
 		<p>
         - You\'ll never be <b>tracked</b><br>
@@ -83,32 +86,34 @@
         - We\'ll always respect your <b>privacy</b><br>
         - Moreover, it\'s lightweight!<br>
         </p>
-
+        <br>
         <h2>How does it work?</h2>
-        <p>This app will show you bus timetables gathering data from <b>www.gtt.to.it</b> or <b>www.5t.torino.it</b> "for personal use".</p>
-
-		<p>Who worked on BusTO:<br>
-		- <b>Fabio Mazza</b> current senior rockstar developer.<br>
-        - <b>Andrea Ugo</b> current junior rockstar developer.<br>
-		- <b>Silviu Chiriac</b> designer of the 2021 logo.<br>
-		- <b>Marco M</b> rockstar tester and bug hunter.<br>
-		- <b>Ludovico Pavesi</b> previous senior rockstar developer asd.<br>
-		- <b>Valerio Bozzolan</b> maintainer and infrastructure sponsor.<br>
-		- <b>Marco Gagino</b> contributor and icon creator.<br>
+        <p>This app is able to do all the amazing things it does by pulling data from <b>www.gtt.to.it</b>, <b>www.5t.torino.it</b> or <b>muoversiatorino.it</b> "for personal use", along with open data from the AperTO (aperto.comune.torino.it) website.</p>
+        <br>
+		<p>The work of several people is behind this app, in particular:<br>
+		- <b>Fabio Mazza</b>, current senior rockstar developer.<br>
+        - <b>Andrea Ugo</b>, current junior rockstar developer.<br>
+		- <b>Silviu Chiriac</b>, designer of the 2021 logo.<br>
+		- <b>Marco M</b>, rockstar tester and bug hunter.<br>
+		- <b>Ludovico Pavesi</b>, previous senior rockstar developer (asd).<br>
+		- <b>Valerio Bozzolan</b>, maintainer and infrastructure (sponsor).<br>
+		- <b>Marco Gagino</b>, contributor and first icon creator.<br>
 		- <b>JSoup</b> web scraper library.<br>
 		- <b>makovkastar</b> floating buttons.<br>
-		- <b>Google</b> Material Design icons.<br>
-		- All the contributors!
+		- <b>Google</b> Material Design icons and Volley framework.<br>
+		- <b>Android</b> app components.<br>
+		- All the contributors, and the beta testers, too!
 		</p>
-		
+		<br>
 		<h2>Licenses</h2>
-		<p>The app and the related source code are released by Valerio Bozzolan under the terms of the <i>GNU General Public License v3+</i>).
+		<p>The app and the related source code are released by Valerio Bozzolan and the other authors under the terms of the <i>GNU General Public License v3+</i>).
 		So everyone is allowed to use, to study, to improve and to share this app by <b>any kind of means</b> and for <b>any purpose</b>: under the conditions of maintaining this rights and of attributing the original work to Valerio Bozzolan.</p>
-
+        <br>
 		<h2>Notes</h2>
-		<p>This app has been developed <b>hoping to be useful to everyone</b> but without ANY warranty.</p>
-		<p>This translation is kindly provided by Riccardo Caniato and Marco Gagino.</p>
-		<p>Get involved! :)</p>
+		<p>This app has been developed with the <b>hope to be useful to everyone</b>, but comes without ANY warranty of any kind.</p>
+		<p>The data used by the app comes <b>directly</b> from GTT and other public agencies: if you find any errors, please take it up to them, not to us.</p>
+		<p>This translation is kindly provided by Riccardo Caniato, Marco Gagino and Fabio Mazza.</p>
+		<p>Now you can hack public transport, too! :)</p>
     ]]>
     </string>
 
@@ -124,10 +129,10 @@
     <string name="nearby_stops_message">Nearby stops</string>
     <string name="nearby_arrivals_message">Nearby connections</string>
     <string name="app_version">App version</string>
-    <string name="num_stops_nearby_not_number">The number of stops to show in the recents is invalid</string>
+    <string name="num_stops_nearby_not_number">The number of stops to show in the recent stops is invalid</string>
     <string name="invalid_number">Invalid value, put a valid number</string>
 
-    <string name="position_searching_message">Finding the position&#8230;</string>
+    <string name="position_searching_message">Finding location</string>
     <string name="no_stops_nearby">No stops nearby</string>
     <string name="pref_num_elements">Minimum number of stops</string>
     <string name="main_menu_pref">Preferences</string>
@@ -155,7 +160,7 @@
     <!--
     Mixed button strings
     !-->
-    <string name="open_telegram">Join Telegram channel</string>
+    <string name="open_telegram"> Join Telegram channel</string>
     <!--
    Map view buttons strings
    !-->
@@ -251,4 +256,31 @@
 
     <string name="remove_all_trips">Remove all GTFS trips info</string>
     <string name="all_trips_removed">All GTFS trips have been removed from the database</string>
+
+    <!-- Tutorial strings -->
+    <string name="tutorial_action">Show tutorial</string>
+    <string name="tutorial_first">
+        <![CDATA[Thank you for installing BusTO, the free and <b>open source</b> app for Turin public transport. This is an <b>independent</b> app, with no ads and no tracking whatsoever.]]> </string>
+    <string name="tutorial_search"> <![CDATA[You can search for the arrival times at a bus stop by inserting the number in the top, or scanning a QR code when you are at the stop
+        touching the icon on the left ]]>
+    </string>
+    <string name="tutorial_arrivals">
+        <![CDATA[Once you have found a bus stop, you can save it in the <b>favorites</b> by touching the star next to its name]]>
+    </string>
+    <string name="tutorial_stops">
+        <![CDATA[You can see the stops near your position directly in the main screen...]]>
+    </string>
+
+    <string name="tutorial_map">
+    <![CDATA[...or you can find them in the map, along with the real-time positions of the buses running in the city (in <font color="#2F59CC">blue</font>)]]>
+    </string>
+    <string name="tutorial_line">
+        <![CDATA[You can also look at the line you want and see where the stops are, together with the vehicles serving the line at the moment. Remember to choose the direction you\'re interested in!]]>
+    </string>
+    <string name="tutorial_menu">
+        <![CDATA[You can find all of this from the lateral menu.
+Look in the <b>Settings</b> to customize the app behaviour, and in the <b>About the app</b> section if you want to know more about the app and the developers.]]>
+    </string>
+    <string name="close_tutorial">Close</string>
+
 </resources>