Adds a prototype search page. The previous search bar is not yet removed.
This commit is contained in:
parent
fcdb507ef0
commit
289e2fbbe1
13 changed files with 480 additions and 51 deletions
|
@ -82,6 +82,12 @@
|
||||||
<activity
|
<activity
|
||||||
android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
|
android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
|
||||||
android:theme="@style/Base.Theme.AppCompat" />
|
android:theme="@style/Base.Theme.AppCompat" />
|
||||||
|
<activity android:name=".SearchActivity">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEARCH" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
|
||||||
|
</activity>
|
||||||
|
|
||||||
<receiver android:name=".receiver.NotificationClearBroadcastReceiver" />
|
<receiver android:name=".receiver.NotificationClearBroadcastReceiver" />
|
||||||
|
|
||||||
|
|
|
@ -293,10 +293,11 @@ public class MainActivity extends BaseActivity {
|
||||||
new PrimaryDrawerItem().withIdentifier(1).withName(getString(R.string.action_view_favourites)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_star),
|
new PrimaryDrawerItem().withIdentifier(1).withName(getString(R.string.action_view_favourites)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_star),
|
||||||
new PrimaryDrawerItem().withIdentifier(2).withName(getString(R.string.action_view_mutes)).withSelectable(false).withIcon(muteDrawable),
|
new PrimaryDrawerItem().withIdentifier(2).withName(getString(R.string.action_view_mutes)).withSelectable(false).withIcon(muteDrawable),
|
||||||
new PrimaryDrawerItem().withIdentifier(3).withName(getString(R.string.action_view_blocks)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_block),
|
new PrimaryDrawerItem().withIdentifier(3).withName(getString(R.string.action_view_blocks)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_block),
|
||||||
|
new PrimaryDrawerItem().withIdentifier(4).withName(getString(R.string.action_search)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_search),
|
||||||
new DividerDrawerItem(),
|
new DividerDrawerItem(),
|
||||||
new SecondaryDrawerItem().withIdentifier(4).withName(getString(R.string.action_view_preferences)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_settings),
|
new SecondaryDrawerItem().withIdentifier(5).withName(getString(R.string.action_view_preferences)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_settings),
|
||||||
new SecondaryDrawerItem().withIdentifier(5).withName(getString(R.string.about_title_activity)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_info),
|
new SecondaryDrawerItem().withIdentifier(6).withName(getString(R.string.about_title_activity)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_info),
|
||||||
new SecondaryDrawerItem().withIdentifier(6).withName(getString(R.string.action_logout)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_exit_to_app)
|
new SecondaryDrawerItem().withIdentifier(7).withName(getString(R.string.action_logout)).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_exit_to_app)
|
||||||
)
|
)
|
||||||
.withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
|
.withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -319,14 +320,17 @@ public class MainActivity extends BaseActivity {
|
||||||
intent.putExtra("type", AccountListActivity.Type.BLOCKS);
|
intent.putExtra("type", AccountListActivity.Type.BLOCKS);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
} else if (drawerItemIdentifier == 4) {
|
} else if (drawerItemIdentifier == 4) {
|
||||||
Intent intent = new Intent(MainActivity.this, PreferencesActivity.class);
|
Intent intent = new Intent(MainActivity.this, SearchActivity.class);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
} else if (drawerItemIdentifier == 5) {
|
} else if (drawerItemIdentifier == 5) {
|
||||||
Intent intent = new Intent(MainActivity.this, AboutActivity.class);
|
Intent intent = new Intent(MainActivity.this, PreferencesActivity.class);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
} else if (drawerItemIdentifier == 6) {
|
} else if (drawerItemIdentifier == 6) {
|
||||||
logout();
|
Intent intent = new Intent(MainActivity.this, AboutActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
} else if (drawerItemIdentifier == 7) {
|
} else if (drawerItemIdentifier == 7) {
|
||||||
|
logout();
|
||||||
|
} else if (drawerItemIdentifier == 8) {
|
||||||
Intent intent = new Intent(MainActivity.this, AccountListActivity.class);
|
Intent intent = new Intent(MainActivity.this, AccountListActivity.class);
|
||||||
intent.putExtra("type", AccountListActivity.Type.FOLLOW_REQUESTS);
|
intent.putExtra("type", AccountListActivity.Type.FOLLOW_REQUESTS);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
|
@ -512,7 +516,7 @@ public class MainActivity extends BaseActivity {
|
||||||
// Show follow requests in the menu, if this is a locked account.
|
// Show follow requests in the menu, if this is a locked account.
|
||||||
if (me.locked) {
|
if (me.locked) {
|
||||||
PrimaryDrawerItem followRequestsItem = new PrimaryDrawerItem()
|
PrimaryDrawerItem followRequestsItem = new PrimaryDrawerItem()
|
||||||
.withIdentifier(7)
|
.withIdentifier(8)
|
||||||
.withName(R.string.action_view_follow_requests)
|
.withName(R.string.action_view_follow_requests)
|
||||||
.withSelectable(false)
|
.withSelectable(false)
|
||||||
.withIcon(GoogleMaterial.Icon.gmd_person_add);
|
.withIcon(GoogleMaterial.Icon.gmd_person_add);
|
||||||
|
|
195
app/src/main/java/com/keylesspalace/tusky/SearchActivity.java
Normal file
195
app/src/main/java/com/keylesspalace/tusky/SearchActivity.java
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
/* Copyright 2017 Andrew Dawson
|
||||||
|
*
|
||||||
|
* This file is a part of Tusky.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||||
|
* see <http://www.gnu.org/licenses>. */
|
||||||
|
|
||||||
|
package com.keylesspalace.tusky;
|
||||||
|
|
||||||
|
import android.app.SearchManager;
|
||||||
|
import android.app.SearchableInfo;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v7.app.ActionBar;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.support.v7.widget.SearchView;
|
||||||
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.keylesspalace.tusky.adapter.SearchResultsAdapter;
|
||||||
|
import com.keylesspalace.tusky.entity.SearchResults;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
public class SearchActivity extends BaseActivity implements SearchView.OnQueryTextListener {
|
||||||
|
private static final String TAG = "SearchActivity"; // logging tag
|
||||||
|
|
||||||
|
@BindView(R.id.progress_bar) ProgressBar progressBar;
|
||||||
|
@BindView(R.id.message_no_results) TextView messageNoResults;
|
||||||
|
private SearchResultsAdapter adapter;
|
||||||
|
private String currentQuery;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_search);
|
||||||
|
ButterKnife.bind(this);
|
||||||
|
|
||||||
|
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
ActionBar bar = getSupportActionBar();
|
||||||
|
if (bar != null) {
|
||||||
|
bar.setDisplayHomeAsUpEnabled(true);
|
||||||
|
bar.setDisplayShowHomeEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
|
||||||
|
recyclerView.setHasFixedSize(true);
|
||||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
adapter = new SearchResultsAdapter();
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
|
handleIntent(getIntent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onNewIntent(Intent intent) {
|
||||||
|
super.onNewIntent(intent);
|
||||||
|
handleIntent(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
super.onCreateOptionsMenu(menu);
|
||||||
|
|
||||||
|
getMenuInflater().inflate(R.menu.search_toolbar, menu);
|
||||||
|
SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
|
||||||
|
setupSearchView(searchView);
|
||||||
|
|
||||||
|
if (currentQuery != null) {
|
||||||
|
searchView.setQuery(currentQuery, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case android.R.id.home: {
|
||||||
|
onBackPressed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onQueryTextChange(String newText) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onQueryTextSubmit(String query) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleIntent(Intent intent) {
|
||||||
|
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||||
|
currentQuery = intent.getStringExtra(SearchManager.QUERY);
|
||||||
|
search(currentQuery);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupSearchView(SearchView searchView) {
|
||||||
|
searchView.setIconifiedByDefault(false);
|
||||||
|
|
||||||
|
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
|
||||||
|
if (searchManager != null) {
|
||||||
|
List<SearchableInfo> searchables = searchManager.getSearchablesInGlobalSearch();
|
||||||
|
SearchableInfo searchableInfo = searchManager.getSearchableInfo(getComponentName());
|
||||||
|
for (SearchableInfo info : searchables) {
|
||||||
|
if (info.getSuggestAuthority() != null
|
||||||
|
&& info.getSuggestAuthority().startsWith("applications")) {
|
||||||
|
searchableInfo = info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
searchView.setSearchableInfo(searchableInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
searchView.setOnQueryTextListener(this);
|
||||||
|
searchView.setFocusable(false);
|
||||||
|
searchView.setFocusableInTouchMode(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void search(String query) {
|
||||||
|
clearResults();
|
||||||
|
Callback<SearchResults> callback = new Callback<SearchResults>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<SearchResults> call, Response<SearchResults> response) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
SearchResults results = response.body();
|
||||||
|
if (results.accounts != null || results.hashtags != null) {
|
||||||
|
adapter.updateSearchResults(results);
|
||||||
|
hideFeedback();
|
||||||
|
} else {
|
||||||
|
displayNoResults();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onSearchFailure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<SearchResults> call, Throwable t) {
|
||||||
|
onSearchFailure();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mastodonAPI.search(query, false)
|
||||||
|
.enqueue(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSearchFailure() {
|
||||||
|
displayNoResults();
|
||||||
|
Log.e(TAG, "Search request failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearResults() {
|
||||||
|
adapter.updateSearchResults(null);
|
||||||
|
progressBar.setVisibility(View.VISIBLE);
|
||||||
|
messageNoResults.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayNoResults() {
|
||||||
|
progressBar.setVisibility(View.GONE);
|
||||||
|
messageNoResults.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideFeedback() {
|
||||||
|
progressBar.setVisibility(View.GONE);
|
||||||
|
messageNoResults.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.keylesspalace.tusky.adapter;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.keylesspalace.tusky.R;
|
||||||
|
import com.keylesspalace.tusky.entity.Account;
|
||||||
|
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||||
|
import com.pkmmte.view.CircularImageView;
|
||||||
|
import com.squareup.picasso.Picasso;
|
||||||
|
|
||||||
|
class AccountViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
private View container;
|
||||||
|
private TextView username;
|
||||||
|
private TextView displayName;
|
||||||
|
private CircularImageView avatar;
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
AccountViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
container = itemView.findViewById(R.id.account_container);
|
||||||
|
username = (TextView) itemView.findViewById(R.id.account_username);
|
||||||
|
displayName = (TextView) itemView.findViewById(R.id.account_display_name);
|
||||||
|
avatar = (CircularImageView) itemView.findViewById(R.id.account_avatar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupWithAccount(Account account) {
|
||||||
|
id = account.id;
|
||||||
|
String format = username.getContext().getString(R.string.status_username_format);
|
||||||
|
String formattedUsername = String.format(format, account.username);
|
||||||
|
username.setText(formattedUsername);
|
||||||
|
displayName.setText(account.getDisplayName());
|
||||||
|
Context context = avatar.getContext();
|
||||||
|
Picasso.with(context)
|
||||||
|
.load(account.avatar)
|
||||||
|
.placeholder(R.drawable.avatar_default)
|
||||||
|
.error(R.drawable.avatar_error)
|
||||||
|
.into(avatar);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupActionListener(final AccountActionListener listener) {
|
||||||
|
container.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
listener.onViewAccount(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,18 +15,13 @@
|
||||||
|
|
||||||
package com.keylesspalace.tusky.adapter;
|
package com.keylesspalace.tusky.adapter;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.entity.Account;
|
|
||||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||||
import com.pkmmte.view.CircularImageView;
|
|
||||||
import com.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
/** Both for follows and following lists. */
|
/** Both for follows and following lists. */
|
||||||
public class FollowAdapter extends AccountAdapter {
|
public class FollowAdapter extends AccountAdapter {
|
||||||
|
@ -71,43 +66,4 @@ public class FollowAdapter extends AccountAdapter {
|
||||||
return VIEW_TYPE_ACCOUNT;
|
return VIEW_TYPE_ACCOUNT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class AccountViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
private View container;
|
|
||||||
private TextView username;
|
|
||||||
private TextView displayName;
|
|
||||||
private CircularImageView avatar;
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
AccountViewHolder(View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
container = itemView.findViewById(R.id.account_container);
|
|
||||||
username = (TextView) itemView.findViewById(R.id.account_username);
|
|
||||||
displayName = (TextView) itemView.findViewById(R.id.account_display_name);
|
|
||||||
avatar = (CircularImageView) itemView.findViewById(R.id.account_avatar);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupWithAccount(Account account) {
|
|
||||||
id = account.id;
|
|
||||||
String format = username.getContext().getString(R.string.status_username_format);
|
|
||||||
String formattedUsername = String.format(format, account.username);
|
|
||||||
username.setText(formattedUsername);
|
|
||||||
displayName.setText(account.getDisplayName());
|
|
||||||
Context context = avatar.getContext();
|
|
||||||
Picasso.with(context)
|
|
||||||
.load(account.avatar)
|
|
||||||
.placeholder(R.drawable.avatar_default)
|
|
||||||
.error(R.drawable.avatar_error)
|
|
||||||
.into(avatar);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupActionListener(final AccountActionListener listener) {
|
|
||||||
container.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
listener.onViewAccount(id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
/* Copyright 2017 Andrew Dawson
|
||||||
|
*
|
||||||
|
* This file is a part of Tusky.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||||
|
* see <http://www.gnu.org/licenses>. */
|
||||||
|
|
||||||
|
package com.keylesspalace.tusky.adapter;
|
||||||
|
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.keylesspalace.tusky.R;
|
||||||
|
import com.keylesspalace.tusky.entity.Account;
|
||||||
|
import com.keylesspalace.tusky.entity.SearchResults;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SearchResultsAdapter extends RecyclerView.Adapter {
|
||||||
|
private static final int VIEW_TYPE_ACCOUNT = 0;
|
||||||
|
private static final int VIEW_TYPE_HASHTAG = 1;
|
||||||
|
|
||||||
|
private List<Account> accountList;
|
||||||
|
private List<String> hashtagList;
|
||||||
|
|
||||||
|
public SearchResultsAdapter() {
|
||||||
|
super();
|
||||||
|
accountList = new ArrayList<>();
|
||||||
|
hashtagList = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
switch (viewType) {
|
||||||
|
default:
|
||||||
|
case VIEW_TYPE_ACCOUNT: {
|
||||||
|
View view = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.item_account, parent, false);
|
||||||
|
return new AccountViewHolder(view);
|
||||||
|
}
|
||||||
|
case VIEW_TYPE_HASHTAG: {
|
||||||
|
View view = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.item_hashtag, parent, false);
|
||||||
|
return new HashtagViewHolder(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
|
||||||
|
if (position < accountList.size()) {
|
||||||
|
AccountViewHolder holder = (AccountViewHolder) viewHolder;
|
||||||
|
holder.setupWithAccount(accountList.get(position));
|
||||||
|
} else {
|
||||||
|
HashtagViewHolder holder = (HashtagViewHolder) viewHolder;
|
||||||
|
int index = position - accountList.size();
|
||||||
|
holder.setHashtag(hashtagList.get(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return accountList.size() + hashtagList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
if (position >= accountList.size()) {
|
||||||
|
return VIEW_TYPE_HASHTAG;
|
||||||
|
} else {
|
||||||
|
return VIEW_TYPE_ACCOUNT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateSearchResults(SearchResults results) {
|
||||||
|
if (results != null) {
|
||||||
|
if (results.accounts != null) {
|
||||||
|
accountList.addAll(Arrays.asList(results.accounts));
|
||||||
|
}
|
||||||
|
if (results.hashtags != null) {
|
||||||
|
hashtagList.addAll(Arrays.asList(results.hashtags));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
accountList.clear();
|
||||||
|
hashtagList.clear();
|
||||||
|
}
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class HashtagViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
private TextView hashtag;
|
||||||
|
|
||||||
|
HashtagViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
hashtag = (TextView) itemView.findViewById(R.id.hashtag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setHashtag(String tag) {
|
||||||
|
hashtag.setText(String.format("#%s", tag));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* Copyright 2017 Andrew Dawson
|
||||||
|
*
|
||||||
|
* This file is a part of Tusky.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||||
|
* see <http://www.gnu.org/licenses>. */
|
||||||
|
|
||||||
|
package com.keylesspalace.tusky.entity;
|
||||||
|
|
||||||
|
public class SearchResults {
|
||||||
|
public Account[] accounts;
|
||||||
|
public Status[] statuses;
|
||||||
|
public String[] hashtags;
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ import com.keylesspalace.tusky.entity.Media;
|
||||||
import com.keylesspalace.tusky.entity.Notification;
|
import com.keylesspalace.tusky.entity.Notification;
|
||||||
import com.keylesspalace.tusky.entity.Profile;
|
import com.keylesspalace.tusky.entity.Profile;
|
||||||
import com.keylesspalace.tusky.entity.Relationship;
|
import com.keylesspalace.tusky.entity.Relationship;
|
||||||
|
import com.keylesspalace.tusky.entity.SearchResults;
|
||||||
import com.keylesspalace.tusky.entity.Status;
|
import com.keylesspalace.tusky.entity.Status;
|
||||||
import com.keylesspalace.tusky.entity.StatusContext;
|
import com.keylesspalace.tusky.entity.StatusContext;
|
||||||
|
|
||||||
|
@ -191,6 +192,9 @@ public interface MastodonAPI {
|
||||||
@POST("api/v1/reports")
|
@POST("api/v1/reports")
|
||||||
Call<ResponseBody> report(@Field("account_id") String accountId, @Field("status_ids[]") List<String> statusIds, @Field("comment") String comment);
|
Call<ResponseBody> report(@Field("account_id") String accountId, @Field("status_ids[]") List<String> statusIds, @Field("comment") String comment);
|
||||||
|
|
||||||
|
@GET("api/v1/search")
|
||||||
|
Call<SearchResults> search(@Query("q") String q, @Query("resolve") Boolean resolve);
|
||||||
|
|
||||||
@FormUrlEncoded
|
@FormUrlEncoded
|
||||||
@POST("api/v1/apps")
|
@POST("api/v1/apps")
|
||||||
Call<AppCredentials> authenticateApp(
|
Call<AppCredentials> authenticateApp(
|
||||||
|
|
50
app/src/main/res/layout/activity_search.xml
Normal file
50
app/src/main/res/layout/activity_search.xml
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
tools:context="com.keylesspalace.tusky.SearchActivity">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<android.support.v7.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/toolbar_background_color"
|
||||||
|
app:navigationIcon="?attr/homeAsUpIndicator" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<android.support.v7.widget.RecyclerView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:id="@+id/recycler_view" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/progress_bar"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/message_no_results"
|
||||||
|
android:text="@string/search_no_results"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</android.support.design.widget.CoordinatorLayout>
|
7
app/src/main/res/layout/item_hashtag.xml
Normal file
7
app/src/main/res/layout/item_hashtag.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/hashtag"
|
||||||
|
android:padding="8dp" />
|
10
app/src/main/res/menu/search_toolbar.xml
Normal file
10
app/src/main/res/menu/search_toolbar.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?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_search"
|
||||||
|
android:title="@string/action_search"
|
||||||
|
android:icon="@android:drawable/ic_menu_search"
|
||||||
|
app:actionViewClass="android.support.v7.widget.SearchView"
|
||||||
|
app:showAsAction="always" />
|
||||||
|
</menu>
|
|
@ -100,6 +100,7 @@
|
||||||
<string name="action_undo">Undo</string>
|
<string name="action_undo">Undo</string>
|
||||||
<string name="action_accept">Accept</string>
|
<string name="action_accept">Accept</string>
|
||||||
<string name="action_reject">Reject</string>
|
<string name="action_reject">Reject</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
|
||||||
<string name="send_status_link_to">Share toot URL to…</string>
|
<string name="send_status_link_to">Share toot URL to…</string>
|
||||||
<string name="send_status_content_to">Share toot to…</string>
|
<string name="send_status_content_to">Share toot to…</string>
|
||||||
|
@ -116,6 +117,9 @@
|
||||||
<string name="hint_content_warning">Content warning</string>
|
<string name="hint_content_warning">Content warning</string>
|
||||||
<string name="hint_display_name">Display name</string>
|
<string name="hint_display_name">Display name</string>
|
||||||
<string name="hint_note">Bio</string>
|
<string name="hint_note">Bio</string>
|
||||||
|
<string name="hint_search">Search accounts and tags…</string>
|
||||||
|
|
||||||
|
<string name="search_no_results">No results</string>
|
||||||
|
|
||||||
<string name="label_avatar">Avatar</string>
|
<string name="label_avatar">Avatar</string>
|
||||||
<string name="label_header">Header</string>
|
<string name="label_header">Header</string>
|
||||||
|
|
5
app/src/main/res/xml/searchable.xml
Normal file
5
app/src/main/res/xml/searchable.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:hint="@string/hint_search">
|
||||||
|
</searchable>
|
Loading…
Reference in a new issue