Merge pull request #95 from ClaytonWWilson/revamped-search-filter

Revamped search filter
This commit is contained in:
Clayton Wilson 2020-11-02 00:56:42 -05:00 committed by GitHub
commit 90a09d9d53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 579 additions and 250 deletions

View File

@ -0,0 +1,113 @@
package com.example.listify;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import com.crystal.crystalrangeseekbar.interfaces.OnRangeSeekbarChangeListener;
import com.crystal.crystalrangeseekbar.widgets.CrystalRangeSeekbar;
import com.example.listify.adapter.CheckBoxListViewAdapter;
import java.util.ArrayList;
public class FilterDialogFragment extends DialogFragment {
public interface OnFilterListener {
void sendFilter(ArrayList<String> selectedStores, double minPrice, double maxPrice);
}
public OnFilterListener onFilterListener;
CrystalRangeSeekbar priceSeekbar;
CheckBoxListViewAdapter checkBoxAdapter;
private ArrayList<String> selectedStores;
private ArrayList<String> stores;
private double maxProductPrice; // The highest price on the slider
private double minPrice; // The selected min price
private double maxPrice; // The selected max price
public FilterDialogFragment(ArrayList<String> selectedStores, ArrayList<String> stores, double maxProductPrice, double minPrice, double maxPrice) {
this.selectedStores = selectedStores;
this.stores = stores;
this.maxProductPrice = maxProductPrice;
this.minPrice = minPrice;
this.maxPrice = maxPrice;
}
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
// Get the layout inflater
LayoutInflater inflater = requireActivity().getLayoutInflater();
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
View root = inflater.inflate(R.layout.dialog_filter, null);
builder.setView(root)
// Add action buttons
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
selectedStores = checkBoxAdapter.getChecked();
onFilterListener.sendFilter(selectedStores, priceSeekbar.getSelectedMinValue().doubleValue(), priceSeekbar.getSelectedMaxValue().doubleValue());
}
})
.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
FilterDialogFragment.this.getDialog().cancel();
}
});
ListView storesList = root.findViewById(R.id.store_name_list);
// Create arraylist of stores from search results
ArrayList<String> storeChoices = new ArrayList<>(stores);
// Create adapter and send stores and selected stores
checkBoxAdapter = new CheckBoxListViewAdapter(getActivity(), storeChoices, this.selectedStores);
storesList.setAdapter(checkBoxAdapter);
// Set up the seekbar for price
priceSeekbar = (CrystalRangeSeekbar) root.findViewById(R.id.price_range_seekbar);
final TextView tvMin = (TextView) root.findViewById(R.id.tv_min_price);
final TextView tvMax = (TextView) root.findViewById(R.id.tv_max_price);
priceSeekbar.setMaxValue((float) this.maxProductPrice);
priceSeekbar.setMinStartValue((float) this.minPrice);
priceSeekbar.setMaxStartValue((float) this.maxPrice);
priceSeekbar.apply();
// Update price display
priceSeekbar.setOnRangeSeekbarChangeListener(new OnRangeSeekbarChangeListener() {
@Override
public void valueChanged(Number minValue, Number maxValue) {
tvMin.setText(String.format("$%.2f", minValue.doubleValue()));
tvMax.setText(String.format("$%.2f", maxValue.doubleValue()));
}
});
return builder.create();
}
// Required to extend DialogFragment
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
try {
onFilterListener = (OnFilterListener) getActivity();
} catch (ClassCastException e) {
Log.e("FilterDialogFragment", "onAttach: ClassCastException: " + e.getMessage());
}
}
}

View File

