Can search groups

This commit is contained in:
Pierre HUBERT 2018-12-27 09:36:14 +01:00
parent 4e79e299bf
commit 8fa4c5bcc4
23 changed files with 935 additions and 68 deletions

View File

@ -39,6 +39,11 @@
android:name=".ui.activities.SearchUserActivity"
android:label="@string/activity_searchuser_title" />
<!-- Global search activity -->
<activity
android:name=".ui.activities.SearchActivity"
android:label="@string/activity_search_title" />
<!-- Notifications background refresh service -->
<service
android:name=".data.services.NotificationsService"
@ -50,8 +55,9 @@
android:label="@string/activity_view_pdf_label" />
<!-- Account settings activity -->
<activity android:name=".ui.activities.AccountSettingsActivity"
android:label="@string/activity_account_settings_label"/>
<activity
android:name=".ui.activities.AccountSettingsActivity"
android:label="@string/activity_account_settings_label" />
<!-- Settings activity -->
<activity
@ -63,7 +69,6 @@
android:name=".ui.activities.AboutActivity"
android:label="@string/activity_about_title" />
</application>
</manifest>

View File

@ -0,0 +1,12 @@
package org.communiquons.android.comunic.client.data.enums;
/**
* Different kinds of search result
*
* @author Pierre HUBERT
*/
public enum KindSearchResult {
USER,
GROUP,
UNKNOWN
}

View File

