diff --git a/app/src/main/java/it/reyboz/bustorino/ActivityIntro.kt b/app/src/main/java/it/reyboz/bustorino/ActivityIntro.kt --- a/app/src/main/java/it/reyboz/bustorino/ActivityIntro.kt +++ b/app/src/main/java/it/reyboz/bustorino/ActivityIntro.kt @@ -3,9 +3,11 @@ import android.content.Intent import android.os.Bundle import android.util.Log +import android.util.TypedValue import android.view.View import android.widget.ImageButton import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.res.ResourcesCompat import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.viewpager2.adapter.FragmentStateAdapter @@ -21,10 +23,12 @@ private lateinit var viewPager : ViewPager2 private lateinit var btnForward: ImageButton private lateinit var btnBackward: ImageButton + private lateinit var closeBottomButton: ImageButton private var restartMain = true + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_intro) @@ -32,6 +36,7 @@ viewPager = findViewById(R.id.viewPager) btnBackward = findViewById(R.id.btnPrevious) btnForward = findViewById(R.id.btnNext) + closeBottomButton = findViewById(R.id.btnCompactClose) val extras = intent.extras if(extras!=null){ @@ -56,6 +61,11 @@ btnBackward.setOnClickListener { viewPager.setCurrentItem(viewPager.currentItem-1, true) } + /*closeBottomButton.setOnClickListener { + closeIntroduction() + } + + */ viewPager.registerOnPageChangeCallback(object : OnPageChangeCallback() { @@ -67,12 +77,30 @@ } if(position == NUM_ITEMS-1){ btnForward.visibility = View.INVISIBLE - } else{ - btnForward.visibility = View.VISIBLE + closeBottomButton.visibility = View.VISIBLE + }else if(position == NUM_ITEMS-2){ + if(closeBottomButton.visibility == View.VISIBLE) { + closeBottomButton.visibility = View.INVISIBLE + btnForward.visibility = View.VISIBLE + } + //btnForward.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.arrow_forward_white, null)) + //btnForward.setBackgroundColor(ResourcesCompat.getColor(resources,R.attr.colorAccent, theme)) + /*val + GET THE COLOR VALUE OF THE THEMER + colo = TypedValue() + theme.resolveAttribute(R.attr.colorAccent,colo, true) + btnForward.backgroundTintList //(colo.data) + + */ } } + }) + + closeBottomButton.setOnClickListener { + closeIntroduction() + } } diff --git a/app/src/main/java/it/reyboz/bustorino/adapters/RouteAdapter.kt b/app/src/main/java/it/reyboz/bustorino/adapters/RouteAdapter.kt --- a/app/src/main/java/it/reyboz/bustorino/adapters/RouteAdapter.kt +++ b/app/src/main/java/it/reyboz/bustorino/adapters/RouteAdapter.kt @@ -11,11 +11,11 @@ import java.lang.ref.WeakReference class RouteAdapter(val routes: List<GtfsRoute>, - click: onItemClick, - private val layoutId: Int = R.layout.line_title_header) : + click: ItemClicker, + private val layoutId: Int = R.layout.line_title_header) : RecyclerView.Adapter<RouteAdapter.ViewHolder>() { - val clickreference: WeakReference<onItemClick> + val clickreference: WeakReference<ItemClicker> init { clickreference = WeakReference(click) } @@ -53,7 +53,7 @@ } } - fun interface onItemClick{ + fun interface ItemClicker{ fun onRouteItemClicked(gtfsRoute: GtfsRoute) } } \ No newline at end of file diff --git a/app/src/main/java/it/reyboz/bustorino/adapters/RouteOnlyLineAdapter.kt b/app/src/main/java/it/reyboz/bustorino/adapters/RouteOnlyLineAdapter.kt --- a/app/src/main/java/it/reyboz/bustorino/adapters/RouteOnlyLineAdapter.kt +++ b/app/src/main/java/it/reyboz/bustorino/adapters/RouteOnlyLineAdapter.kt @@ -7,10 +7,18 @@ import androidx.recyclerview.widget.RecyclerView import it.reyboz.bustorino.R import it.reyboz.bustorino.backend.Palina +import java.lang.ref.WeakReference -class RouteOnlyLineAdapter (val routeNames: List<String>) : +class RouteOnlyLineAdapter (val routeNames: List<String>, + onItemClick: OnClick?) : RecyclerView.Adapter<RouteOnlyLineAdapter.ViewHolder>() { + + private val clickreference: WeakReference<OnClick>? + init { + clickreference = if(onItemClick!=null) WeakReference(onItemClick) else null + } + /** * Provide a reference to the type of views that you are using * (custom ViewHolder) @@ -23,7 +31,7 @@ textView = view.findViewById(R.id.routeBallID) } } - constructor(palina: Palina, showOnlyEmpty: Boolean): this(palina.routesNamesWithNoPassages) + constructor(palina: Palina, showOnlyEmpty: Boolean): this(palina.routesNamesWithNoPassages, null) // Create new views (invoked by the layout manager) override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder { @@ -40,9 +48,15 @@ // Get element from your dataset at this position and replace the // contents of the view with that element viewHolder.textView.text = routeNames[position] + viewHolder.itemView.setOnClickListener{ + clickreference?.get()?.onItemClick(position, routeNames[position]) + } } // Return the size of your dataset (invoked by the layout manager) override fun getItemCount() = routeNames.size + fun interface OnClick{ + fun onItemClick(index: Int, name: String) + } } diff --git a/app/src/main/java/it/reyboz/bustorino/data/GtfsRepository.kt b/app/src/main/java/it/reyboz/bustorino/data/GtfsRepository.kt --- a/app/src/main/java/it/reyboz/bustorino/data/GtfsRepository.kt +++ b/app/src/main/java/it/reyboz/bustorino/data/GtfsRepository.kt @@ -35,4 +35,8 @@ fun getAllRoutes(): LiveData<List<GtfsRoute>>{ return gtfsDao.getAllRoutes() } + + fun getRouteFromGtfsId(gtfsId: String): LiveData<GtfsRoute>{ + return gtfsDao.getRouteByGtfsID(gtfsId) + } } \ No newline at end of file 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 @@ -19,12 +19,16 @@ import android.content.Context; import android.content.SharedPreferences; +import android.util.Log; import it.reyboz.bustorino.R; import static android.content.Context.MODE_PRIVATE; import androidx.preference.PreferenceManager; +import java.util.HashSet; +import java.util.Set; + /** * Static class for commonly used SharedPreference operations */ @@ -33,6 +37,8 @@ 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 final String PREF_FAVORITE_LINES = "pref_favorite_lines"; + public static SharedPreferences getMainSharedPreferences(Context context){ return context.getSharedPreferences(context.getString(R.string.mainSharedPreferences), MODE_PRIVATE); } @@ -59,4 +65,27 @@ final SharedPreferences pref = getMainSharedPreferences(con); return pref.getBoolean(PREF_INTRO_ACTIVITY_RUN, false); } + + public static boolean addOrRemoveLineToFavorites(Context con, String gtfsLineId, boolean addToFavorites){ + final SharedPreferences pref = getMainSharedPreferences(con); + final HashSet<String> favorites = new HashSet<>(pref.getStringSet(PREF_FAVORITE_LINES, new HashSet<>())); + boolean modified = true; + if(addToFavorites) + favorites.add(gtfsLineId); + else if(favorites.contains(gtfsLineId)) + favorites.remove(gtfsLineId); + else + modified = false; // we are not changing anything + if(modified) { + final SharedPreferences.Editor editor = pref.edit(); + editor.putStringSet(PREF_FAVORITE_LINES, favorites); + editor.apply(); + } + return modified; + } + + public static HashSet<String> getFavoritesLinesGtfsIDs(Context con){ + final SharedPreferences pref = getMainSharedPreferences(con); + return new HashSet<>(pref.getStringSet(PREF_FAVORITE_LINES, new HashSet<>())); + } } diff --git a/app/src/main/java/it/reyboz/bustorino/data/gtfs/GtfsDBDao.kt b/app/src/main/java/it/reyboz/bustorino/data/gtfs/GtfsDBDao.kt --- a/app/src/main/java/it/reyboz/bustorino/data/gtfs/GtfsDBDao.kt +++ b/app/src/main/java/it/reyboz/bustorino/data/gtfs/GtfsDBDao.kt @@ -26,8 +26,8 @@ @Query("SELECT * FROM "+GtfsRoute.DB_TABLE) fun getAllRoutes() : LiveData<List<GtfsRoute>> - @Query("SELECT * FROM ${GtfsRoute.DB_TABLE} WHERE ${GtfsRoute.COL_ROUTE_ID} IN (:routeGtfsIds)") - fun getRoutesByIDs(routeGtfsIds: List<String>): LiveData<List<GtfsRoute>> + @Query("SELECT * FROM ${GtfsRoute.DB_TABLE} WHERE ${GtfsRoute.COL_ROUTE_ID} LIKE :gtfsId") + fun getRouteByGtfsID(gtfsId: String) : LiveData<GtfsRoute> @Query("SELECT "+GtfsTrip.COL_TRIP_ID+" FROM "+GtfsTrip.DB_TABLE) diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.java --- a/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.java +++ b/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.java @@ -409,7 +409,7 @@ final ArrayList<String> routesWithNoPassages = lastUpdatedPalina.getRoutesNamesWithNoPassages(); Collections.sort(routesWithNoPassages, new LinesNameSorter()); - noArrivalsAdapter = new RouteOnlyLineAdapter(routesWithNoPassages); + noArrivalsAdapter = new RouteOnlyLineAdapter(routesWithNoPassages, null); if(noArrivalsRecyclerView!=null){ noArrivalsRecyclerView.setAdapter(noArrivalsAdapter); //hide the views if there are no empty routes diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/IntroFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/IntroFragment.kt --- a/app/src/main/java/it/reyboz/bustorino/fragments/IntroFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/IntroFragment.kt @@ -9,6 +9,7 @@ import android.view.View import android.view.ViewGroup import android.widget.Button +import android.widget.ImageButton import android.widget.ImageView import android.widget.TextView import androidx.fragment.app.Fragment @@ -33,6 +34,7 @@ private lateinit var textView: TextView + private lateinit var listener: IntroListener override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -88,6 +90,7 @@ 6-> { setImageBitmap(imageHolder,R.drawable.tuto_menu) setTextHtmlDescription(R.string.tutorial_menu) + //this is the cheapest trick ever lol val closeButton = root.findViewById<Button>(R.id.closeAllButton) closeButton.visibility = View.VISIBLE closeButton.setOnClickListener { diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt --- a/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/LinesDetailFragment.kt @@ -20,6 +20,7 @@ import android.animation.ObjectAnimator import android.annotation.SuppressLint import android.content.Context +import android.content.SharedPreferences import android.graphics.Paint import android.os.Bundle import android.util.Log @@ -45,6 +46,7 @@ import it.reyboz.bustorino.backend.gtfs.PolylineParser import it.reyboz.bustorino.backend.utils import it.reyboz.bustorino.data.MatoTripsDownloadWorker +import it.reyboz.bustorino.data.PreferencesHolder import it.reyboz.bustorino.data.gtfs.MatoPattern import it.reyboz.bustorino.data.gtfs.MatoPatternWithStops import it.reyboz.bustorino.data.gtfs.TripAndPatternWithStops @@ -67,7 +69,7 @@ class LinesDetailFragment() : ScreenBaseFragment() { - private lateinit var lineID: String + private var lineID = "" private lateinit var patternsSpinner: Spinner private var patternsAdapter: ArrayAdapter<String>? = null @@ -83,7 +85,31 @@ private var firstInit = true private var pausedFragment = false private lateinit var switchButton: ImageButton + + private var favoritesButton: ImageButton? = null + private var isLineInFavorite = false + private val lineSharedPrefMonitor = SharedPreferences.OnSharedPreferenceChangeListener { pref, keychanged -> + if(keychanged!=PreferencesHolder.PREF_FAVORITE_LINES || lineID.isEmpty()) return@OnSharedPreferenceChangeListener + val newFavorites = pref.getStringSet(PreferencesHolder.PREF_FAVORITE_LINES, HashSet()) + newFavorites?.let { + isLineInFavorite = it.contains(lineID) + //if the button has been intialized, change the icon accordingly + favoritesButton?.let { button-> + if(isLineInFavorite) { + button.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ic_star_filled, null)) + Toast.makeText(context,R.string.favorites_line_add,Toast.LENGTH_SHORT).show() + } else { + button.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ic_star_outline, null)) + Toast.makeText(context,R.string.favorites_line_remove,Toast.LENGTH_SHORT).show() + } + + + } + } + } + private lateinit var stopsRecyclerView: RecyclerView + private lateinit var descripTextView: TextView //adapter for recyclerView private val stopAdapterListener= object : StopAdapterListener { override fun onTappedStop(stop: Stop?) { @@ -93,7 +119,7 @@ viewModel.shouldShowMessage=false } stop?.let { - fragmentListener?.requestArrivalsForStopID(it.ID) + fragmentListener.requestArrivalsForStopID(it.ID) } if(stop == null){ Log.e(DEBUG_TAG,"Passed wrong stop") @@ -142,12 +168,27 @@ val rootView = inflater.inflate(R.layout.fragment_lines_detail, container, false) lineID = requireArguments().getString(LINEID_KEY, "") switchButton = rootView.findViewById(R.id.switchImageButton) + favoritesButton = rootView.findViewById(R.id.favoritesButton) stopsRecyclerView = rootView.findViewById(R.id.patternStopsRecyclerView) + descripTextView = rootView.findViewById(R.id.lineDescripTextView) + descripTextView.visibility = View.INVISIBLE val titleTextView = rootView.findViewById<TextView>(R.id.titleTextView) - titleTextView.text = getString(R.string.line)+" "+GtfsUtils.getLineNameFromGtfsID(lineID) + favoritesButton?.isClickable = true + favoritesButton?.setOnClickListener { + if(lineID.isNotEmpty()) + PreferencesHolder.addOrRemoveLineToFavorites(requireContext(),lineID,!isLineInFavorite) + } + val preferences = PreferencesHolder.getMainSharedPreferences(requireContext()) + val favorites = preferences.getStringSet(PreferencesHolder.PREF_FAVORITE_LINES, HashSet()) + if(favorites!=null && favorites.contains(lineID)){ + favoritesButton?.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ic_star_filled, null)) + isLineInFavorite = true + } + preferences.registerOnSharedPreferenceChangeListener(lineSharedPrefMonitor) + patternsSpinner = rootView.findViewById(R.id.patternsSpinner) patternsAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_dropdown_item, ArrayList<String>()) patternsSpinner.adapter = patternsAdapter @@ -195,6 +236,10 @@ showStopsAsList(stops) } } + viewModel.gtfsRoute.observe(viewLifecycleOwner){route-> + descripTextView.text = route.longName + descripTextView.visibility = View.VISIBLE + } if(pausedFragment && viewModel.selectedPatternLiveData.value!=null){ val patt = viewModel.selectedPatternLiveData.value!! Log.d(DEBUG_TAG, "Recreating views on resume, setting pattern: ${patt.pattern.code}") @@ -310,7 +355,7 @@ // add ability to zoom with 2 fingers it.setMultiTouchControls(true) - it.minZoomLevel = 11.0 + it.minZoomLevel = 12.0 //map controller setup val mapController = it.controller diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/LinesGridShowingFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/LinesGridShowingFragment.kt --- a/app/src/main/java/it/reyboz/bustorino/fragments/LinesGridShowingFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/LinesGridShowingFragment.kt @@ -15,7 +15,9 @@ import androidx.recyclerview.widget.RecyclerView import it.reyboz.bustorino.R import it.reyboz.bustorino.adapters.RouteAdapter +import it.reyboz.bustorino.adapters.RouteOnlyLineAdapter import it.reyboz.bustorino.backend.utils +import it.reyboz.bustorino.data.PreferencesHolder import it.reyboz.bustorino.data.gtfs.GtfsRoute import it.reyboz.bustorino.middleware.AutoFitGridLayoutManager import it.reyboz.bustorino.util.LinesNameSorter @@ -29,11 +31,12 @@ private val viewModel: LinesGridShowingViewModel by viewModels() //private lateinit var gridLayoutManager: AutoFitGridLayoutManager - + private lateinit var favoritesRecyclerView: RecyclerView private lateinit var urbanRecyclerView: RecyclerView private lateinit var extraurbanRecyclerView: RecyclerView private lateinit var touristRecyclerView: RecyclerView + private lateinit var favoritesTitle: TextView private lateinit var urbanLinesTitle: TextView private lateinit var extrurbanLinesTitle: TextView private lateinit var touristLinesTitle: TextView @@ -53,7 +56,7 @@ return@Comparator linesNameSorter.compare(a.shortName, b.shortName) } - private val routeClickListener = RouteAdapter.onItemClick { + private val routeClickListener = RouteAdapter.ItemClicker { fragmentListener.showLineOnMap(it.gtfsId) } private val arrows = HashMap<String, ImageView>() @@ -66,10 +69,12 @@ ): View? { val rootView = inflater.inflate(R.layout.fragment_lines_grid, container, false) + favoritesRecyclerView = rootView.findViewById(R.id.favoritesRecyclerView) urbanRecyclerView = rootView.findViewById(R.id.urbanLinesRecyclerView) extraurbanRecyclerView = rootView.findViewById(R.id.extraurbanLinesRecyclerView) touristRecyclerView = rootView.findViewById(R.id.touristLinesRecyclerView) + favoritesTitle = rootView.findViewById(R.id.favoritesTitleView) urbanLinesTitle = rootView.findViewById(R.id.urbanLinesTitleView) extrurbanLinesTitle = rootView.findViewById(R.id.extraurbanLinesTitleView) touristLinesTitle = rootView.findViewById(R.id.touristLinesTitleView) @@ -77,6 +82,7 @@ arrows[AG_URBAN] = rootView.findViewById(R.id.arrowUrb) arrows[AG_TOUR] = rootView.findViewById(R.id.arrowTourist) arrows[AG_EXTRAURB] = rootView.findViewById(R.id.arrowExtraurban) + arrows[AG_FAV] = rootView.findViewById(R.id.arrowFavorites) //show urban expanded by default val recViews = listOf(urbanRecyclerView, extraurbanRecyclerView, touristRecyclerView) @@ -87,6 +93,13 @@ ) recyView.layoutManager = gridLayoutManager } + //init favorites recyclerview + val gridLayoutManager = AutoFitGridLayoutManager( + requireContext().applicationContext, + (utils.convertDipToPixels(context, 70f)).toInt() + ) + favoritesRecyclerView.layoutManager = gridLayoutManager + viewModel.routesLiveData.observe(viewLifecycleOwner){ //routesList = ArrayList(it) @@ -116,6 +129,15 @@ } } + viewModel.favoritesLines.observe(viewLifecycleOwner){ routes-> + val routesNames = routes.map { it.shortName } + //create new item click listener every time + val adapter = RouteOnlyLineAdapter(routesNames){ pos, _ -> + val r = routes[pos] + fragmentListener.showLineOnMap(r.gtfsId) + } + favoritesRecyclerView.adapter = adapter + } //onClicks urbanLinesTitle.setOnClickListener { @@ -127,14 +149,33 @@ touristLinesTitle.setOnClickListener { openLinesAndCloseOthersIfNeeded(AG_TOUR) } + favoritesTitle.setOnClickListener { + closeOpenFavorites() + } + arrows[AG_FAV]?.setOnClickListener { + closeOpenFavorites() + } //arrows onClicks - for(k in arrows.keys){ + for(k in Companion.AGENCIES){ //k is either AG_TOUR, AG_EXTRAURBAN, AG_URBAN arrows[k]?.setOnClickListener { openLinesAndCloseOthersIfNeeded(k) } } + return rootView } + private fun closeOpenFavorites(){ + if(favoritesRecyclerView.visibility == View.VISIBLE){ + //close it + favoritesRecyclerView.visibility = View.GONE + setOpen(arrows[AG_FAV]!!, false) + viewModel.favoritesExpanded.value = false + } else{ + favoritesRecyclerView.visibility = View.VISIBLE + setOpen(arrows[AG_FAV]!!, true) + viewModel.favoritesExpanded.value = true + } + } private fun openLinesAndCloseOthersIfNeeded(agency: String){ if(openRecyclerView!="" && openRecyclerView!= agency) { @@ -205,6 +246,20 @@ override fun onResume() { super.onResume() + val pref = PreferencesHolder.getMainSharedPreferences(requireContext()) + val res = pref.getStringSet(PreferencesHolder.PREF_FAVORITE_LINES, HashSet()) + res?.let { viewModel.setFavoritesLinesIDs(HashSet(it))} + //restore state + viewModel.favoritesExpanded.value?.let { + if(!it){ + //close it + favoritesRecyclerView.visibility = View.GONE + setOpen(arrows[AG_FAV]!!, false) + } else{ + favoritesRecyclerView.visibility = View.VISIBLE + setOpen(arrows[AG_FAV]!!, true) + } + } viewModel.isUrbanExpanded.value?.let { if(it) { urbanRecyclerView.visibility = View.VISIBLE @@ -246,6 +301,7 @@ companion object { private const val COLUMN_WIDTH_DP=200 + private const val AG_FAV = "fav" private const val AG_URBAN = "gtt:U" private const val AG_EXTRAURB ="gtt:E" private const val AG_TOUR ="gtt:T" diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesGridShowingViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesGridShowingViewModel.kt --- a/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesGridShowingViewModel.kt +++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesGridShowingViewModel.kt @@ -4,10 +4,11 @@ import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.map import it.reyboz.bustorino.data.GtfsRepository -import it.reyboz.bustorino.data.NextGenDB -import it.reyboz.bustorino.data.OldDataRepository import it.reyboz.bustorino.data.gtfs.GtfsDatabase +import it.reyboz.bustorino.data.gtfs.GtfsRoute +import it.reyboz.bustorino.util.LinesNameSorter class LinesGridShowingViewModel(application: Application) : AndroidViewModel(application) { @@ -24,4 +25,27 @@ val isUrbanExpanded = MutableLiveData(true) val isExtraUrbanExpanded = MutableLiveData(false) val isTouristExpanded = MutableLiveData(false) + val favoritesExpanded = MutableLiveData(true) + + val favoritesLinesIDs = MutableLiveData<HashSet<String>>() + + private val linesNameSorter = LinesNameSorter() + private val linesComparator = Comparator<GtfsRoute> { a,b -> + return@Comparator linesNameSorter.compare(a.shortName, b.shortName) + } + + fun setFavoritesLinesIDs(linesIds: HashSet<String>){ + favoritesLinesIDs.value = linesIds + } + + val favoritesLines = favoritesLinesIDs.map {lineIds -> + val linesList = ArrayList<GtfsRoute>() + if (lineIds.size == 0 || routesLiveData.value==null) return@map linesList + for(line in routesLiveData.value!!){ + if(lineIds.contains(line.gtfsId)) + linesList.add(line) + } + linesList.sortWith(linesComparator) + return@map linesList + } } \ No newline at end of file diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesViewModel.kt --- a/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesViewModel.kt +++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesViewModel.kt @@ -52,6 +52,9 @@ gtfsRepo.getPatternsWithStopsForRouteID(it) } + val gtfsRoute = routeIDToSearch.switchMap { + gtfsRepo.getRouteFromGtfsId(it) + } fun setRouteIDQuery(routeID: String){ diff --git a/app/src/main/res/drawable-it-xhdpi/tuto_menu.webp b/app/src/main/res/drawable-it-xhdpi/tuto_menu.webp 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 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001 literal 0 Hc$@<O00001 diff --git a/app/src/main/res/drawable/close_white_large.xml b/app/src/main/res/drawable/close_white_large.xml new file mode 100644 --- /dev/null +++ b/app/src/main/res/drawable/close_white_large.xml @@ -0,0 +1,5 @@ +<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="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/> +</vector> diff --git a/app/src/main/res/drawable/ic_star_filled.xml b/app/src/main/res/drawable/ic_star_filled.xml --- a/app/src/main/res/drawable/ic_star_filled.xml +++ b/app/src/main/res/drawable/ic_star_filled.xml @@ -1,6 +1,6 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" + android:width="28dp" + android:height="28dp" android:viewportWidth="24" android:viewportHeight="24"> <path diff --git a/app/src/main/res/drawable/ic_star_outline.xml b/app/src/main/res/drawable/ic_star_outline.xml --- a/app/src/main/res/drawable/ic_star_outline.xml +++ b/app/src/main/res/drawable/ic_star_outline.xml @@ -1,6 +1,6 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" + android:width="28dp" + android:height="28dp" android:viewportWidth="24" android:viewportHeight="24"> <path diff --git a/app/src/main/res/layout/activity_intro.xml b/app/src/main/res/layout/activity_intro.xml --- a/app/src/main/res/layout/activity_intro.xml +++ b/app/src/main/res/layout/activity_intro.xml @@ -26,6 +26,17 @@ android:contentDescription="@string/next" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent"/> + + <ImageButton + android:src="@drawable/close_white_large" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:id="@+id/btnCompactClose" + android:backgroundTint="?colorAccent" + android:textColor="@color/white" + app:circularflow_radiusInDP="5dp" + android:contentDescription="@string/next" + android:visibility="gone" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent"/> <androidx.viewpager2.widget.ViewPager2 android:layout_width="0dp" android:layout_height="0dp" diff --git a/app/src/main/res/layout/fragment_intro.xml b/app/src/main/res/layout/fragment_intro.xml --- a/app/src/main/res/layout/fragment_intro.xml +++ b/app/src/main/res/layout/fragment_intro.xml @@ -20,7 +20,7 @@ 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:layout_marginTop="30dp" android:maxWidth="280dp" android:textSize="18sp" android:textAlignment="center" @@ -37,7 +37,9 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="@id/tutorialTextView" android:backgroundTint="?colorPrimaryDark" + android:fontFamily="@font/pitagon_semibold" android:textColor="@color/white" - app:layout_constraintEnd_toEndOf="@id/tutorialTextView" android:layout_marginTop="12dp"/> + app:layout_constraintEnd_toEndOf="@id/tutorialTextView" + android:layout_marginTop="18dp"/> </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_lines_detail.xml b/app/src/main/res/layout/fragment_lines_detail.xml --- a/app/src/main/res/layout/fragment_lines_detail.xml +++ b/app/src/main/res/layout/fragment_lines_detail.xml @@ -20,18 +20,58 @@ android:layout_marginTop="8dp" android:gravity="center_horizontal|center_vertical" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp" android:layout_marginEnd="8dp"/> + <ImageButton + android:src="@drawable/ic_list_30" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:id="@+id/switchImageButton" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintRight_toRightOf="parent" + android:layout_margin="6dp" + android:backgroundTint="@color/blue_620" + /> + <androidx.cardview.widget.CardView + android:layout_width="wrap_content" android:layout_height="30dp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="@id/switchImageButton" + app:layout_constraintBottom_toBottomOf="@id/switchImageButton" + android:id="@+id/starCardView" + android:layout_marginStart="10dp" + android:minHeight="20sp" + android:elevation="10dp" + android:padding="5dp"> + <ImageButton + android:id="@+id/favoritesButton" + android:layout_width="45dp" + android:layout_height="match_parent" + android:layout_gravity="end" + android:background="@android:color/transparent" + android:foreground="?attr/selectableItemBackground" + app:srcCompat="@drawable/ic_star_outline" + tools:ignore="OnClick"/> + </androidx.cardview.widget.CardView> + <TextView + android:text="DCCII" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:id="@+id/lineDescripTextView" + app:layout_constraintTop_toBottomOf="@id/titleTextView" + app:layout_constraintLeft_toLeftOf="@id/titleTextView" + app:layout_constraintRight_toRightOf="@id/titleTextView" + android:textColor="@color/grey_700" + android:textSize="16sp" + android:maxWidth="300sp" + android:layout_marginTop="8dp"/> <Spinner android:layout_width="0dp" android:layout_height="wrap_content" android:id="@+id/patternsSpinner" - app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/routeDescrTextView" - android:layout_marginTop="8dp" app:layout_constraintTop_toBottomOf="@+id/titleTextView" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/headingToTextView" + android:layout_marginTop="4dp" app:layout_constraintTop_toBottomOf="@+id/lineDescripTextView" android:layout_marginStart="4dp"/> <TextView android:text="@string/direction_duep" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:id="@+id/routeDescrTextView" + android:id="@+id/headingToTextView" app:layout_constraintStart_toStartOf="parent" android:textAppearance="@style/TextAppearance.AppCompat.Body1" android:textColor="?android:attr/textColorPrimary" @@ -79,16 +119,7 @@ android:layout_marginRight="10dp" android:layout_marginEnd="10dp" />--> - <ImageButton - android:src="@drawable/ic_list_30" - android:layout_width="wrap_content" - android:layout_height="wrap_content" android:id="@+id/switchImageButton" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintRight_toRightOf="parent" - app:layout_constraintBottom_toTopOf="@id/patternsSpinner" - android:layout_margin="6dp" - android:backgroundTint="@color/blue_500" - /> + <View android:id="@+id/divider" diff --git a/app/src/main/res/layout/fragment_lines_grid.xml b/app/src/main/res/layout/fragment_lines_grid.xml --- a/app/src/main/res/layout/fragment_lines_grid.xml +++ b/app/src/main/res/layout/fragment_lines_grid.xml @@ -15,6 +15,44 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:animateLayoutChanges="true" > + <ImageView + android:src="@drawable/baseline_chevron_right_24" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:id="@+id/arrowFavorites" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintBottom_toBottomOf="@id/favoritesTitleView" + android:layout_margin="4dp" + android:layout_marginStart="16dp" + android:rotation="90" + /> + <TextView android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/favorites_lines" + android:textAppearance="@style/TextAppearance.AppCompat.Body2" + android:textSize="@dimen/subtitle_size" + android:layout_margin="4dp" + android:textColor="@color/black_900" + android:gravity="center" + android:id="@+id/favoritesTitleView" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintLeft_toRightOf="@id/arrowFavorites" + app:layout_constraintBottom_toTopOf="@id/favoritesRecyclerView" + android:layout_marginLeft="6dp" + app:layout_constraintVertical_bias="0.0" + app:layout_constraintVertical_chainStyle="packed"/> + <androidx.recyclerview.widget.RecyclerView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:id="@+id/favoritesRecyclerView" + android:layout_marginLeft="20dp" + android:layout_marginRight="20dp" + android:visibility="visible" + app:layout_constraintTop_toBottomOf="@id/favoritesTitleView" + app:layout_constraintBottom_toTopOf="@id/urbanLinesTitleView" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintVertical_bias="0.0" + + /> <ImageView android:src="@drawable/baseline_chevron_right_24" android:layout_width="wrap_content" @@ -34,12 +72,12 @@ android:textColor="@color/black_900" android:gravity="center" android:id="@+id/urbanLinesTitleView" - app:layout_constraintTop_toTopOf="parent" + app:layout_constraintTop_toBottomOf="@id/favoritesRecyclerView" app:layout_constraintLeft_toRightOf="@id/arrowUrb" app:layout_constraintBottom_toTopOf="@id/urbanLinesRecyclerView" android:layout_marginLeft="6dp" app:layout_constraintVertical_bias="0.0" - app:layout_constraintVertical_chainStyle="packed"/> + /> <androidx.recyclerview.widget.RecyclerView android:layout_width="match_parent" android:layout_height="0dp" 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 @@ -211,12 +211,15 @@ <string name="pref_shown_startup_def_desc">Tocca per cambiare</string> <string name="positions_source_pref_title">Fonte posizioni in tempo reale di bus e tram</string> - <array name="positions_source_sel"> <item>MaTO (aggiornate più spesso, può non funzionare)</item> <item>GTFS RT (più stabile)</item> </array> + <string name="favorites_line_add">Linea aggiunta ai preferiti</string> + <string name="favorites_line_remove">Linea rimossa dai preferiti</string> + <string name="favorites_lines">Preferite</string> + <!-- lines --> <string name="long_press_stop_4_options">Tocca a lungo la fermata per le opzioni</string> <string name="remove_all_trips">Rimuovi tutti i trip GTFS</string> @@ -246,7 +249,7 @@ <![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> + <string name="close_tutorial">Capito, chiudi il tutorial</string> </resources> 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 @@ -39,7 +39,7 @@ <string name="extraurban_lines">Extra urban lines</string> <string name="turist_lines">Tourist lines</string> - <string name="direction_duep">Heading to:</string> + <string name="direction_duep">Destination:</string> <string name="lines_fill">Lines: %1$s</string> <string name="line_fill">Line: %1$s</string> <string name="no_passages">No timetable found</string> @@ -55,6 +55,9 @@ <string name="action_author">Meet the author</string> <string name="added_in_favorites">Bus stop is now in your favorites</string> <string name="removed_from_favorites">Bus stop removed from your favorites</string> + <string name="favorites_line_add">Added line to favorites</string> + <string name="favorites_line_remove">Remove line from favorites</string> + <string name="favorites_lines">Favorites</string> <string name="action_favorites">Favorites</string> <string name="title_activity_favorites">Favorites</string> <string name="title_activity_map">Map</string> @@ -281,6 +284,6 @@ <![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> + <string name="close_tutorial">OK, close the tutorial</string> </resources>