@ -225,6 +225,7 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver {
ArrayList<String> pQuantity;
ArrayList<String> pImages;
MyAdapter (Context c, ArrayList<String> names, ArrayList<String> stores, ArrayList<String> prices, ArrayList<String> quantity, ArrayList<String> images) {
super(c, R.layout.activity_listproductentry, R.id.productView, names);
context = c;

View File

@ -190,18 +190,6 @@ public class MainActivity extends AppCompatActivity implements CreateListDialogF
return NavigationUI.navigateUp(navController, mAppBarConfiguration) || super.onSupportNavigateUp();
}
// This function only exists for the create new list option in hamburger menu
public void onClickCreateList(MenuItem m) {
m.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
CreateListDialogFragment createListDialogFragment = new CreateListDialogFragment();
createListDialogFragment.show(getSupportFragmentManager(), "Create New List");
return false;
}
});
}
public void onClickSignout(MenuItem m) {
m.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override

View File

@ -3,6 +3,8 @@ import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
@ -23,28 +25,35 @@ import java.util.Properties;
import static com.example.listify.MainActivity.am;
public class SearchResults extends AppCompatActivity implements SortDialogFragment.OnSortingListener, Requestor.Receiver {
public class SearchResults extends AppCompatActivity implements FilterDialogFragment.OnFilterListener, SortDialogFragment.OnSortListener, Requestor.Receiver {
private ListView listView;
private MenuItem filterItem;
private ProgressBar loadingSearch;
private SearchResultsListAdapter searchResultsListAdapter;
private List<Product> resultsProductList = new ArrayList<>();
private List<Product> resultsProductListSorted = new ArrayList<>();
private ArrayList<String> stores = new ArrayList<>();
private int storeSelection;
private int sortMode;
private ArrayList<String> selectedStores = new ArrayList<>();
private SortModes sortMode = SortModes.NONE;
private boolean descending;
private double minPrice = 0;
private double maxPrice = -1;
@Override
public void sendSort(int storeSelection, int sortMode, boolean descending, double minPrice, double maxPrice) {
this.storeSelection = storeSelection;
this.sortMode = sortMode;
this.descending = descending;
public void sendFilter(ArrayList<String> selectedStores, double minPrice, double maxPrice) {
this.selectedStores = selectedStores;
this.minPrice = minPrice;
this.maxPrice = maxPrice;
sortResults();
}
@Override
public void sendSort(SortModes sortMode, boolean descending) {
this.sortMode = sortMode;
this.descending = descending;
sortResults();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -120,22 +129,27 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme
return false;
}
});
}
// TODO: Change this to a menu in which sort and filter are two different options
// TODO: Sort should be disabled until a search is made
// Create a dialog for filtering and sorting search results
ImageButton sortButton = (ImageButton) findViewById(R.id.results_sort_button);
sortButton.setOnClickListener(new View.OnClickListener() {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
//Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.search, menu);
MenuItem sortItem = menu.findItem(R.id.action_sort);
sortItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public void onClick(View v) {
// Sort the store list
stores.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
public boolean onMenuItemClick(MenuItem item) {
SortDialogFragment sortDialog = new SortDialogFragment(sortMode, descending);
sortDialog.show(getSupportFragmentManager(), "Sort Dialog");
return false;
}
});
// TODO: Reset upper and lower limits on price filter when a new search is made
filterItem = menu.findItem(R.id.action_filter);
filterItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
// Determine the max price for the price slider
double maxProductPrice;
if (resultsProductList.isEmpty()) {
@ -159,10 +173,18 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme
// Round up to nearest whole number for display on price seekbar
maxProductPrice = Math.ceil(maxProductPrice);
SortDialogFragment sortDialog = new SortDialogFragment(storeSelection, stores, sortMode, descending, maxProductPrice, minPrice, maxPrice);
sortDialog.show(getSupportFragmentManager(), "Sort");
FilterDialogFragment sortDialog = new FilterDialogFragment(selectedStores, stores, maxProductPrice, minPrice, maxPrice);
sortDialog.show(getSupportFragmentManager(), "Filter Dialog");
return false;
}
});
// Disable filtering by default until a search is made
if (resultsProductList.isEmpty()) {
filterItem.setEnabled(false);
}
return true;
}
// Override default phone back button to add animation
@ -200,10 +222,11 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme
// Sort based on mode
switch (this.sortMode) {
case 0:
case NONE:
// Do nothing
break;
case 1:
case NAME:
resultsProductListSorted.sort(new Comparator<Product>() {
@Override
public int compare(Product a, Product b) {
@ -211,8 +234,8 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme
}
});
break;
case 2:
case PRICE:
resultsProductListSorted.sort(new Comparator<Product>() {
@Override
public int compare(Product a, Product b) {
@ -227,7 +250,7 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme
});
break;
case 3:
case STORE:
resultsProductListSorted.sort(new Comparator<Product>() {
@Override
public int compare(Product a, Product b) {
@ -236,7 +259,7 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme
});
break;
case 4:
case UPC:
resultsProductListSorted.sort(new Comparator<Product>() {
@Override
public int compare(Product a, Product b) {
@ -247,7 +270,7 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme
}
// Flip the list if descending is selected
if (this.sortMode != 0 & this.descending) {
if (this.descending) {
for (int i = 0; i < resultsProductListSorted.size() / 2; i++) {
Product temp = resultsProductListSorted.get(i);
resultsProductListSorted.set(i, resultsProductListSorted.get(resultsProductListSorted.size() - i - 1));
@ -256,10 +279,10 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme
}
// Only keep results that match the current store selection
if (this.storeSelection != 0) {
if (!this.selectedStores.equals(this.stores)) {
ArrayList<Product> temp = new ArrayList<>();
resultsProductListSorted.forEach(product -> {
if (product.getChainName().equals(this.stores.get(this.storeSelection - 1))) {
if (this.selectedStores.contains(product.getChainName())) {
temp.add(product);
}
});
@ -317,8 +340,24 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme
}
}
// Reset selected stores on search so that every store is selected
this.selectedStores.clear();
this.selectedStores.addAll(stores);
// Add all results to the sorted list
resultsProductListSorted.addAll(resultsProductList);
// Filtering should only be allowed if there are items in the results
runOnUiThread(new Runnable() {
@Override
public void run() {
if (resultsProductList.isEmpty()) {
filterItem.setEnabled(false);
} else {
filterItem.setEnabled(true);
}
}
});
// Apply selected sorting to the list
sortResults();

View File

@ -1,56 +1,41 @@
package com.example.listify;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.Spinner;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.SwitchCompat;
import androidx.fragment.app.DialogFragment;
import com.crystal.crystalrangeseekbar.interfaces.OnRangeSeekbarChangeListener;
import com.crystal.crystalrangeseekbar.widgets.CrystalRangeSeekbar;
import java.util.ArrayList;
public class SortDialogFragment extends DialogFragment {
public interface OnSortingListener {
void sendSort(int storeSelection, int sortMode, boolean descending, double minPrice, double maxPrice);
public interface OnSortListener {
void sendSort(SortModes sortMode, boolean descending);
}
public OnSortingListener onSortingListener;
public OnSortListener onSortListener;
CrystalRangeSeekbar priceSeekbar;
private int storeSelection;
private int sortMode;
private SortModes sortMode;
private boolean descending;
private ArrayList<String> stores;
private double maxProductPrice; // The highest price on the slider
private double minPrice; // The selected min price
private double maxPrice; // The selected max price
public SortDialogFragment(int storeSelection, ArrayList<String> stores, int sortMode, boolean descending, double maxProductPrice, double minPrice, double maxPrice) {
this.storeSelection = storeSelection;
this.stores = stores;
TextView tvSortNone;
TextView tvSortName;
TextView tvSortPrice;
TextView tvSortStore;
SwitchCompat swDescending;
public SortDialogFragment(SortModes sortMode, boolean descending) {
this.sortMode = sortMode;
this.descending = descending;
this.maxProductPrice = maxProductPrice;
this.minPrice = minPrice;
this.maxPrice = maxPrice;
}
// TODO: Sorting should scroll the user back to the top of the page
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
@ -60,122 +45,105 @@ public class SortDialogFragment extends DialogFragment {
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
View root = inflater.inflate(R.layout.dialog_sort, null);
builder.setView(root)
// Add action buttons
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
onSortingListener.sendSort(storeSelection, sortMode, descending, priceSeekbar.getSelectedMinValue().doubleValue(), priceSeekbar.getSelectedMaxValue().doubleValue());
}
})
.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
SortDialogFragment.this.getDialog().cancel();
}
});
builder.setView(root);
Spinner storeDropdown = (Spinner) root.findViewById(R.id.sort_store_dropdown);
String[] storeChoices = new String[stores.size() + 1];
storeChoices[0] = "All";
for (int i = 1; i < stores.size() + 1; i++) {
storeChoices[i] = stores.get(i - 1);
tvSortNone = (TextView) root.findViewById(R.id.sort_none);
tvSortName = (TextView) root.findViewById(R.id.sort_name);
tvSortPrice = (TextView) root.findViewById(R.id.sort_price);
tvSortStore = (TextView) root.findViewById(R.id.sort_store);
LinearLayout llDescendingContainer = (LinearLayout) root.findViewById(R.id.descending_container);
swDescending = (SwitchCompat) root.findViewById(R.id.switch_descending);
switch (this.sortMode) {
case NONE:
tvSortNone.setBackgroundColor(getResources().getColor(R.color.colorAccent));
break;
case NAME:
tvSortName.setBackgroundColor(getResources().getColor(R.color.colorAccent));
break;
case PRICE:
tvSortPrice.setBackgroundColor(getResources().getColor(R.color.colorAccent));
break;
case STORE:
tvSortStore.setBackgroundColor(getResources().getColor(R.color.colorAccent));
break;
}
// Create the store selection dropdown
ArrayAdapter<String> storeAdapter = new ArrayAdapter<>(root.getContext(), android.R.layout.simple_spinner_dropdown_item, storeChoices);
storeDropdown.setAdapter(storeAdapter);
storeDropdown.setSelection(this.storeSelection);
storeDropdown.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
storeSelection = position;
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
// Change the sort arrow to be pointing up or down based on ascending or descending
final ImageButton sortDirectionButton = root.findViewById(R.id.sort_direction_button);
if (descending) {
sortDirectionButton.setImageResource(R.drawable.ic_baseline_arrow_downward_50);
} else {
sortDirectionButton.setImageResource(R.drawable.ic_baseline_arrow_upward_50);
if (this.descending) {
swDescending.setChecked(true);
}
// Change arrow pointing direction whenever the user clicks the button
sortDirectionButton.setOnClickListener(new View.OnClickListener() {
tvSortNone.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (descending) {
descending = false;
sortDirectionButton.setImageResource(R.drawable.ic_baseline_arrow_upward_50);
} else {
descending = true;
sortDirectionButton.setImageResource(R.drawable.ic_baseline_arrow_downward_50);
}
handleClicked(tvSortNone, SortModes.NONE, swDescending.isChecked());
}
});
// Create the sort mode selection dropdown
Spinner sortDropdown = (Spinner) root.findViewById(R.id.sort_mode_dropdown);
String[] items = new String[] {"<Default>", "Name", "Price", "Store"};
ArrayAdapter<String> adapter = new ArrayAdapter<>(root.getContext(), android.R.layout.simple_spinner_dropdown_item, items);
sortDropdown.setAdapter(adapter);
sortDropdown.setSelection(this.sortMode);
sortDropdown.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
tvSortName.setOnClickListener(new View.OnClickListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
sortMode = position;
// Update the sort direction button
if (position == 0) {
sortDirectionButton.setEnabled(false);
} else {
sortDirectionButton.setEnabled(true);
}
public void onClick(View v) {
handleClicked(tvSortName, SortModes.NAME, swDescending.isChecked());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {}
});
// Disable the direction button if they have the default sorting mode selected
// Ascending and Descending are mostly irrelevant in the default sort mode
if (sortDropdown.getSelectedItemPosition() == 0) {
sortDirectionButton.setEnabled(false);
}
// Set up the seekbar for price
priceSeekbar = (CrystalRangeSeekbar) root.findViewById(R.id.price_range_seekbar);
final TextView tvMin = (TextView) root.findViewById(R.id.tv_min_price);
final TextView tvMax = (TextView) root.findViewById(R.id.tv_max_price);
priceSeekbar.setMaxValue((float) this.maxProductPrice);
priceSeekbar.setMinStartValue((float) this.minPrice);
priceSeekbar.setMaxStartValue((float) this.maxPrice);
priceSeekbar.apply();
// Update price display
priceSeekbar.setOnRangeSeekbarChangeListener(new OnRangeSeekbarChangeListener() {
tvSortPrice.setOnClickListener(new View.OnClickListener() {
@Override
public void valueChanged(Number minValue, Number maxValue) {
tvMin.setText(String.format("$%.2f", minValue.doubleValue()));
tvMax.setText(String.format("$%.2f", maxValue.doubleValue()));
public void onClick(View v) {
handleClicked(tvSortPrice, SortModes.PRICE, swDescending.isChecked());
}
});
tvSortStore.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handleClicked(tvSortStore, SortModes.STORE, swDescending.isChecked());
}
});
// TODO: set onclick listener for descending switch
llDescendingContainer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("linear");
swDescending.performClick();
// handleClicked(sortMode, swDescending.isChecked());
}
});
swDescending.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("switch");
descending = swDescending.isChecked();
onSortListener.sendSort(sortMode, swDescending.isChecked());
}
});
return builder.create();
}
void handleClicked(TextView tvSelected, SortModes sortMode, boolean descending) {
this.sortMode = sortMode;
this.descending = descending;
tvSortNone.setBackgroundColor(getResources().getColor(R.color.white));
tvSortName.setBackgroundColor(getResources().getColor(R.color.white));
tvSortPrice.setBackgroundColor(getResources().getColor(R.color.white));
tvSortStore.setBackgroundColor(getResources().getColor(R.color.white));
tvSelected.setBackgroundColor(getResources().getColor(R.color.colorAccent));
onSortListener.sendSort(sortMode, descending);
// SortDialogFragment.this.getDialog().cancel();
}
// Required to extend DialogFragment
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
try {
onSortingListener = (OnSortingListener) getActivity();
onSortListener = (OnSortListener) getActivity();
} catch (ClassCastException e) {
Log.e("SortDialogFragment", "onAttach: ClassCastException: " + e.getMessage());
}

