Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fb search by keywords #160

Merged
merged 7 commits into from Nov 18, 2018
Expand Up @@ -11,13 +11,17 @@
import org.junit.Test;
import org.junit.runner.RunWith;

import static android.support.test.espresso.Espresso.closeSoftKeyboard;
import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.clearText;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.scrollTo;
import static android.support.test.espresso.action.ViewActions.typeText;
import static android.support.test.espresso.matcher.ViewMatchers.withId;


import static ch.epfl.swissteam.services.TestUtils.sleep;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.instanceOf;
Expand All @@ -33,6 +37,9 @@ public class ServicesFragmentTest {
@Before
public void initialize() {
LocationManager.get().setMock();
User testUser = TestUtils.getTestUser();
testUser.addToDB(DBUtility.get().getDb_());
GoogleSignInSingleton.putUniqueID(TestUtils.M_GOOGLE_ID);
}

@After
Expand All @@ -45,6 +52,24 @@ public void openFragment() {
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.button_maindrawer_services));
onView(withId(R.id.services_spinner)).perform(scrollTo()).perform(click());
//onData(allOf(is(instanceOf(Categories.class)), is(Categories.HOUSE))).perform(scrollTo()).perform(click());
}

@Test
public void clickSearchWithoutKeyWords(){
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.button_maindrawer_services));
sleep(1000);
onView(withId(R.id.button_services_search)).perform(click());
}

