Refactoring of Search Behavior: Restoring of Previous Search Query After Coming Back from Card Interaction or Screen Rotation on Search

This commit is contained in:
vp193dt
2024-09-30 21:56:57 +02:00
committed by Sylvia van Os
parent 91f5f9a8b4
commit 6f4582eec9
2 changed files with 113 additions and 6 deletions

View File

@@ -54,6 +54,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
public static final String RESTART_ACTIVITY_INTENT = "restart_activity_intent";
private static final int MEDIUM_SCALE_FACTOR_DIP = 460;
static final String STATE_SEARCH_QUERY = "SEARCH_QUERY";
private SQLiteDatabase mDatabase;
private LoyaltyCardCursorAdapter mAdapter;
@@ -61,6 +62,8 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
private SearchView mSearchView;
private int mLoyaltyCardCount = 0;
protected String mFilter = "";
private String currentQuery = "";
private String finalQuery = "";
protected Object mGroup = null;
protected DBHelper.LoyaltyCardOrder mOrder = DBHelper.LoyaltyCardOrder.Alpha;
protected DBHelper.LoyaltyCardOrderDirection mOrderDirection = DBHelper.LoyaltyCardOrderDirection.Ascending;
@@ -70,9 +73,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
private View mNoMatchingCardsText;
private View mNoGroupCardsText;
private TabLayout groupsTabLayout;
private Runnable mUpdateLoyaltyCardListRunnable;
private ActivityResultLauncher<Intent> mBarcodeScannerLauncher;
private ActivityResultLauncher<Intent> mSettingsLauncher;
@@ -199,7 +200,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
protected void onCreate(Bundle inputSavedInstanceState) {
SplashScreen.installSplashScreen(this);
super.onCreate(inputSavedInstanceState);
// We should extract the share intent after we called the super.onCreate as it may need to spawn a dialog window and the app needs to be initialized to not crash
extractIntentFields(getIntent());
@@ -298,7 +298,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
if (mSearchView != null && !mSearchView.isIconified()) {
mFilter = mSearchView.getQuery().toString();
}
// Start of active tab logic
updateTabGroups(groupsTabLayout);
@@ -513,6 +512,24 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
}
@Override
// Saving currentQuery to finalQuery for user, this will be used to restore search history, happens when user clicks a card from list
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
finalQuery = currentQuery;
// Putting the query also into outState for later use in onRestoreInstanceState when rotating screen
if (mSearchView != null) {
outState.putString(STATE_SEARCH_QUERY, finalQuery);
}
}
@Override
// Restoring instance state when rotation of screen happens with the goal to restore search query for user
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
finalQuery = savedInstanceState.getString(STATE_SEARCH_QUERY, "");
}
@Override
public boolean onCreateOptionsMenu(Menu inputMenu) {
getMenuInflater().inflate(R.menu.main_menu, inputMenu);
@@ -525,7 +542,6 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
mSearchView = (SearchView) searchMenuItem.getActionView();
mSearchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
mSearchView.setSubmitButtonEnabled(false);
mSearchView.setOnCloseListener(() -> {
invalidateOptionsMenu();
return false;
@@ -550,6 +566,9 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
mSearchView.clearFocus();
return false;
}
currentQuery = "";
mFilter = "";
updateLoyaltyCardList(false);
return true;
}
});
@@ -564,7 +583,21 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
@Override
public boolean onQueryTextChange(String newText) {
mFilter = newText;
// New logic to ensure search history after coming back from picked card - user will see the last search query
if (newText.isEmpty()) {
if(!finalQuery.isEmpty()){
// Setting the query text for user after coming back from picked card from finalQuery
mSearchView.setQuery(finalQuery, false);
}
else if(!currentQuery.isEmpty()){
// Else if is needed in case user deletes search - expected behaviour is to show all cards
currentQuery = "";
mSearchView.setQuery(currentQuery, false);
}
} else {
// Setting search query each time user changes the text in search to temporary variable to be used later in finalQuery String which will be used to restore search history
currentQuery = newText;
}
TabLayout.Tab currentTab = groupsTabLayout.getTabAt(groupsTabLayout.getSelectedTabPosition());
mGroup = currentTab != null ? currentTab.getTag() : null;
@@ -573,6 +606,14 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard
return true;
}
});
// Check if we came from a picked card back to search, in that case we want to show the search view with previous search query
if(!finalQuery.isEmpty()){
// Expand the search view to show the query
searchMenuItem.expandActionView();
// Setting the query text to empty String due to behaviour of onQueryTextChange after coming back from picked card - onQueryTextChange is called automatically without users interaction
finalQuery = "";
mSearchView.setQuery(currentQuery, false);
}
}
return super.onCreateOptionsMenu(inputMenu);