@ -0,0 +1,182 @@
package org.communiquons.android.comunic.client.data.helpers;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.ArrayMap;
import org.communiquons.android.comunic.client.data.enums.KindSearchResult;
import org.communiquons.android.comunic.client.data.models.APIRequest;
import org.communiquons.android.comunic.client.data.models.APIResponse;
import org.communiquons.android.comunic.client.data.models.GroupInfo;
import org.communiquons.android.comunic.client.data.models.SearchResult;
import org.communiquons.android.comunic.client.data.models.SearchResultWithInfo;
import org.communiquons.android.comunic.client.data.models.UserInfo;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
/**
* Search helper
*
* This helper is used to search users and groups
*
* @author Pierre HUBERT
*/
public class SearchHelper extends BaseHelper {
public SearchHelper(Context context) {
super(context);
}
/**
* Perform a global search in the database
*
* @param query The query to search for
* @return The list of results / null in case of failure
*/
@Nullable
public ArrayList<SearchResult> global(String query) {
//Prepare request
APIRequest request = new APIRequest(getContext(), "search/global");
request.addString("query", query);
//Execute request
try {
APIResponse response = request.exec();
if(response.getResponse_code() != 200)
return null;
//Get JSON data
JSONArray data = response.getJSONArray();
if(data == null)
return null;
//Parse and return results
ArrayList<SearchResult> results = new ArrayList<>();
for(int i = 0; i < data.length(); i++)
results.add(JSONObjectToSearchResult(data.getJSONObject(i)));
return results;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Fill search result with information for users, groups...
*
* @param list The list of results to process
* @return Information for groups, users / null in case of failure
*/
@Nullable
public ArrayList<SearchResultWithInfo> fillResults(@NonNull ArrayList<SearchResult> list){
ArrayList<SearchResultWithInfo> listWithInfo = new ArrayList<>();
//Extract the ids of the users and the groups to get
ArrayList<Integer> usersID = new ArrayList<>();
ArrayList<Integer> groupsID = new ArrayList<>();
for(SearchResult result : list){
if(result.getKind() == KindSearchResult.USER)
usersID.add(result.getId());
else if(result.getKind() == KindSearchResult.GROUP)
groupsID.add(result.getId());
SearchResultWithInfo resultWithInfo = new SearchResultWithInfo();
result.copyTo(resultWithInfo);
listWithInfo.add(resultWithInfo);
}
//Get information about users (if any)
if(usersID.size() > 0){
ArrayMap<Integer, UserInfo> usersInfo = new GetUsersHelper(getContext())
.getMultiple(usersID);
if(usersInfo == null)
return null;
//Process the list of result to apply information
for(SearchResultWithInfo result : listWithInfo){
//Skip non related entries
if(result.getKind() != KindSearchResult.USER)
continue;
result.setUserInfo(usersInfo.get(result.getId()));
}
}
//Get information about groups (if any)
if(groupsID.size() > 0){
ArrayMap<Integer, GroupInfo> groupsInfo = new GroupsHelper(getContext())
.getInfoMultiple(groupsID);
if(groupsInfo == null)
return null;
//Process the list of result to apply information
for(SearchResultWithInfo result : listWithInfo){
//Skip non related entries
if(result.getKind() != KindSearchResult.GROUP)
continue;
result.setGroupInfo(groupsInfo.get(result.getId()));
}
}
return listWithInfo;
}
/**
* Turn a string into a search kind result
*
* @param string The string to convert
* @return Matching search result
*/
private static KindSearchResult StringToKindSearchResult(String string){
switch (string){
case "user":
return KindSearchResult.USER;
case "group":
return KindSearchResult.GROUP;
default:
return KindSearchResult.UNKNOWN;
}
}
/**
* Turn a JSONObject into a SearchResult object
*
* @param object The object to convert
* @return Generated SearchResult object
* @throws JSONException This exception is thrown in case of failure
*/
private static SearchResult JSONObjectToSearchResult(JSONObject object) throws JSONException {
SearchResult result = new SearchResult();
result.setId(object.getInt("id"));
result.setKind(StringToKindSearchResult(object.getString("kind")));
return result;
}
}

View File

@ -2,6 +2,8 @@ package org.communiquons.android.comunic.client.data.models;
import android.content.Context;
import org.communiquons.android.comunic.client.data.helpers.APIRequestHelper;
import java.util.ArrayList;
/**
@ -99,17 +101,17 @@ public class APIRequest {
public String get_parameters_encoded(){
//Return string
String result = "";
StringBuilder result = new StringBuilder();
//Process loop
for(int i = 0; i < parameters.size(); i++){
//Make sure to separate parameters
result += (i > 0 ? "&" : "");
result += parameters.get(i).get_encoded();
result.append(i > 0 ? "&" : "");
result.append(parameters.get(i).get_encoded());
}
return result;
return result.toString();
}
/**
@ -147,4 +149,16 @@ public class APIRequest {
public boolean isTryContinueOnError() {
return tryContinueOnError;
}
/**
* Execute the request
*
* This is a convenience method
*
* @return The result of the operation
* @throws Exception In case of failure
*/
public APIResponse exec() throws Exception {
return new APIRequestHelper().exec(this);
}
}

View File

@ -0,0 +1,46 @@
package org.communiquons.android.comunic.client.data.models;
import org.communiquons.android.comunic.client.data.enums.KindSearchResult;
/**
* Single search result
*
* @author Pierre HUBERT
*/
public class SearchResult {
//Private fields
private int id;
private KindSearchResult kind;
/**
* Base constructor
*/
public SearchResult(){}
/**
* Copy the values of the current object to a new object
*
* @param dst Destination object
*/
public void copyTo(SearchResult dst){
dst.setId(getId());
dst.setKind(getKind());
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public KindSearchResult getKind() {
return kind;
}
public void setKind(KindSearchResult kind) {
this.kind = kind;
}
}

View File

@ -0,0 +1,28 @@
package org.communiquons.android.comunic.client.data.models;
/**
* This object handles a search result and all the information associated with it
*
* @author Pierre HUBERT
*/
public class SearchResultWithInfo extends SearchResult {
private GroupInfo groupInfo;
private UserInfo userInfo;
public GroupInfo getGroupInfo() {
return groupInfo;
}
public void setGroupInfo(GroupInfo groupInfo) {
this.groupInfo = groupInfo;
}
public UserInfo getUserInfo() {
return userInfo;
}
public void setUserInfo(UserInfo userInfo) {
this.userInfo = userInfo;
}
}

View File

@ -28,14 +28,36 @@ public final class Constants {
public static final int POST_CREATE_FORM_PICK_PHOTO = 2;
/**
* Intent code : search a user
* Main Activity : search a user
*/
public static final int MAIN_ACTIVITY_SEARCH_USER_INTENT = 3;
/**
* Main Activity : make a global search
*/
public static final int MAIN_ACTIVITY_GLOBAL_SEARCH_INTENT = 4;
/**
* Pick image to update account image
*/
public static final int ACCOUNT_IMAGE_SETTINGS_PICK_NEW_INTENT = 4;
public static final int ACCOUNT_IMAGE_SETTINGS_PICK_NEW_INTENT = 5;
}
/**
* Intents results
*/
public final class IntentResults {
/**
* Search user result
*/
public static final String SEARCH_USER_RESULT = "org.communiquons.android.searchUser.RESULT";
/**
* Global search result
*/
public static final String SEARCH_GLOBAL_RESULT = "org.communiquons.android.globalSearch.RESULT";
}
}

View File

@ -1,9 +1,13 @@
package org.communiquons.android.comunic.client.ui.activities;
import android.os.Bundle;
import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import org.communiquons.android.comunic.client.ui.asynctasks.SafeAsyncTasksManager;
/**
* Base application activity
*
@ -11,10 +15,40 @@ import android.support.v7.app.AppCompatActivity;
*/
public abstract class BaseActivity extends AppCompatActivity {
/**
* Tasks manager
*/
private SafeAsyncTasksManager mSafeAsyncTasksManager = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Initialize task manager
mSafeAsyncTasksManager = new SafeAsyncTasksManager();
}
@Override
protected void onDestroy() {
super.onDestroy();
//Unset all task
mSafeAsyncTasksManager.unsetAllTasks();
}
@NonNull
@Override
public ActionBar getSupportActionBar() {
assert super.getSupportActionBar() != null;
return super.getSupportActionBar();
}
/**
* Get tasks manager associated with this activity
*
* @return Task manager associated to this activity
*/
public SafeAsyncTasksManager getTasksManager() {
return mSafeAsyncTasksManager;
}
}