View File

@ -0,0 +1,9 @@
package com.example.listify;
public enum SortModes {
NONE,
NAME,
PRICE,
STORE,
UPC
}

View File

@ -0,0 +1,94 @@
package com.example.listify.adapter;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import com.example.listify.R;
import java.util.ArrayList;
public class CheckBoxListViewAdapter extends BaseAdapter {
private Activity activity;
ArrayList<String> list = new ArrayList<>();
ArrayList<String> checkedList = new ArrayList<>();
public CheckBoxListViewAdapter(Activity activity, ArrayList<String> list, ArrayList<String> checkedList) {
super();
this.activity = activity;
this.list = list;
this.checkedList = checkedList;
}
@Override
public int getCount() {
return list.size();
}
@Override
public String getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public class ViewHolder {
public TextView label;
public CheckBox checkBox;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
LayoutInflater inflator = ((Activity) activity).getLayoutInflater();
if (convertView == null) {
convertView = inflator.inflate(R.layout.filter_store_item, null);
convertView.setSoundEffectsEnabled(false);
holder = new ViewHolder();
holder.label = (TextView) convertView.findViewById(R.id.store_name);
holder.checkBox = (CheckBox)convertView.findViewById(R.id.store_check_box);
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int getPosition = (Integer) buttonView.getTag();
if (isChecked) {
checkedList.add(list.get(getPosition));
} else {
checkedList.remove(list.get(getPosition));
}
}
});
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("clicked");
holder.checkBox.performClick();
}
});
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.checkBox.setTag(position);
holder.label.setText("" + list.get(position));
holder.checkBox.setChecked(checkedList.contains(list.get(position)));
return convertView;
}
public ArrayList<String> getChecked() {
return this.checkedList;
}
}

