mirror of
https://github.com/ClaytonWWilson/Listify.git
synced 2025-12-15 18:28:47 +00:00
Merge pull request #95 from ClaytonWWilson/revamped-search-filter
Revamped search filter
This commit is contained in:
commit
90a09d9d53
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
package com.example.listify;
|
||||
|
||||
public enum SortModes {
|
||||
NONE,
|
||||
NAME,
|
||||
PRICE,
|
||||
STORE,
|
||||
UPC
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
|
||||
62
Listify/app/src/main/res/layout/dialog_filter.xml
Normal file
62
Listify/app/src/main/res/layout/dialog_filter.xml
Normal 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>
|
||||
@ -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>
|
||||
|
||||
|
||||
|
||||
28
Listify/app/src/main/res/layout/filter_store_item.xml
Normal file
28
Listify/app/src/main/res/layout/filter_store_item.xml
Normal 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>
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
|
||||
14
Listify/app/src/main/res/menu/search.xml
Normal file
14
Listify/app/src/main/res/menu/search.xml
Normal 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>
|
||||
@ -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>
|
||||
Loading…
Reference in New Issue
Block a user