View File

@ -7,6 +7,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
@ -49,14 +50,16 @@ import org.communiquons.android.comunic.client.ui.fragments.groups.GroupPageMain
import org.communiquons.android.comunic.client.ui.fragments.groups.UserGroupsFragment;
import org.communiquons.android.comunic.client.ui.fragments.userpage.UserAccessDeniedFragment;
import org.communiquons.android.comunic.client.ui.fragments.userpage.UserPageFragment;
import org.communiquons.android.comunic.client.ui.listeners.OnOpenGroupListener;
import org.communiquons.android.comunic.client.ui.listeners.onOpenUsersPageListener;
import org.communiquons.android.comunic.client.ui.listeners.OnOpenPageListener;
import org.communiquons.android.comunic.client.ui.listeners.onPostOpenListener;
import org.communiquons.android.comunic.client.ui.listeners.openConversationListener;
import org.communiquons.android.comunic.client.ui.listeners.updateConversationListener;
import org.communiquons.android.comunic.client.ui.utils.UiUtils;
import org.communiquons.android.comunic.client.ui.views.NavigationBar;
import java.util.Objects;
import static org.communiquons.android.comunic.client.ui.Constants.IntentRequestCode.MAIN_ACTIVITY_GLOBAL_SEARCH_INTENT;
import static org.communiquons.android.comunic.client.ui.Constants.IntentRequestCode.MAIN_ACTIVITY_SEARCH_USER_INTENT;
@ -66,8 +69,8 @@ import static org.communiquons.android.comunic.client.ui.Constants.IntentRequest
* @author Pierre HUBERT
*/
public class MainActivity extends BaseActivity implements
openConversationListener, updateConversationListener, onOpenUsersPageListener,
onPostOpenListener, NavigationBar.OnNavigationItemSelectedListener, OnOpenGroupListener {
openConversationListener, updateConversationListener, OnOpenPageListener,
onPostOpenListener, NavigationBar.OnNavigationItemSelectedListener {
/**
* Debug tag
@ -245,9 +248,9 @@ public class MainActivity extends BaseActivity implements
return true;
}
//To search a user
if (id == R.id.action_search_user) {
searchUser();
//To perform a wider search
if(id == R.id.action_search) {
searchGlobal();
return true;
}
@ -387,9 +390,28 @@ public class MainActivity extends BaseActivity implements
switch (requestCode) {
//User search
case MAIN_ACTIVITY_SEARCH_USER_INTENT:
assert data.getData() != null;
openUserPage(Integer.decode(data.getData().getQueryParameter("userID")));
openUserPage(Integer.decode(
Objects.requireNonNull(
data.getData().getQueryParameter("userID"))));
break;
//Global search result
case MAIN_ACTIVITY_GLOBAL_SEARCH_INTENT:
assert data.getData() != null;
//Open user page or group accordingly to the choice of the user
Uri result = data.getData();
String type = result.getQueryParameter(SearchActivity.INTENT_ARG_RESULT_TYPE);
int id = Integer.decode(Objects.requireNonNull(result.getQueryParameter(SearchActivity.INTENT_ARG_RESULT_ID)));
if(Objects.equals(type, SearchActivity.INTENT_RESULT_USER))
openUserPage(id);
else
onOpenGroup(id);
break;
}
@ -759,6 +781,17 @@ public class MainActivity extends BaseActivity implements
}
/**
* Perform a global search
*/
private void searchGlobal(){
//Make intent
Intent intent = new Intent(this, SearchActivity.class);
startActivityForResult(intent, MAIN_ACTIVITY_GLOBAL_SEARCH_INTENT);
}
/**
* Open group page
*

View File

@ -0,0 +1,178 @@
package org.communiquons.android.comunic.client.ui.activities;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.MenuItem;
import android.widget.EditText;
import android.widget.Toast;
import org.communiquons.android.comunic.client.R;
import org.communiquons.android.comunic.client.data.models.SearchResultWithInfo;
import org.communiquons.android.comunic.client.ui.Constants;
import org.communiquons.android.comunic.client.ui.adapters.SearchResultsAdapter;
import org.communiquons.android.comunic.client.ui.asynctasks.GlobalSearchTask;
import org.communiquons.android.comunic.client.ui.asynctasks.SafeAsyncTask;
import org.communiquons.android.comunic.client.ui.listeners.OnOpenPageListener;
import java.util.ArrayList;
import java.util.concurrent.ThreadPoolExecutor;
/**
* Search activity
*
* This activity can be used to search both users and groups
*
* @author Pierre HUBERT
*/
public class SearchActivity extends BaseActivity implements TextWatcher, OnOpenPageListener {
/**
* Debug tag
*/
private static final String TAG = SearchActivity.class.getSimpleName();
/**
* Results type
*/
public static final String INTENT_ARG_RESULT_ID = "id";
public static final String INTENT_ARG_RESULT_TYPE = "type";
public static final String INTENT_RESULT_USER = "user";
public static final String INTENT_RESULT_GROUP = "group";
/**
* Adapters
*/
private SearchResultsAdapter mAdapter;
/**
* Views
*/
private RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
//Add go back button
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
((EditText)findViewById(R.id.searchInput)).addTextChangedListener(this);
//Initialize recycler view
mRecyclerView = findViewById(R.id.resultsRecyclerView);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new SearchResultsAdapter(this ,this);
mRecyclerView.setAdapter(mAdapter);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
//Check if we have to finish activity
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//Check if user did not type at least three characters
if(s.length() < 3)
return; //We ignore small researches
//Perform the search
getTasksManager().unsetSpecificTasks(GlobalSearchTask.class);
GlobalSearchTask task = new GlobalSearchTask(this);
task.setOnPostExecuteListener(new SafeAsyncTask.OnPostExecuteListener<ArrayList<SearchResultWithInfo>>() {
@Override
public void OnPostExecute(@Nullable ArrayList<SearchResultWithInfo> searchResultWithInfoList) {
onGotNewList(searchResultWithInfoList);
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ""+s);
getTasksManager().addTask(task);
}
@Override
public void afterTextChanged(Editable s) {
}
private void onGotNewList(@Nullable ArrayList<SearchResultWithInfo> list){
//First, check for errors
if(list == null){
Toast.makeText(this, R.string.err_get_search_results, Toast.LENGTH_SHORT).show();
return;
}
//Apply search results
mAdapter.setList(list);
}
@Override
public void onOpenGroup(int groupID) {
sendResult(groupID, INTENT_RESULT_GROUP);
}
@Override
public void onOpenGroupAccessDenied(int groupID) {
onOpenGroup(groupID);
}
@Override
public void openUserPage(int userID) {
sendResult(userID, INTENT_RESULT_USER);
}
@Override
public void openUserAccessDeniedPage(int userID) {
openUserPage(userID);
}
/**
* This method is called once the user has made a selection
*
* @param id The id of the element chosen by the user
* @param type The type of the element chosen by the user
*/
private void sendResult(int id, String type){
//Send result and terminates activity
Intent intent = new Intent(Constants.IntentResults.SEARCH_GLOBAL_RESULT);
intent.setData(Uri.parse("?" + INTENT_ARG_RESULT_TYPE+"="+type+"&"+INTENT_ARG_RESULT_ID+"="+id));
setResult(RESULT_OK, intent);
finish();
}
}

View File

@ -18,6 +18,7 @@ import android.widget.Toast;
import org.communiquons.android.comunic.client.R;
import org.communiquons.android.comunic.client.data.helpers.DatabaseHelper;
import org.communiquons.android.comunic.client.data.helpers.GetUsersHelper;
import org.communiquons.android.comunic.client.ui.Constants;
import org.communiquons.android.comunic.client.ui.adapters.UsersBasicAdapter;
import org.communiquons.android.comunic.client.data.models.UserInfo;
@ -81,7 +82,7 @@ public class SearchUserActivity extends AppCompatActivity
*/
private void onGotUserID(int userID){
Intent data = new Intent("org.communiquons.android.RESULT");
Intent data = new Intent(Constants.IntentResults.SEARCH_USER_RESULT);
data.setData(Uri.parse("?userID=" + userID));
setResult(RESULT_OK, data);
finish();

View File

@ -6,13 +6,11 @@ import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.communiquons.android.comunic.client.R;
import org.communiquons.android.comunic.client.data.models.GroupInfo;
import org.communiquons.android.comunic.client.ui.listeners.OnGroupActionListener;
import org.communiquons.android.comunic.client.ui.views.GroupImageView;
import org.communiquons.android.comunic.client.ui.views.GroupMembershipStatusView;
import org.communiquons.android.comunic.client.ui.viewholders.GroupViewHolder;
import java.util.ArrayList;
@ -62,55 +60,12 @@ public class GroupsListAdapter extends BaseRecyclerViewAdapter {
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(getContext()).inflate(
R.layout.viewholder_group, viewGroup, false);
return new GroupHolder(view);
return new GroupViewHolder(view, mOnGroupActionListener);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
((GroupHolder)viewHolder).bind(i);
((GroupViewHolder)viewHolder).bind(mList.get(i));
}
/**
* Single group holder class
*/
private class GroupHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private GroupInfo mGroupInfo;
private GroupImageView mGroupImageView;
private TextView mGroupName;
private GroupMembershipStatusView mGroupMembershipStatus;
GroupHolder(@NonNull View itemView) {
super(itemView);
itemView.setOnClickListener(this);
mGroupImageView = itemView.findViewById(R.id.groupImage);
mGroupName = itemView.findViewById(R.id.groupName);
mGroupMembershipStatus = itemView.findViewById(R.id.groupMembershipStatusView);
mGroupMembershipStatus.setOnGroupMembershipUpdateListener(mOnGroupActionListener);
}
GroupInfo getGroup(int pos){
return mList.get(pos);
}
void bind(int pos){
mGroupInfo = getGroup(pos);
mGroupImageView.setGroup(mGroupInfo);
mGroupName.setText(mGroupInfo.getDisplayName());
mGroupMembershipStatus.setGroup(mGroupInfo);
}
@Override
public void onClick(View v) {
if(v.equals(itemView))
mOnGroupActionListener.onOpenGroup(mGroupInfo.getId());
}
}
}

View File

@ -0,0 +1,112 @@
package org.communiquons.android.comunic.client.ui.adapters;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import org.communiquons.android.comunic.client.R;
import org.communiquons.android.comunic.client.data.enums.KindSearchResult;
import org.communiquons.android.comunic.client.data.models.SearchResultWithInfo;
import org.communiquons.android.comunic.client.ui.listeners.OnOpenPageListener;
import org.communiquons.android.comunic.client.ui.viewholders.GroupViewHolder;
import org.communiquons.android.comunic.client.ui.viewholders.UserViewHolder;
import java.util.ArrayList;
/**
* Search results adapter
*
* @author Pierre HUBERT
*/
public class SearchResultsAdapter extends BaseRecyclerViewAdapter {
/**
* The list of results to the search
*/
private ArrayList<SearchResultWithInfo> mList;
/**
* Open listener
*/
private OnOpenPageListener openPageListener;
/**
* Get view types
*/
private final int VIEW_TYPE_USER = 0;
private final int VIEW_TYPE_GROUP = 1;
public SearchResultsAdapter(Context context, @Nullable OnOpenPageListener openPageListener) {
super(context);
this.mList = new ArrayList<>();
this.openPageListener = openPageListener;
}
/**
* Set (update) the list of search results
*
* @param list New list to apply
*/
public void setList(ArrayList<SearchResultWithInfo> list){
this.mList = list;
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return mList.size();
}
@Override
public int getItemViewType(int position) {
return mList.get(position).getKind() == KindSearchResult.USER ?
VIEW_TYPE_USER : VIEW_TYPE_GROUP;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int type) {
RecyclerView.ViewHolder viewHolder;
if(type == VIEW_TYPE_USER){
viewHolder = new UserViewHolder(LayoutInflater
.from(getContext())
.inflate(R.layout.viewholder_user, viewGroup, false)
, openPageListener);
}
else if(type == VIEW_TYPE_GROUP){
viewHolder = new GroupViewHolder(LayoutInflater
.from(getContext())
.inflate(R.layout.viewholder_group, viewGroup, false)
, openPageListener);
}
else
throw new RuntimeException("Intend to display a none supported kind of result!");
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
SearchResultWithInfo searchResultWithInfo = mList.get(i);
if(searchResultWithInfo.getKind() == KindSearchResult.USER){
((UserViewHolder)viewHolder).bind(searchResultWithInfo.getUserInfo());
}
if(searchResultWithInfo.getKind() == KindSearchResult.GROUP){
((GroupViewHolder)viewHolder).bind(searchResultWithInfo.getGroupInfo());
}
}
}

View File

@ -59,6 +59,7 @@ public class UsersBasicAdapter extends ArrayAdapter<UserInfo> {
account_image.setUser(userInfos);
}
return convertView;
}
}