View File

@@ -3,18 +3,22 @@ package protect.card_locker;
import static android.os.Looper.getMainLooper;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.robolectric.Shadows.shadowOf;
import android.app.Activity;
import android.content.ComponentName;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.widget.SearchView;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.tabs.TabLayout;
@@ -210,9 +214,12 @@ public class MainActivityTest {
@Test
public void testFiltering() {
// FIXME: This test directly sets mFilter instead of using mSearchView, making it not test the search flow correctly
// It may falsely succeed or fail, but we're leaving it here so we at least test something instead of nothing
ActivityController activityController = Robolectric.buildActivity(MainActivity.class).create();
MainActivity mainActivity = (MainActivity) activityController.get();
activityController.start();
activityController.resume();
@@ -244,6 +251,16 @@ public class MainActivityTest {
activityController.pause();
activityController.resume();
Configuration configuration = mainActivity.getResources().getConfiguration();
configuration.orientation = Configuration.ORIENTATION_LANDSCAPE;
mainActivity.onConfigurationChanged(configuration);
configuration.orientation = Configuration.ORIENTATION_PORTRAIT;
mainActivity.onConfigurationChanged(configuration);
configuration.orientation = Configuration.ORIENTATION_LANDSCAPE;
mainActivity.onConfigurationChanged(configuration);
assertEquals(View.GONE, helpSection.getVisibility());
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
assertEquals(View.VISIBLE, list.getVisibility());
@@ -337,6 +354,12 @@ public class MainActivityTest {
mainActivity.mFilter = "second";
configuration.orientation = Configuration.ORIENTATION_LANDSCAPE;
mainActivity.onConfigurationChanged(configuration);
configuration.orientation = Configuration.ORIENTATION_PORTRAIT;
mainActivity.onConfigurationChanged(configuration);
activityController.pause();
activityController.resume();
@@ -371,6 +394,10 @@ public class MainActivityTest {
mainActivity.mFilter = "company";
// Rotate to landscape (right)
configuration.orientation = Configuration.ORIENTATION_LANDSCAPE;
mainActivity.onConfigurationChanged(configuration);
activityController.pause();
activityController.resume();
@@ -443,4 +470,43 @@ public class MainActivityTest {
database.close();
}
@Test
public void testSearchQueryRestorationAfterNavigatingBack() {
ActivityController activityController = Robolectric.buildActivity(MainActivity.class).create();
MainActivity mainActivity = (MainActivity) activityController.get();
activityController.start();
activityController.resume();
final Menu menu = shadowOf(Robolectric.setupActivity(MainActivity.class)).getOptionsMenu();
MenuItem searchMenuItem = menu.findItem(R.id.action_search);
SearchView mSearchView = (SearchView) searchMenuItem.getActionView();
SQLiteDatabase database = TestHelpers.getEmptyDb(mainActivity).getWritableDatabase();
DBHelper.insertLoyaltyCard(database, "The First Store", "Initial note", null, null, new BigDecimal("0"), null, "cardId", null, CatimaBarcode.fromBarcode(BarcodeFormat.UPC_A), Color.BLACK, 0, null,0);
DBHelper.insertLoyaltyCard(database, "The Second Store", "Secondary note", null, null, new BigDecimal("0"), null, "cardId", null, CatimaBarcode.fromBarcode(BarcodeFormat.UPC_A), Color.BLACK, 0, null,0);
String finalQuery = "store";
assert mSearchView != null;
mSearchView.setQuery(finalQuery, false);
activityController.pause();
activityController.resume();
// Simulation of what happens when users comes back after picking up card
// We simulate expanding and setting the Query that we want to restore (in code it is from finalQuery String)
searchMenuItem.expandActionView();
mSearchView.setQuery(finalQuery, false);
activityController.pause();
activityController.resume();
assertTrue(searchMenuItem.isActionViewExpanded());
assertEquals("store", mSearchView.getQuery().toString());
database.close();
}
}