View File

@ -23,10 +23,12 @@
android:id="@+id/backToHomeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:translationX="-10dp"
android:padding="10dp"
app:srcCompat="@drawable/abc_vector_test"
android:background="@null"
android:contentDescription="@string/backButton"/>
android:contentDescription="@string/backButton"
android:foreground="?android:attr/selectableItemBackgroundBorderless"/>
<SearchView
android:id="@+id/searchBar"
@ -36,14 +38,6 @@
>
</SearchView>
<ImageButton
android:id="@+id/results_sort_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/sort_button_desc"
android:background="@null"
app:srcCompat="@drawable/ic_baseline_sort_28" />
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>

View File

@ -19,13 +19,15 @@
app:popupTheme="@style/AppTheme.PopupOverlay" >
<ImageButton
android:id="@+id/searchButton"
android:layout_width="30dp"
android:layout_width="wrap_content"
android:layout_gravity="end"
android:layout_marginEnd="5dp"
android:layout_height="wrap_content"
android:padding="10dp"
app:srcCompat="@drawable/ic_baseline_search_28"
android:contentDescription="@string/search_button_desc"
android:background="@null"/>
android:background="@null"
android:foreground="?android:attr/selectableItemBackgroundBorderless"/>
</androidx.appcompat.widget.Toolbar>