View File

@ -0,0 +1,32 @@
package org.communiquons.android.comunic.client.ui.asynctasks;
import android.content.Context;
import android.support.annotation.Nullable;
import org.communiquons.android.comunic.client.data.helpers.SearchHelper;
import org.communiquons.android.comunic.client.data.models.SearchResult;
import org.communiquons.android.comunic.client.data.models.SearchResultWithInfo;
import java.util.ArrayList;
public class GlobalSearchTask extends SafeAsyncTask<String, Void, ArrayList<SearchResultWithInfo>> {
public GlobalSearchTask(Context context) {
super(context);
}
@Override
@Nullable
protected ArrayList<SearchResultWithInfo> doInBackground(String... strings) {
SearchHelper helper = new SearchHelper(getContext());
//First, perform the search itself
ArrayList<SearchResult> list = helper.global(strings[0]);
if(list == null)
return null;
//Then get information about related users and groups
return helper.fillResults(list);
}
}

View File

@ -0,0 +1,9 @@
package org.communiquons.android.comunic.client.ui.listeners;
/**
* Implement this interface on activities that can open group and user pages
*
* @author Pierre HUBERT
*/
public interface OnOpenPageListener extends OnOpenGroupListener, onOpenUsersPageListener {
}

View File

@ -0,0 +1,73 @@
package org.communiquons.android.comunic.client.ui.viewholders;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import org.communiquons.android.comunic.client.R;
import org.communiquons.android.comunic.client.data.models.GroupInfo;
import org.communiquons.android.comunic.client.ui.listeners.OnGroupActionListener;
import org.communiquons.android.comunic.client.ui.listeners.OnOpenGroupListener;
import org.communiquons.android.comunic.client.ui.views.GroupImageView;
import org.communiquons.android.comunic.client.ui.views.GroupMembershipStatusView;
/**
* Single group holder class
*
* @author Pierre HUBERT
*/
public class GroupViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private GroupInfo mGroupInfo;
private OnOpenGroupListener mOnOpenGroupListener;
private GroupImageView mGroupImageView;
private TextView mGroupName;
private GroupMembershipStatusView mGroupMembershipStatus;
public GroupViewHolder(@NonNull View itemView, @Nullable OnOpenGroupListener openGroupListener){
this(itemView, null);
mOnOpenGroupListener = openGroupListener;
}
public GroupViewHolder(@NonNull View itemView, @Nullable OnGroupActionListener actionListener) {
super(itemView);
itemView.setOnClickListener(this);
mGroupImageView = itemView.findViewById(R.id.groupImage);
mGroupName = itemView.findViewById(R.id.groupName);
mGroupMembershipStatus = itemView.findViewById(R.id.groupMembershipStatusView);
if(actionListener != null) {
mGroupMembershipStatus.setOnGroupMembershipUpdateListener(actionListener);
mOnOpenGroupListener = actionListener;
}
else
mGroupMembershipStatus.setVisibility(View.GONE);
}
/**
* Bind (apply) a new group to the view
*
* @param group The group to apply to the view
*/
public void bind(GroupInfo group){
mGroupInfo = group;
mGroupImageView.setGroup(mGroupInfo);
mGroupName.setText(mGroupInfo.getDisplayName());
mGroupMembershipStatus.setGroup(mGroupInfo);
}
@Override
public void onClick(View v) {
if(v.equals(itemView) && mOnOpenGroupListener != null)
mOnOpenGroupListener.onOpenGroup(mGroupInfo.getId());
}
}

