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 @@ -76,9 +76,20 @@ } @Override - public void showMapCenteredOnStop(Stop stop) { + public void showMapCenteredOnStop(@Nullable Stop stop) { } + + @Override + public void openLinesFragment() { + Log.d(DEBUG_TAG, "Asked to open lines grid fragment"); + } + + @Override + public void openFavoritesFragment() { + + } + @Override public void openLineFromStop(String routeGtfsId, @Nullable String stopIDFrom){ @@ -101,4 +112,9 @@ tr.commit(); } + @Override + public void openNearbyStopsFragment() { + Log.d(DEBUG_TAG, "Requested to open nearby stops fragment"); + } + } \ 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 @@ -552,9 +552,10 @@ * @param fraMan the fragmentManager * @param arguments args for the fragment */ - private static void createShowMainFragment(FragmentManager fraMan,@Nullable Bundle arguments, boolean addToBackStack){ + private static MainScreenFragment createShowMainFragment(FragmentManager fraMan,@Nullable Bundle arguments, boolean addToBackStack){ + var frag = MainScreenFragment.newInstance(null); FragmentTransaction ft = fraMan.beginTransaction() - .replace(R.id.mainActContentFrame, MainScreenFragment.class, arguments, MainScreenFragment.FRAGMENT_TAG) + .replace(R.id.mainActContentFrame, frag, MainScreenFragment.FRAGMENT_TAG) .setReorderingAllowed(false) /*.setCustomAnimations( R.anim.slide_in, // enter @@ -565,6 +566,7 @@ .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); if (addToBackStack) ft.addToBackStack(null); ft.commit(); + return frag; } private void requestMapFragment(final boolean allowReturn){ @@ -630,12 +632,12 @@ .commit(); } - private void showMainFragment(boolean addToBackStack){ + private MainScreenFragment showMainFragment(boolean addToBackStack){ FragmentManager fraMan = getSupportFragmentManager(); Fragment fragment = fraMan.findFragmentByTag(MainScreenFragment.FRAGMENT_TAG); final MainScreenFragment mainScreenFragment; if (fragment==null | !(fragment instanceof MainScreenFragment)){ - createShowMainFragment(fraMan, null, addToBackStack); + mainScreenFragment = createShowMainFragment(fraMan, null, addToBackStack); } else if(!fragment.isVisible()){ @@ -646,7 +648,7 @@ } else{ mainScreenFragment = (MainScreenFragment) fragment; } - //return mainScreenFragment; + return mainScreenFragment; } @Nullable private MainScreenFragment getMainFragmentIfVisible(){ @@ -661,6 +663,7 @@ public void showFloatingActionButton(boolean yes) { //TODO } + /* public void setDrawerSelectedItem(String fragmentTag){ switch (fragmentTag){ @@ -773,6 +776,27 @@ tr.commit(); } + @Override + public void openNearbyStopsFragment() { + var fr = getMainFragmentIfVisible(); + if (fr == null){ + // it is not visible, + fr = showMainFragment(false); + + } + fr.openNearbyStopsFragment(); + } + + @Override + public void openLinesFragment() { + showLinesFragment(getSupportFragmentManager(), true, null); + } + + @Override + public void openFavoritesFragment() { + checkAndShowFavoritesFragment(getSupportFragmentManager(), true); + } + @Override public void toggleSpinner(boolean state) { MainScreenFragment probableFragment = getMainFragmentIfVisible(); @@ -791,10 +815,12 @@ @Override - public void showMapCenteredOnStop(Stop stop) { + public void showMapCenteredOnStop(@Nullable Stop stop) { createAndShowMapFragment(stop, true); } + + //Map Fragment stuff void createAndShowMapFragment(@Nullable Stop stop, boolean addToBackStack){ final FragmentManager fm = getSupportFragmentManager(); diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt --- a/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt @@ -758,11 +758,15 @@ return null } - fun isFragmentForTheSameStop(p: Palina): Boolean { - return if (tag != null) tag == getFragmentTag(p) + fun isFragmentForTheSameStop(stopID: String) : Boolean{ + return if (tag != null) tag == getFragmentTag(stopID) else false } + fun isFragmentForTheSameStop(p: Palina): Boolean { + return isFragmentForTheSameStop(p.ID) + } + /** * Request arrivals in the fragment @@ -812,10 +816,13 @@ return fragment } + + //return "palina_" + p.ID + @JvmStatic - fun getFragmentTag(p: Palina): String { - return "palina_" + p.ID - } + fun getFragmentTag(stopID: String) = "palina_$stopID" + @JvmStatic + fun getFragmentTag(p: Palina) = getFragmentTag(p.ID) @JvmStatic fun getArrivalsWorkID(stopID: String) = "arrivals_search_$stopID" diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/ButtonsFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/ButtonsFragment.kt new file mode 100644 --- /dev/null +++ b/app/src/main/java/it/reyboz/bustorino/fragments/ButtonsFragment.kt @@ -0,0 +1,145 @@ +package it.reyboz.bustorino.fragments + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.util.Log +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.GridLayout +import android.widget.ImageView +import android.widget.TextView +import it.reyboz.bustorino.ActivitySettings +import it.reyboz.bustorino.R + + +/** + * A simple [Fragment] subclass. + * Use the [ButtonsFragment.newInstance] factory method to + * create an instance of this fragment. + */ +class ButtonsFragment : ScreenBaseFragment() { + + private lateinit var gridLayout: GridLayout + + private var listener: CommonFragmentListener? = null + private lateinit var items: List + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + arguments?.let { + + } + if(listener is FragmentListenerMain){ + val ll = listener as FragmentListenerMain + ll.enableRefreshLayout(false) + } + } + private val marginHoriz = 30 + private val marginVer = 25 + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + val root = inflater.inflate(R.layout.fragment_buttons, container, false) + items = listOf( + CardMenuItem(CardAction.NEARBY, getString(R.string.nearby_me), R.drawable.compass_3_fill), + CardMenuItem(CardAction.MAP, getString(R.string.map), R.drawable.map), + CardMenuItem(CardAction.FAVORITES_STOPS, getString(R.string.action_favorites), R.drawable.ic_star_filled_white), + CardMenuItem(CardAction.LINES, getString(R.string.lines), R.drawable.ic_moving_emph), + CardMenuItem(CardAction.SETTINGS, getString(R.string.action_settings), R.drawable.ic_baseline_settings_24), + ) + gridLayout = root.findViewById(R.id.homeGridLayout) + + items.forEach { item -> + // Inflate base layout + val cardView = LayoutInflater.from(requireContext()) + .inflate(R.layout.item_card_button, gridLayout, false) + + // Popola icona e testo + cardView.findViewById(R.id.cardIcon).setImageResource(item.iconRes) + cardView.findViewById(R.id.cardLabel).text = item.label + // Parametri griglia: colonna flessibile + margini + cardView.layoutParams = GridLayout.LayoutParams().apply { + width = 0 + height = GridLayout.LayoutParams.WRAP_CONTENT + columnSpec = GridLayout.spec(GridLayout.UNDEFINED, 1f) + setMargins(marginHoriz, marginVer, marginHoriz, marginVer) // margini tra le card + } + + // Click + cardView.setOnClickListener { onCardClicked(item) } + + gridLayout.addView(cardView) + } + return root + } + + + private fun onCardClicked(item: CardMenuItem) { + Log.d(DEBUG_TAG, "onCardClicked - item: ${item}, listener: ${listener}") + // reagisci al tap + val list = listener + if(list == null){ + Log.w(DEBUG_TAG, "onCardClicked - listener is null") + } else + when(item.action) { + CardAction.NEARBY -> { + list.openNearbyStopsFragment() + } + CardAction.MAP -> { list.showMapCenteredOnStop(null)} + CardAction.LINES -> { list.openLinesFragment();} + CardAction.SETTINGS -> { startActivity(Intent(requireContext(), ActivitySettings::class.java)) } + CardAction.FAVORITES_STOPS -> { list.openFavoritesFragment();} + } + } + + override fun getBaseViewForSnackBar(): View? { + return null + } + + override fun onAttach(context: Context) { + super.onAttach(context) + if (context is CommonFragmentListener) { + listener = context + Log.d(DEBUG_TAG, "onAttach") + } else{ + throw RuntimeException("$context must implement CommonFragmentListener") + } + } + + override fun onDetach() { + listener = null + Log.d(DEBUG_TAG, "onDetach") + super.onDetach() + } + + companion object { + /** + * @return A new instance of fragment ButtonsFragment. + */ + @JvmStatic + fun newInstance() = + ButtonsFragment().apply { + arguments = Bundle().apply { + } + } + const val DEBUG_TAG = "BusTO-ButtonsFragment" + + enum class CardAction { + NEARBY, MAP, FAVORITES_STOPS, LINES, SETTINGS + } + + data class CardMenuItem( + val action: CardAction, + val label: String, + val iconRes: Int + ) + + const val FRAGMENT_TAG = "HomeButtonsFragment" + } +} \ No newline at end of file diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/CommonFragmentListener.java b/app/src/main/java/it/reyboz/bustorino/fragments/CommonFragmentListener.java --- a/app/src/main/java/it/reyboz/bustorino/fragments/CommonFragmentListener.java +++ b/app/src/main/java/it/reyboz/bustorino/fragments/CommonFragmentListener.java @@ -35,7 +35,7 @@ * We want to open the map on the specified stop * @param stop needs to have location data (latitude, longitude) */ - void showMapCenteredOnStop(Stop stop); + void showMapCenteredOnStop(@Nullable Stop stop); /** * We want to show the line in detail for route coming from a stop @@ -50,4 +50,16 @@ * @param args extra arguments given as Bundle */ void openLineFromVehicle(String routeGtfsId, @Nullable String optionalPatternId, @Nullable Bundle args); + + /** + * Show the nearby stops fragment + */ + void openNearbyStopsFragment(); + + /** + * Show the lines + */ + void openLinesFragment(); + + void openFavoritesFragment(); } diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/FragmentHelper.java b/app/src/main/java/it/reyboz/bustorino/fragments/FragmentHelper.java --- a/app/src/main/java/it/reyboz/bustorino/fragments/FragmentHelper.java +++ b/app/src/main/java/it/reyboz/bustorino/fragments/FragmentHelper.java @@ -20,11 +20,12 @@ import android.content.Context; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; -import android.os.AsyncTask; import android.util.Log; import android.widget.Toast; @@ -84,48 +85,43 @@ * Called when you need to create a fragment for a specified Palina * @param p the Stop that needs to be displayed */ - public void createOrUpdateStopFragment(Palina p, boolean addToBackStack){ - boolean sameFragment; + public void showArrivalsFragmentForStop(@NonNull Palina p, boolean addToBackStack){ + boolean sameFragment = false; ArrivalsFragment arrivalsFragment = null; + final FragmentManager fm = managerWeakRef.get(); + if(fm == null) return; - if(managerWeakRef.get()==null || shouldHaltAllActivities) { - //SOMETHING WENT VERY WRONG - Log.e(DEBUG_TAG, "We are asked for a new stop but we can't show anything"); - return; - } + if(fm.findFragmentById(primaryFrameLayout) instanceof ArrivalsFragment frag) { + sameFragment = frag.isFragmentForTheSameStop(p); + if(sameFragment) { + arrivalsFragment = frag; + Log.d("BusTO", "Same bus stop, accessing existing fragment"); - FragmentManager fm = managerWeakRef.get(); - - if(fm.findFragmentById(primaryFrameLayout) instanceof ArrivalsFragment) { - arrivalsFragment = (ArrivalsFragment) fm.findFragmentById(primaryFrameLayout); - //Log.d(DEBUG_TAG, "Arrivals are for fragment with same stop?"); - if (arrivalsFragment == null) sameFragment = false; - else sameFragment = arrivalsFragment.isFragmentForTheSameStop(p); - } else { - sameFragment = false; - Log.d(DEBUG_TAG, "We aren't showing an ArrivalsFragment"); - - } - setLastSuccessfullySearchedBusStop(p); - if (sameFragment){ - Log.d("BusTO", "Same bus stop, accessing existing fragment"); - arrivalsFragment = (ArrivalsFragment) fm.findFragmentById(primaryFrameLayout); - if (arrivalsFragment == null) sameFragment = false; + } } - if(!sameFragment) { - //set the String to be displayed on the fragment - String displayName = p.getStopDisplayName(); - if (displayName != null && displayName.length() > 0) { - arrivalsFragment = ArrivalsFragment.newInstance(p.ID,displayName); - } else { - arrivalsFragment = ArrivalsFragment.newInstance(p.ID); + if(!sameFragment) { + // get old fragment + var frag = fm.findFragmentByTag(ArrivalsFragment.getFragmentTag(p)); + if(frag instanceof ArrivalsFragment) { + attachFragmentToContainer(fm, frag, null, true, addToBackStack); + arrivalsFragment = (ArrivalsFragment) frag; + } else { // create new fragment + //set the String to be displayed on the fragment + String displayName = p.getStopDisplayName(); + if (displayName != null && !displayName.isEmpty()) { + arrivalsFragment = ArrivalsFragment.newInstance(p.ID, displayName); + } else { + arrivalsFragment = ArrivalsFragment.newInstance(p.ID); + } + String probableTag = ArrivalsFragment.getFragmentTag(p); + attachFragmentToContainer(fm, arrivalsFragment, probableTag, true, addToBackStack); } - String probableTag = ArrivalsFragment.getFragmentTag(p); - attachFragmentToContainer(fm,arrivalsFragment,new AttachParameters(probableTag, true, addToBackStack)); } - // DO NOT CALL `setListAdapter` ever on arrivals fragment - arrivalsFragment.updateFragmentData(p); + setLastSuccessfullySearchedBusStop(p); + // update the data only if I have information about the passaggi + if(p.getTotalNumberOfPassages() > 0) + arrivalsFragment.updateFragmentData(p); // enable fragment auto refresh arrivalsFragment.setReloadOnResume(true); @@ -146,8 +142,8 @@ Log.e(DEBUG_TAG, "We are asked for a new stop but we can't show anything"); return; } - attachFragmentToContainer(managerWeakRef.get(),listfragment, - new AttachParameters("search_"+query, false,addToBackStack)); + attachFragmentToContainer(managerWeakRef.get(), + listfragment, "search_"+query, false, addToBackStack); listfragment.setStopList(resultList); //listenerMain.readyGUIfor(FragmentKind.STOPS); toggleSpinner(false); @@ -163,30 +159,34 @@ } /** - * Attach a new fragment to a cointainer + * Attach a new fragment to the appropriate container * @param fm the FragmentManager * @param fragment the Fragment - * @param parameters attach parameters + * @param tagAttach attach tag (can be null, the fragment's own tag has preference) + * @param addToBackStack if the transaction is to be added to the stack + * @param toSecondaryFrame if the fragment goes to the secondary frame */ - protected void attachFragmentToContainer(FragmentManager fm,Fragment fragment, AttachParameters parameters){ + protected void attachFragmentToContainer(FragmentManager fm, Fragment fragment, @Nullable String tagAttach, boolean toSecondaryFrame, boolean addToBackStack){ if(shouldHaltAllActivities) //nothing to do return; FragmentTransaction ft = fm.beginTransaction(); int frameID; - if(parameters.attachToSecondaryFrame && secondaryFrameLayout!=NO_FRAME) - // ft.replace(secondaryFrameLayout,fragment,tag); + if(toSecondaryFrame && secondaryFrameLayout!=NO_FRAME) frameID = secondaryFrameLayout; - else frameID = primaryFrameLayout; - switch (parameters.transaction){ - case REPLACE: - ft.replace(frameID,fragment,parameters.tag); - - } - if (parameters.addToBackStack) - ft.addToBackStack("state_"+parameters.tag); + else + frameID = primaryFrameLayout; + var tag = fragment.getTag(); + if(tag == null) tag = tagAttach; + // there is only one case + //switch (pars.transaction){ + // case REPLACE: + ft.replace(frameID,fragment,tag); + //} + if (addToBackStack) + ft.addToBackStack("state_"+tag); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE); - if(!fm.isDestroyed() && !shouldHaltAllActivities) - ft.commit(); + //if(!fm.isDestroyed() && !shouldHaltAllActivities) + ft.commit(); //fm.executePendingTransactions(); } @@ -260,11 +260,12 @@ private void showShortToast(int messageID){ showToastMessage(messageID, true); } - + /* + // 18/05/2026: Commenting, do not remove, might be useful later enum Transaction{ REPLACE, } - static final class AttachParameters { + private static final class AttachParameters { String tag; boolean attachToSecondaryFrame; Transaction transaction; @@ -284,4 +285,6 @@ this.transaction = Transaction.REPLACE; } } + + */ } 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 @@ -36,9 +36,9 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; +import androidx.lifecycle.ViewModelProvider; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import android.os.Handler; import android.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; @@ -53,16 +53,15 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton; -import java.util.List; import java.util.Map; import it.reyboz.bustorino.R; import it.reyboz.bustorino.backend.*; -import it.reyboz.bustorino.data.PreferencesHolder; import it.reyboz.bustorino.middleware.BarcodeScanContract; import it.reyboz.bustorino.middleware.BarcodeScanOptions; import it.reyboz.bustorino.middleware.BarcodeScanUtils; import it.reyboz.bustorino.util.Permissions; +import it.reyboz.bustorino.viewmodels.IntroViewModel; import static it.reyboz.bustorino.backend.utils.getBusStopIDFromUri; import static it.reyboz.bustorino.util.Permissions.LOCATION_PERMISSIONS; @@ -107,7 +106,7 @@ //private ImageButton addToFavorites; //// HIDDEN BUT IMPORTANT ELEMENTS //// private FragmentManager childFragMan; - + private IntroViewModel introViewModel; private void refreshStop() { if(getContext() == null){ Log.w(DEBUG_TAG,"Asked to refresh stop but context is null"); @@ -158,6 +157,7 @@ /// LOCATION STUFF /// boolean pendingIntroRun = false; boolean pendingNearbyStopsFragmentRequest = false; + boolean pendingNearbyAddToBackStack = false; boolean locationPermissionGranted, locationPermissionAsked = false; //AppLocationManager locationManager; private final ActivityResultLauncher requestPermissionLauncher = @@ -186,7 +186,7 @@ //showNearbyStopsFragment(); Log.d(DEBUG_TAG, "We have location permission"); if (pendingNearbyStopsFragmentRequest) { - showNearbyFragmentIfPossible(); + showNearbyFragmentIfPossible(pendingNearbyAddToBackStack); pendingNearbyStopsFragmentRequest = false; } } @@ -206,8 +206,12 @@ } - public static MainScreenFragment newInstance() { - return new MainScreenFragment(); + public static MainScreenFragment newInstance(@Nullable String pendingStopID) { + var frag = new MainScreenFragment(); + var bundle = new Bundle(); + bundle.putString(PENDING_STOP_SEARCH, pendingStopID); + frag.setArguments(bundle); + return frag; } @Override @@ -216,9 +220,11 @@ if (getArguments() != null) { //do nothing Log.d(DEBUG_TAG, "ARGS ARE NOT NULL: "+getArguments()); - if (getArguments().getString(PENDING_STOP_SEARCH)!=null) - pendingStopID = getArguments().getString(PENDING_STOP_SEARCH); + var eventualStopSearch = getArguments().getString(PENDING_STOP_SEARCH); + if (eventualStopSearch!=null) + pendingStopID = eventualStopSearch; } + } @Override @@ -283,6 +289,13 @@ cr.setPowerRequirement(Criteria.NO_REQUIREMENT); */ //locationManager = AppLocationManager.getInstance(requireContext()); + introViewModel = new ViewModelProvider(requireActivity()).get(IntroViewModel.class); + introViewModel.getIntroIsRunning().observe(getViewLifecycleOwner(), isRunning -> { + pendingIntroRun = isRunning; + }); + + if(pendingStopID == null) + showButtonsFragment(true); Log.d(DEBUG_TAG, "OnCreateView, savedInstanceState null: "+(savedInstanceState==null)); @@ -361,7 +374,6 @@ throw new RuntimeException(context + " must implement CommonFragmentListener"); } - } @Override public void onDetach() { @@ -377,18 +389,9 @@ if (setupOnStart) { if (pendingStopID==null){ - if(PreferencesHolder.hasIntroFinishedOneShot(requireContext())){ - Log.d(DEBUG_TAG, "Showing nearby stops"); - if(!checkLocationPermission()){ - requestLocationPermission(); - pendingNearbyStopsFragmentRequest = true; - } - else { - showNearbyFragmentIfPossible(); - } - } else { - //The Introductory Activity is about to be started, hence pause the request and show later - pendingIntroRun = true; + if(!pendingIntroRun){ + //show the fragment + //showButtonsFragment(); } } @@ -400,6 +403,33 @@ } } + private void showButtonsFragment(boolean addInsteadOfReplace){ + + swipeRefreshLayout.setVisibility(View.VISIBLE); + var ft = childFragMan.beginTransaction(); + var frag = ButtonsFragment.newInstance(); + if(addInsteadOfReplace) + ft.add(R.id.resultFrame,frag, ButtonsFragment.FRAGMENT_TAG); + else{ + ft.replace(R.id.resultFrame, frag, ButtonsFragment.FRAGMENT_TAG); + ft.addToBackStack(null); + } + ft.commit(); + } + + private void showNearbyStopsFragmentChecking(boolean addToBackStack){ + if(!checkLocationPermission()){ + requestLocationPermission(); + pendingNearbyStopsFragmentRequest = true; + pendingNearbyAddToBackStack = addToBackStack; + Log.d(DEBUG_TAG, "requesting location permission for nearby fragment"); + } + else { + Log.d(DEBUG_TAG, "Showing nearby stops fragment"); + showNearbyFragmentIfPossible(addToBackStack); + } + } + @Override public void onResume() { super.onResume(); @@ -409,18 +439,6 @@ //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 { - showNearbyFragmentIfPossible(); - } - //deactivate flag - pendingIntroRun = false; - } if(Permissions.bothLocationPermissionsGranted(con)){ Log.d(DEBUG_TAG, "Location permission OK"); //if(!locationManager.isRequesterRegistered(requester)) @@ -430,18 +448,22 @@ Log.d(DEBUG_TAG, "Pending stop ID for arrivals: "+pendingStopID); //this is the second time we are attaching this fragment -> Log.d(DEBUG_TAG, "Waiting for new stop request: "+ suppressArrivalsReload); - //TODO: if we come back to this from another fragment, and the user has given again the permission - // for the Location, we should show the Nearby Stops + if(!suppressArrivalsReload && pendingStopID==null){ //none of the following cases are true // check if we are showing any fragment + /* + //TODO: check if this is needed final Fragment fragment = getChildFragmentManager().findFragmentById(R.id.resultFrame); + if(fragment==null || swipeRefreshLayout.getVisibility() != View.VISIBLE){ //we are not showing anything if(Permissions.anyLocationPermissionsGranted(getContext())){ showNearbyFragmentIfPossible(); } } + + */ } if (suppressArrivalsReload){ // we have to suppress the reloading of the (possible) ArrivalsFragment @@ -476,8 +498,6 @@ } - - /* GUI METHODS */ @@ -613,25 +633,6 @@ //actionHelpMenuItem.setVisible(false); } - private void actuallyShowNearbyStopsFragment(){ - swipeRefreshLayout.setVisibility(View.VISIBLE); - final Fragment existingFrag = childFragMan.findFragmentById(R.id.resultFrame); - // fragment; - if (!(existingFrag instanceof NearbyStopsFragment)){ - Log.d(DEBUG_TAG, "actually showing Nearby Stops Fragment"); - //there is no fragment showing - final NearbyStopsFragment fragment = NearbyStopsFragment.newInstance(NearbyStopsFragment.FragType.STOPS); - - FragmentTransaction ft = childFragMan.beginTransaction(); - - ft.replace(R.id.resultFrame, fragment, NearbyStopsFragment.FRAGMENT_TAG); - if (getActivity()!=null && !getActivity().isFinishing()) - ft.commit(); - else Log.e(DEBUG_TAG, "Not showing nearby fragment because activity null or is finishing"); - } - } - - @Override public void showFloatingActionButton(boolean yes) { mListener.showFloatingActionButton(yes); @@ -678,12 +679,27 @@ @Override public void openLineFromStop(String routeGtfsId, @Nullable String stopIDFrom) { //pass to activity - mListener.openLineFromStop(routeGtfsId, stopIDFrom); + if(mListener!=null) mListener.openLineFromStop(routeGtfsId, stopIDFrom); } @Override public void openLineFromVehicle(String routeGtfsId, @Nullable String optionalPatternId, @Nullable Bundle args) { - mListener.openLineFromVehicle(routeGtfsId, optionalPatternId, args); + if(mListener!=null) mListener.openLineFromVehicle(routeGtfsId, optionalPatternId, args); + } + + @Override + public void openNearbyStopsFragment() { + showNearbyStopsFragmentChecking(true); + } + + @Override + public void openLinesFragment() { + if(mListener!=null) mListener.openLinesFragment(); + } + + @Override + public void openFavoritesFragment() { + if(mListener!=null) mListener.openFavoritesFragment(); } @Override @@ -709,29 +725,28 @@ Log.e(DEBUG_TAG, "Asked for arrivals with null context"); return; } - ArrivalsFetcher[] fetchers = utils.getDefaultArrivalsFetchers(getContext()).toArray(new ArrivalsFetcher[0]); - if (ID == null || ID.length() <= 0) { + if (ID == null || ID.isEmpty()) { // we're still in UI thread, no need to mess with Progress showToastMessage(R.string.insert_bus_stop_number_error, true); toggleSpinner(false); - } else if (framan.findFragmentById(R.id.resultFrame) instanceof ArrivalsFragment) { - ArrivalsFragment fragment = (ArrivalsFragment) framan.findFragmentById(R.id.resultFrame); - if (fragment != null && fragment.getStopID() != null && fragment.getStopID().equals(ID)){ - // Run with previous fetchers - //fragment.getCurrentFetchers().toArray() - fragment.requestArrivalsForTheFragment(); - } else{ - //SHOW NEW ARRIVALS FRAGMENT - //new AsyncArrivalsSearcher(fragmentHelper, fetchers, getContext()).execute(ID); - fragmentHelper.createOrUpdateStopFragment(new Palina(ID), true); + } else{ + var palinaTrial = new Palina(ID); + if (framan.findFragmentById(R.id.resultFrame) instanceof ArrivalsFragment fragment) { + if (fragment.isFragmentForTheSameStop(palinaTrial)){ + // Run with previous fetchers + //fragment.getCurrentFetchers().toArray() + fragment.requestArrivalsForTheFragment(); + } else{ + // The rest of the case is handled by the fragment Helper + fragmentHelper.showArrivalsFragmentForStop(palinaTrial, true); + } } - } - else { - Log.d(DEBUG_TAG, "This is probably the first arrivals search, preparing GUI"); - //prepareGUIForArrivals(); - //new AsyncArrivalsSearcher(fragmentHelper,fetchers, getContext()).execute(ID); - fragmentHelper.createOrUpdateStopFragment(new Palina(ID), true); + else { + // this is not needed any more + //prepareGUIForArrivals(); + fragmentHelper.showArrivalsFragmentForStop(palinaTrial, true); + } } } @@ -747,13 +762,16 @@ } private void requestLocationPermission(){ + if(shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)){ + makeToast(R.string.enable_position_message_nearby); + } requestPermissionLauncher.launch(LOCATION_PERMISSIONS); } - private void showNearbyFragmentIfPossible() { + private void showNearbyFragmentIfPossible(boolean addToBackStack) { if (isNearbyFragmentShown()) { //nothing to do - Log.w(DEBUG_TAG, "Asked to show nearby fragment but we already are showing it"); + Log.d(DEBUG_TAG, "Asked to show nearby fragment but we already are showing it"); return; } if (getContext() == null) { @@ -764,10 +782,24 @@ if (fragmentHelper.getLastSuccessfullySearchedBusStop() == null && !childFragMan.isDestroyed()) { //Go ahead with the request - - actuallyShowNearbyStopsFragment(); + swipeRefreshLayout.setVisibility(View.VISIBLE); + final Fragment existingFrag = childFragMan.findFragmentById(R.id.resultFrame); + // fragment; + if (!(existingFrag instanceof NearbyStopsFragment)){ + Log.d(DEBUG_TAG, "actually showing Nearby Stops Fragment"); + //there is no fragment showing + final NearbyStopsFragment fragment = NearbyStopsFragment.newInstance(NearbyStopsFragment.FragType.STOPS); + + FragmentTransaction ft = childFragMan.beginTransaction(); + + ft.replace(R.id.resultFrame, fragment, NearbyStopsFragment.FRAGMENT_TAG); + if(addToBackStack) ft.addToBackStack(null); + if (getActivity()!=null && !getActivity().isFinishing()) + ft.commit(); + else Log.e(DEBUG_TAG, "Not showing nearby fragment because activity null or is finishing"); + } pendingNearbyStopsFragmentRequest = false; } } } \ No newline at end of file diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java --- a/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java +++ b/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java @@ -2,11 +2,7 @@ import android.Manifest; import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; import android.content.SharedPreferences; -import android.net.Uri; -import android.provider.Settings; import android.util.Log; import android.view.View; import android.view.inputmethod.InputMethodManager; @@ -15,7 +11,6 @@ import androidx.activity.result.ActivityResultCallback; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; @@ -44,12 +39,18 @@ return getOption(mContext, optionName, optDefault); } - protected void showToastMessage(int messageID, boolean short_lenght) { - final int length = short_lenght ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG; + protected void showToastMessage(int messageID, boolean shortT) { + final int length = shortT ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG; final Context context = getContext(); if(context!=null) Toast.makeText(context, messageID, length).show(); } + protected void makeToast(String message){ + Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show(); + } + protected void makeToast(int messageID){ + Toast.makeText(getContext(), messageID, Toast.LENGTH_SHORT).show(); + } public void hideKeyboard() { if (getActivity()==null) return; diff --git a/app/src/main/java/it/reyboz/bustorino/middleware/StopSearcher.kt b/app/src/main/java/it/reyboz/bustorino/middleware/StopSearcher.kt --- a/app/src/main/java/it/reyboz/bustorino/middleware/StopSearcher.kt +++ b/app/src/main/java/it/reyboz/bustorino/middleware/StopSearcher.kt @@ -1,6 +1,5 @@ package it.reyboz.bustorino.middleware -import android.content.Context import android.util.Log import it.reyboz.bustorino.backend.Fetcher import it.reyboz.bustorino.backend.FiveTStopsFetcher @@ -11,8 +10,6 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.lang.ref.WeakReference diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/FavoritesViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/FavoritesViewModel.kt --- a/app/src/main/java/it/reyboz/bustorino/viewmodels/FavoritesViewModel.kt +++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/FavoritesViewModel.kt @@ -1,21 +1,15 @@ package it.reyboz.bustorino.viewmodels import android.app.Application -import android.util.Log import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MediatorLiveData -import androidx.lifecycle.application import androidx.lifecycle.map import androidx.lifecycle.switchMap -import androidx.lifecycle.viewModelScope import androidx.work.WorkInfo import it.reyboz.bustorino.backend.Stop import it.reyboz.bustorino.backend.StopFavoritesData import it.reyboz.bustorino.data.DBUpdateWorker.Companion.getWorkInfoLiveData -import it.reyboz.bustorino.data.FavoritesLiveData import it.reyboz.bustorino.data.OldDataRepository -import it.reyboz.bustorino.data.QueryLiveData -import kotlinx.coroutines.launch import java.util.concurrent.Executors class FavoritesViewModel(application: Application) : AndroidViewModel(application) { diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/IntroViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/IntroViewModel.kt new file mode 100644 --- /dev/null +++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/IntroViewModel.kt @@ -0,0 +1,11 @@ +package it.reyboz.bustorino.viewmodels + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class IntroViewModel: ViewModel() { + + + var introIsRunning = MutableLiveData(false) + +} \ 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 @@ -3,12 +3,9 @@ import android.app.Application import android.util.Log import androidx.lifecycle.* -import it.reyboz.bustorino.backend.Result import it.reyboz.bustorino.backend.Stop 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.data.gtfs.MatoPatternWithStops import it.reyboz.bustorino.data.gtfs.PatternStop diff --git a/app/src/main/res/drawable-hdpi/ic_star.png b/app/src/main/res/drawable-hdpi/ic_star.png deleted file mode 100644 index 7337fed6ef223388e380ab5eb665da0d3f3abd02..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@^#mtppu=b3qT=9!WD=p(%VazM^! zA30CNPhKBe3D#w51}Z=$tLZZZ99WskObP{3r7WpnrJR{G0t6I*UH)R%>N1l)v;2$M zOpLxg*XsyaPjwmv$S=?s4^#gy02@sNY@|Jfiokvo0sBBP&C6(6QZs_ZlO;8cqdx(B zr8V||i9}~0;!k%~(!~hvE=jr)Q=f8ej`CSa4NpGBU2T?h>5WxXS_axnvG%9IE(%l|sXGPKnNk1ihl(glXtFf9%us7zNx2#r8V`K;9f^To|{QiKWn}q6S+3rX|b;V0v3V1l|`#-hMh#NAML<%*nq?_umw!l`R*F< z&f3(&q0d|FAd#5{1U>uF)EY<0_42(3hzabGL_DvW|NeFmuogG<9 zOtxzS0>*ICVjNk_XFiELdjfn0=DRs?gl1&kViN4jhm~Hn&I)mymO>&5zAXxbX%Ky6OwybMOGh!GVPbAZ{wb zU8m2b#s)4>djGKSB~6pI=X|H9=TBjc6p&PsR7#^GN@+vOj+J?!FR8x@VkA}ckBX$? zp1>Fb&~%oXcCE16?`j%5Azp|AZ{JSXx+&5NqXZ9(iXy+(Y%HCU8yG5FzYk27y)p0000E>F2H^KoTC{j>Q;0>4CEAg5bEMMK#Bwr15TC z0!M(2F~)5KzU!JGxDwUXqEDNdrI8Uj?g4K6ZwZL|HH~yw>h$dUPVbupw;z-=)ahVY zN@7%uG5wOtKn2(XY)+utX5b5;BB?B?KZI^gV?f+>Cutq9+h_M%V9@&u1AhIX@A)_Q zISHNsH9!9gECMfqWxu`-`~loIv!%H4sA&-NHq~C>1E364frG%8Yb5K=0yls;;2H1& zxNT;0aoxNu>7u#^7kx>_OM||a47dcG&Z>150L#E-URlGyA*UowPOM>4=YsgIkgYGT#SCsz_Rhq40#HzD6~CgoHjH+YAdXJ97^hlk~KK zk~RMx*y3(pB1D+qTWj#_r;DEJ_Rf|5oh%{7oQnTJAX^#aL&wjnc2N| zT-4LtJu|BU=l$7He3}Ojh~k2zO6VS4WLZ>P#v9~?fIE_Yhy=z?1>BYEqb^ff8$Tmy zpQQDnXFY~Dte5n4X7xZMvRj4|K-M~t*39QYW`P0)3KZxzyaw8)I0MPWRjL30002ov JPDHLkV1nl#^7;S( diff --git a/app/src/main/res/drawable-xxhdpi/ic_star.png b/app/src/main/res/drawable-xxhdpi/ic_star.png deleted file mode 100644 index bc99ac86917c0ce1c8ba594eea8caafb9db1a380..0000000000000000000000000000000000000000 GIT binary patch literal 0 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 P00000NkvXXu0mjfSA22Y diff --git a/app/src/main/res/drawable/compass_3_fill.xml b/app/src/main/res/drawable/compass_3_fill.xml new file mode 100644 --- /dev/null +++ b/app/src/main/res/drawable/compass_3_fill.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_moving_emph.xml b/app/src/main/res/drawable/ic_moving_emph.xml --- a/app/src/main/res/drawable/ic_moving_emph.xml +++ b/app/src/main/res/drawable/ic_moving_emph.xml @@ -4,6 +4,6 @@ android:viewportWidth="48" android:viewportHeight="48"> diff --git a/app/src/main/res/drawable/ic_star_filled_white.xml b/app/src/main/res/drawable/ic_star_filled_white.xml --- a/app/src/main/res/drawable/ic_star_filled_white.xml +++ b/app/src/main/res/drawable/ic_star_filled_white.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/layout/fragment_buttons.xml b/app/src/main/res/layout/fragment_buttons.xml new file mode 100644 --- /dev/null +++ b/app/src/main/res/layout/fragment_buttons.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + \ 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 @@ -13,7 +13,6 @@ android:layout_width="40dip" android:layout_height="40dip" android:layout_alignBottom="@+id/searchButton" - android:layout_marginLeft="16dp" android:layout_marginStart="16dp" android:background="@drawable/qrcode_button_custom" android:contentDescription="@string/qrcode" @@ -27,8 +26,6 @@ android:layout_marginLeft="5dip" android:layout_marginRight="5dip" android:layout_toEndOf="@+id/QRButton" - android:layout_toLeftOf="@+id/searchButton" - android:layout_toRightOf="@+id/QRButton" android:layout_toStartOf="@+id/searchButton" android:ems="10" android:hint="@string/insert_bus_stop_number" @@ -37,8 +34,6 @@ android:selectAllOnFocus="true" android:singleLine="true" > - - - - - \ No newline at end of file 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 @@ -151,7 +151,8 @@ ListFragment - BusTO it.reyboz.bustorino.preferences db_is_updating - + + Nearby me Nearby stops Nearby connections App version