View File

@ -0,0 +1,62 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_store_selection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_marginStart="15dp"
android:text="@string/store_selection"
android:textSize="20sp"/>
<ListView
android:id="@+id/store_name_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="10dp"/>
<TextView
android:id="@+id/tv_price_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginStart="15dp"
android:text="Price"
android:textSize="20sp"/>
<com.crystal.crystalrangeseekbar.widgets.CrystalRangeSeekbar
android:id="@+id/price_range_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_min_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="20dp"
android:layout_marginStart="15dp"
android:text="$00.00" />
<TextView
android:id="@+id/tv_max_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="20dp"
android:layout_marginEnd="15dp"
android:gravity="end"
android:text="$00.00" />
</LinearLayout>
</LinearLayout>

View File

@ -1,93 +1,104 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="30dp">
<!-- I would've use a ListView here, but it doesn't offer enough customization -->
<TextView
android:id="@+id/sort_none"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="None"
android:textSize="16sp"
android:textColor="@android:color/black"
android:paddingStart="16dp"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackgroundBorderless" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/list_divider" />
<TextView
android:id="@+id/tv_store_selection"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="15dp"
android:layout_marginStart="15dp"
android:text="@string/store_selection" />
android:id="@+id/sort_name"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Name"
android:textSize="16sp"
android:textColor="@android:color/black"
android:paddingStart="16dp"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackgroundBorderless"/>
<Spinner
android:id="@+id/sort_store_dropdown"
android:layout_width="265dp"
android:layout_marginStart="15dp"
android:layout_height="wrap_content"
android:background="@android:drawable/spinner_dropdown_background"
android:spinnerMode="dropdown"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/list_divider" />
<TextView
android:id="@+id/tv_sort_by"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="20dp"
android:layout_marginStart="15dp"
android:text="Sort by" />
android:id="@+id/sort_price"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Price"
android:textSize="16sp"
android:textColor="@android:color/black"
android:paddingStart="16dp"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackgroundBorderless"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/list_divider" />
<TextView
android:id="@+id/sort_store"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Store"
android:textSize="16sp"
android:textColor="@android:color/black"
android:paddingStart="16dp"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackgroundBorderless"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/list_divider" />
<LinearLayout
android:id="@+id/descending_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="15dp">
<Spinner
android:id="@+id/sort_mode_dropdown"
android:layout_width="265dp"
android:layout_height="wrap_content"
android:background="@android:drawable/spinner_dropdown_background"
android:spinnerMode="dropdown"/>
<ImageButton
android:id="@+id/sort_direction_button"
android:layout_marginTop="-6dp"
android:layout_width="57dp"
android:layout_height="70dp"
android:background="@null"
android:src="@drawable/ic_baseline_arrow_upward_50"/>
</LinearLayout>
<TextView
android:id="@+id/tv_price_label"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="20dp"
android:layout_marginStart="15dp"
android:text="Price" />
<com.crystal.crystalrangeseekbar.widgets.CrystalRangeSeekbar
android:id="@+id/price_range_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="50dp"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackgroundBorderless"
android:soundEffectsEnabled="false">
<TextView
android:id="@+id/tv_min_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="20dp"
android:layout_marginStart="15dp"
android:text="$00.00" />
<TextView
android:id="@+id/tv_max_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="20dp"
android:layout_marginEnd="15dp"
android:gravity="end"
android:text="$00.00" />
android:text="Descending"
android:textSize="16sp"
android:textColor="@android:color/black"
android:paddingStart="16dp"/>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/switch_descending"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/store_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:textSize="16sp"
android:layout_marginStart="25dp"/>
<CheckBox
android:id="@+id/store_check_box"
android:checked="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:focusable="false"
android:gravity="end"
android:layout_marginEnd="20dp"
android:layout_marginBottom="-5dp"
android:layout_alignParentEnd="true" />
</RelativeLayout>

View File

@ -5,7 +5,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:dragEdge="right"
app:dragEdge="left"
app:mode="same_level">
<FrameLayout

View File

@ -20,6 +20,11 @@
android:id="@+id/nav_lists"
android:icon="@drawable/ic_baseline_list_alt_28"
android:title="@string/menu_lists" />
<!-- <item-->
<!-- android:id="@+id/nav_create_list"-->
<!-- android:icon="@drawable/ic_baseline_add_28"-->
<!-- android:title="Create New List"-->
<!-- android:onClick="onClickCreateList" />-->
<item
android:id="@+id/nav_logout"
android:title="Sign out"

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_sort"
android:orderInCategory="101"
android:title="Sort"
app:showAsAction="never" />
<item
android:id="@+id/action_filter"
android:orderInCategory="101"
android:title="Filter"
app:showAsAction="never" />
</menu>

View File

@ -11,4 +11,5 @@
<color name="list_row_hover_start_color">#ebeef0</color>
<color name="list_row_hover_end_color">#1c9ef4</color>
<color name="light_gray">#e6e6e6</color>
<color name="white">#ffffffff</color>
</resources>