View File

@ -0,0 +1,56 @@
package org.communiquons.android.comunic.client.ui.viewholders;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import org.communiquons.android.comunic.client.R;
import org.communiquons.android.comunic.client.data.models.UserInfo;
import org.communiquons.android.comunic.client.ui.listeners.onOpenUsersPageListener;
import org.communiquons.android.comunic.client.ui.views.WebUserAccountImage;
/**
* User view holder
*
* Handles displaying of a single user
*
* @author Pierre HUBERT
*/
public class UserViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
//Private fields
private onOpenUsersPageListener mListener;
private WebUserAccountImage mUserAccountImage;
private TextView mUserName;
private UserInfo mUserInfo;
public UserViewHolder(@NonNull View itemView, @Nullable onOpenUsersPageListener listener) {
super(itemView);
mUserAccountImage = itemView.findViewById(R.id.user_account_image);
mUserName = itemView.findViewById(R.id.user_name);
this.mListener = listener;
itemView.setOnClickListener(this);
}
/**
* Apply a new user to this view
*
* @param userInfo Information about the user to apply
*/
public void bind(UserInfo userInfo){
this.mUserInfo = userInfo;
mUserAccountImage.setUser(userInfo);
mUserName.setText(userInfo.getDisplayFullName());
}
@Override
public void onClick(View v) {
if(mListener != null && v.equals(itemView))
mListener.openUserPage(mUserInfo.getId());
}
}

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.activities.SearchActivity">
<EditText
android:id="@+id/searchInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:ems="10"
android:inputType="textPersonName"
android:hint="@string/input_search_hint"
android:lines="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.support.v7.widget.RecyclerView
android:id="@+id/resultsRecyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/searchInput" />
</android.support.constraint.ConstraintLayout>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:background="?selectableItemBackground"
android:focusable="true"
android:clickable="true"
android:layout_height="wrap_content">
<org.communiquons.android.comunic.client.ui.views.WebUserAccountImage
android:id="@+id/user_account_image"
android:layout_width="@dimen/account_image_default_width"
android:layout_height="@dimen/account_image_default_height"
android:src="@drawable/default_account_image" />
<TextView
android:id="@+id/user_name"
style="?textAppearanceListItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="User name"
android:layout_gravity="center"
android:paddingStart="5dp"
android:paddingEnd="1dp"/>
</LinearLayout>