@Test
public void clickSearchWithKeywords(){
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.button_maindrawer_services));
sleep(1000);
onView(withId(R.id.edittext_services_keywordsinput)).perform(clearText()).perform(typeText("Python"));
closeSoftKeyboard();
sleep(1000);
onView(withId(R.id.button_services_search)).perform(click());
}
}
Expand Up @@ -24,6 +24,7 @@ public class UserTest extends FirebaseTest {
public static ArrayList<Categories> categories = new ArrayList<>();
public static ArrayList<ChatRelation> chatRelations = new ArrayList<>();
public static HashMap<String, ArrayList<String>> keyWords = new HashMap<>();
public static HashMap<String, ArrayList<String>> lowerCaseKeyWords = new HashMap<>();

@Before
public void setCats() {
Expand All @@ -34,6 +35,7 @@ public void setCats() {
public void setKeyWords(){
ArrayList<String> cookingKeyWords = new ArrayList<>(Arrays.asList("Cake", "IceCream"));
keyWords.put(Categories.COOKING.toString(), cookingKeyWords);
lowerCaseKeyWords.put(Categories.COOKING.toString(), new ArrayList<>(Arrays.asList("cake", "icecream")));
}


Expand All @@ -45,7 +47,7 @@ public void testUserWorks() {
assertEquals(name, user.getName_());
assertEquals(description, user.getDescription_());
assertEquals(categories, user.getCategories_());
assertEquals(keyWords, user.getKeyWords_());
assertEquals(lowerCaseKeyWords, user.getKeyWords_());
assertEquals(imageUrl, user.getImageUrl_());
assertEquals(rating, user.getRating_());
assertEquals(true, user.equals(user));
Expand Down Expand Up @@ -164,7 +166,7 @@ public void removeChatRelationWorksWithRelations() {
public void getKeyWordsForParticularCat(){
User user = new User(googleID, name,email, description, categories, keyWords, null,
imageUrl,rating, 0, 0,null,null);
assertEquals(user.getKeyWords(Categories.COOKING), keyWords.get(Categories.COOKING.toString()));
assertEquals(user.getKeyWords(Categories.COOKING), lowerCaseKeyWords.get(Categories.COOKING.toString()));
assertEquals(user.getKeyWords(Categories.DAILYLIFE), new ArrayList<>());
}

Expand Down
31 changes: 21 additions & 10 deletions app/src/main/java/ch/epfl/swissteam/services/CategoriesAdapter.java
Expand Up @@ -40,8 +40,8 @@ public CategoriesViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int
@Override
public void onBindViewHolder(@NonNull CategoriesViewHolder categoriesViewHolder, int i) {
categoriesViewHolder.nameView_.setText(capabilities_[i].toString());
addAddListener(categoriesViewHolder.checkBox_, capabilities_[i]);
addKeyWordsListener(categoriesViewHolder.keywordsInput_, capabilities_[i]);
addAddListener(categoriesViewHolder.checkBox_, capabilities_[i], categoriesViewHolder);
addKeyWordsListener(categoriesViewHolder.keywordsInput_, capabilities_[i], categoriesViewHolder);

}

Expand All @@ -50,7 +50,8 @@ public int getItemCount() {
return capabilities_.length;
}

private void addKeyWordsListener(EditText edittext, Categories capability){
private void addKeyWordsListener(EditText edittext, Categories capability, CategoriesViewHolder holder){
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Identical blocks of code found in 2 locations. Consider refactoring.


edittext.addTextChangedListener(new TextWatcher() {

@Override
Expand All @@ -66,24 +67,34 @@ public void beforeTextChanged(CharSequence s, int start, int count,

@Override
public void afterTextChanged(Editable s) {

((NewProfileCapabilities) edittext.getContext()).addKeyWords(capability, s.toString());
if (!holder.checkBox_.isChecked()){
holder.checkBox_.setChecked(true);
}
}
});
}

private void addAddListener(View view, Categories capability) {
view.setOnClickListener(v -> {
private void addAddListener(CheckBox view, Categories capability, CategoriesViewHolder holder) {
view.setOnCheckedChangeListener((v, isChecked) -> {
((NewProfileCapabilities) v.getContext()).addCapability(capability);
addRemoveListener(view, capability);
if(!isChecked) {
holder.keywordsInput_.setText("");
view.setChecked(false);
}
addRemoveListener(view, capability, holder);
});
}

private void addRemoveListener(View view, Categories capability) {
view.setOnClickListener(v -> {
private void addRemoveListener(CheckBox view, Categories capability, CategoriesViewHolder holder) {
view.setOnCheckedChangeListener((v, isChecked) -> {
((NewProfileCapabilities) v.getContext()).removeCapability(capability);
((NewProfileCapabilities) v.getContext()).removeKeyWords(capability);
addAddListener(view, capability);
if(!isChecked) {
holder.keywordsInput_.setText("");
view.setChecked(false);
}
addAddListener(view, capability, holder);
});
}

Expand Down
Expand Up @@ -52,24 +52,31 @@ public CategoriesViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int
public void onBindViewHolder(@NonNull CategoriesViewHolder categoriesViewHolder, int i) {
categoriesViewHolder.nameView_.setText(capabilities_[i].toString());
categoriesViewHolder.checkBox_.setChecked(userCapabilities_.contains(capabilities_[i]));
categoriesViewHolder.checkBox_.setOnClickListener(v -> {
categoriesViewHolder.checkBox_.setOnCheckedChangeListener((v, isChecked) -> {
((ProfileSettings) v.getContext()).updateUserCapabilities(capabilities_[i], ((CheckBox) v).isChecked());
if(!isChecked){
categoriesViewHolder.keyWords_.setText("");
v.setChecked(false);
}
});

StringBuilder builder = new StringBuilder();
if(keyWords_.get(capabilities_[i].toString()) != null) {
for (String kw : keyWords_.get(capabilities_[i].toString())) {
builder.append(kw).append(";");
if(!kw.equals("")) {
builder.append(kw).append(";");
}
}
if (builder.length() > 2) {
builder.delete(builder.length() - 1, builder.length());
}
categoriesViewHolder.keyWords_.setText(builder.toString());
}
addKeyWordsListener(categoriesViewHolder.keyWords_, capabilities_[i]);
addKeyWordsListener(categoriesViewHolder.keyWords_, capabilities_[i], categoriesViewHolder);

}

private void addKeyWordsListener(EditText edittext, Categories capability){
private void addKeyWordsListener(EditText edittext, Categories capability, CategoriesViewHolder holder){
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Identical blocks of code found in 2 locations. Consider refactoring.

edittext.addTextChangedListener(new TextWatcher() {

@Override
Expand All @@ -87,6 +94,9 @@ public void beforeTextChanged(CharSequence s, int start, int count,
public void afterTextChanged(Editable s) {

((ProfileSettings) edittext.getContext()).addKeyWords(capability, s.toString());
if (!holder.checkBox_.isChecked()){
holder.checkBox_.setChecked(true);
}
}
});
}
Expand Down
88 changes: 81 additions & 7 deletions app/src/main/java/ch/epfl/swissteam/services/ServicesFragment.java
Expand Up @@ -7,15 +7,20 @@
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

/**
Expand All @@ -28,6 +33,8 @@ public class ServicesFragment extends Fragment {
private RecyclerView.Adapter mAdapter_;
private ArrayList<User> users = new ArrayList<>();
private Location currentUserLocation_;
private ArrayList<String> keywords_;
private Categories currentCategory_;


public ServicesFragment() {
Expand Down Expand Up @@ -57,6 +64,8 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Toolbar toolbar = getActivity().findViewById(R.id.toolbar);
toolbar.setTitle(R.string.toolbar_services);

keywords_ = new ArrayList<>();

RecyclerView mRecyclerView = view.findViewById(R.id.services_recycler);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mAdapter_ = new UserAdapter(users, getContext());
Expand All @@ -71,7 +80,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
filterSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
initDataSet((Categories) adapterView.getItemAtPosition(i));
currentCategory_ = (Categories) adapterView.getItemAtPosition(i);
}

@Override
Expand All @@ -80,19 +89,53 @@ public void onNothingSelected(AdapterView<?> adapterView) {
}
});

EditText keywordsInput = (EditText) view.findViewById(R.id.edittext_services_keywordsinput);
keywordsInput.addTextChangedListener(new TextWatcher() {

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {

}

@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {

}

@Override
public void afterTextChanged(Editable s) {

String inKeywords = s.toString();
Log.i("KEYWORDS_LENGTH", "length = " + s.length());
keywords_ = new ArrayList<>(Arrays.asList(inKeywords.split(" ")));
Log.i("LIST_LENGTH", "list length = " + keywords_.size());
keywords_.remove("");
Log.i("LIST_LENGTH", "list length = " + keywords_.size());
}
});

Button searchButton = (Button) view.findViewById(R.id.button_services_search);
searchButton.setOnClickListener(v ->{
Log.i("KEYWORDS", "list of keywords is empty ? " + keywords_.isEmpty());
initDataSet(currentCategory_, keywords_);
});


return view;
}

private void initDataSet(Categories category) {
private void initDataSet(Categories category, ArrayList<String> keywords) {
View view = getView();
if (category == Categories.ALL) {
DBUtility.get().getAllUsers((usersdb -> {
users.clear();
for (User u : usersdb) {
if(! u.getGoogleId_().equals(GoogleSignInSingleton.get().getClientUniqueID())){
//don't add current user to the list
users.add(u);
if (userContainsKeywords(u, keywords, category)) {
if (!u.getGoogleId_().equals(GoogleSignInSingleton.get().getClientUniqueID())) {
//don't add current user to the list
users.add(u);
}
}
}
Collections.sort(users, this::compareUsersUsingDistanceWithRef);
Expand All @@ -104,10 +147,10 @@ private void initDataSet(Categories category) {
users.clear();
services_problem_text_udpate(view, googleIds.isEmpty());
mAdapter_.notifyDataSetChanged();

for (String googleId : googleIds) {
DBUtility.get().getUser(googleId, user -> {
if (user != null && !users.contains(user) && !user.getGoogleId_().equals(GoogleSignInSingleton.get().getClientUniqueID())) {
if (user != null && !users.contains(user) && !user.getGoogleId_().equals(GoogleSignInSingleton.get().getClientUniqueID()) &&
userContainsKeywords(user, keywords, category)) {
users.add(user);
Collections.sort(users, this::compareUsersUsingDistanceWithRef);
mAdapter_.notifyDataSetChanged();
Expand All @@ -129,6 +172,37 @@ private void services_problem_text_udpate(View view, boolean empty) {
}
}

/**
* return true if keywords of the user contains at least one of the list kw
* for the given category
* the list of keywords kw must contains ONLY LOWERCASE words
* @param u the user
* @param kw list of keywords to search for
* @param cat the category for which want to search the keywords
* @return boolean user has or not
*/
private boolean userContainsKeywords(User u, ArrayList<String> kw, Categories cat){
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method userContainsKeywords has a Cognitive Complexity of 8 (exceeds 5 allowed). Consider refactoring.

ArrayList<String> listForCat;
if(cat.compareTo(Categories.ALL) == 0){
listForCat = new ArrayList<>();
for(Categories c : Categories.values()){
listForCat.addAll(u.getKeyWords(c));
}

}else{
listForCat = u.getKeyWords(cat);
}
if(kw.isEmpty()){
return true;
}
for (String k : kw){
if(listForCat.contains(k)){
return true;
}
}
return false;
}

private int compareUsersUsingDistanceWithRef(User u1, User u2){
Location ref = LocationManager.get().getCurrentLocation_();
int result = 0;
Expand Down
15 changes: 14 additions & 1 deletion app/src/main/java/ch/epfl/swissteam/services/User.java
Expand Up @@ -126,7 +126,20 @@ public User(String googleID_, String name_, String email_, String description_,
this.imageUrl_ = imageUrl_;
this.rating_ = rating_;
this.categories_ = categories_ == null ? new ArrayList<>() : (ArrayList<Categories>) categories_.clone();
this.keyWords_ = keyWords_ == null ? new HashMap<>() : (HashMap<String, ArrayList<String>>) keyWords_.clone();

//keywords are stored in lowercase to simplify the comparison when searching for services
HashMap<String, ArrayList<String>> lowercaseKeywords = new HashMap<>();
if(keyWords_ != null) {
ArrayList<String> kwList;
for (String key : keyWords_.keySet()) {
kwList = new ArrayList<>();
for (String k : keyWords_.get(key)) {
kwList.add(k.toLowerCase());
}
lowercaseKeywords.put(key, kwList);
}
}
this.keyWords_ = lowercaseKeywords;
this.chatRelations_ = chatRelations_ == null ? new ArrayList<>() : (ArrayList<ChatRelation>) chatRelations_.clone();
this.upvotes_ = upvotes_ == null ? new ArrayList<String>() : (ArrayList<String>) upvotes_.clone();
this.downvotes_ = downvotes_ == null ? new ArrayList<String>() : (ArrayList<String>) upvotes_.clone();
Expand Down