View File

@ -9,8 +9,8 @@
<!-- Search user -->
<item
android:id="@+id/action_search_user"
android:title="@string/main_menu_search_user" />
android:id="@+id/action_search"
android:title="@string/main_menu_search" />
<!-- Account settings -->
<item

View File

@ -312,4 +312,11 @@
<string name="dialog_leave_group_cancel">Annuler</string>
<string name="dialog_leave_group_confirm">Quitter</string>
<string name="err_update_group_membership">Une erreur a survenue lors de la mise à jour de votre appartenance au groupe !</string>
<string name="main_menu_search">Rechercher</string>
<string name="activity_search_title">Recherche</string>
<string name="input_search_hint">Rechercher un utilisateur, un groupe…</string>
<string name="err_get_search_results">Une erreur a survenue lors de la récupération du résultat de votre recherche !</string>
<string name="notice_group_access_denied">Accès au groupe refusé.</string>
<string name="err_get_group_info">Impossible de récupérer les informations sur le groupe !</string>
<string name="notice_closed_registration">Accès sur invitation</string>
</resources>

View File

@ -314,4 +314,8 @@
<string name="err_get_group_info">Could not get group information!</string>
<string name="notice_group_access_denied">Access to the group denied.</string>
<string name="notice_closed_registration">Invitation only</string>
<string name="main_menu_search">Search</string>
<string name="activity_search_title">Search</string>
<string name="input_search_hint">Search a user, a group…</string>
<string name="err_get_search_results">Could not get results of your search!</string>
</resources>