Add a feature: Searching for posts.

This commit is contained in:
Alex Ning 2019-02-22 14:55:26 +08:00
parent 1293eac5c8
commit a4f664d428
5 changed files with 137 additions and 30 deletions

View File

@ -1,12 +1,12 @@
package ml.docilealligator.infinityforreddit; package ml.docilealligator.infinityforreddit;
import androidx.annotation.NonNull;
import android.util.Log; import android.util.Log;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import androidx.annotation.NonNull;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;

View File

@ -1,13 +1,13 @@
package ml.docilealligator.infinityforreddit; package ml.docilealligator.infinityforreddit;
import androidx.lifecycle.MutableLiveData;
import androidx.paging.PageKeyedDataSource;
import androidx.annotation.NonNull;
import android.util.Log; import android.util.Log;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Locale; import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.lifecycle.MutableLiveData;
import androidx.paging.PageKeyedDataSource;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Retrofit; import retrofit2.Retrofit;
@ -21,6 +21,7 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
static final int TYPE_FRONT_PAGE = 0; static final int TYPE_FRONT_PAGE = 0;
static final int TYPE_SUBREDDIT = 1; static final int TYPE_SUBREDDIT = 1;
static final int TYPE_USER = 2; static final int TYPE_USER = 2;
static final int TYPE_SEARCH = 3;
private Retrofit retrofit; private Retrofit retrofit;
private String accessToken; private String accessToken;
@ -47,11 +48,11 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
this.onPostFetchedCallback = onPostFetchedCallback; this.onPostFetchedCallback = onPostFetchedCallback;
} }
PostDataSource(Retrofit retrofit, String accessToken, Locale locale, String name, int postType, OnPostFetchedCallback onPostFetchedCallback) { PostDataSource(Retrofit retrofit, String accessToken, Locale locale, String subredditName, int postType, OnPostFetchedCallback onPostFetchedCallback) {
this.retrofit = retrofit; this.retrofit = retrofit;
this.accessToken = accessToken; this.accessToken = accessToken;
this.locale = locale; this.locale = locale;
this.name = name; this.name = subredditName;
paginationNetworkStateLiveData = new MutableLiveData(); paginationNetworkStateLiveData = new MutableLiveData();
initialLoadStateLiveData = new MutableLiveData(); initialLoadStateLiveData = new MutableLiveData();
this.postType = postType; this.postType = postType;
@ -83,6 +84,9 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
case TYPE_USER: case TYPE_USER:
loadUserPostsInitial(callback, null); loadUserPostsInitial(callback, null);
break; break;
case TYPE_SEARCH:
loadSearchPostsInitial(callback);
break;
} }
} }
@ -111,6 +115,8 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
break; break;
case TYPE_USER: case TYPE_USER:
loadUserPostsAfter(params, callback); loadUserPostsAfter(params, callback);
case TYPE_SEARCH:
loadSearchPostsAfter(params, callback);
} }
} }
@ -344,6 +350,81 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
}); });
} }
private void loadSearchPostsInitial(@NonNull final LoadInitialCallback<String, Post> callback) {
RedditAPI api = retrofit.create(RedditAPI.class);
Call<String> getPost = api.searchPosts(name, null, RedditUtils.getOAuthHeader(accessToken));
getPost.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, retrofit2.Response<String> response) {
if(response.isSuccessful()) {
ParsePost.parsePost(response.body(), locale,
new ParsePost.ParsePostListener() {
@Override
public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) {
if(newPosts.size() == 0) {
onPostFetchedCallback.noPost();
} else {
onPostFetchedCallback.hasPost();
}
callback.onResult(newPosts, null, lastItem);
initialLoadStateLiveData.postValue(NetworkState.LOADED);
}
@Override
public void onParsePostFail() {
Log.i("Post fetch error", "Error parsing data");
initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data"));
}
});
} else {
Log.i("Post fetch error", response.message());
initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, response.message()));
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
String errorMessage = t == null ? "unknown error" : t.getMessage();
initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage));
}
});
}
private void loadSearchPostsAfter(@NonNull LoadParams<String> params, @NonNull final LoadCallback<String, Post> callback) {
RedditAPI api = retrofit.create(RedditAPI.class);
Call<String> getPost = api.searchPosts(name, params.key, RedditUtils.getOAuthHeader(accessToken));
getPost.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, retrofit2.Response<String> response) {
if(response.isSuccessful()) {
ParsePost.parsePost(response.body(), locale, new ParsePost.ParsePostListener() {
@Override
public void onParsePostSuccess(ArrayList<Post> newPosts, String lastItem) {
callback.onResult(newPosts, lastItem);
paginationNetworkStateLiveData.postValue(NetworkState.LOADED);
}
@Override
public void onParsePostFail() {
Log.i("Best post", "Error parsing data");
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data"));
}
});
} else {
Log.i("Best post", response.message());
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, response.message()));
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
String errorMessage = t == null ? "unknown error" : t.getMessage();
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage));
}
});
}
void retry() { void retry() {
loadInitial(initialParams, initialCallback); loadInitial(initialParams, initialCallback);
} }

View File

@ -58,14 +58,18 @@ public interface RedditAPI {
Call<String> getInfo(@Path("subredditNamePrefixed") String subredditNamePrefixed, @Query("id") String id); Call<String> getInfo(@Path("subredditNamePrefixed") String subredditNamePrefixed, @Query("id") String id);
@GET("subreddits/search.json?raw_json=1&include_over_18=on") @GET("subreddits/search.json?raw_json=1&include_over_18=on")
Call<String> searchSubreddits(@Query("q") String subredditName, @Query("after") String after); Call<String> searchSubreddits(@Query("q") String subredditName, @Query("after") String after,
@HeaderMap Map<String, String> headers);
@GET("/profiles/search.json?raw_json=1") @GET("profiles/search.json?raw_json=1")
Call<String> searchProfiles(@Query("q") String profileName, @Query("after") String after); Call<String> searchProfiles(@Query("q") String profileName, @Query("after") String after,
@HeaderMap Map<String, String> headers);
@GET("/search.json?raw_json=1") @GET("search.json?raw_json=1&type=link")
Call<String> searchPosts(@Query("q") String query, @Query("after") String after); Call<String> searchPosts(@Query("q") String query, @Query("after") String after,
@HeaderMap Map<String, String> headers);
@GET("/r/{subredditName}/search.json?raw_json=1&restrict_sr=true") @GET("r/{subredditName}/search.json?raw_json=1&type=link&restrict_sr=true")
Call<String> searchPostsInSpecificSubreddit(@Query("q") String query, @Query("after") String after); Call<String> searchPostsInSpecificSubreddit(@Query("q") String query, @Query("after") String after,
@HeaderMap Map<String, String> headers);
} }

View File

@ -17,6 +17,7 @@ import androidx.viewpager.widget.ViewPager;
public class SearchActivity extends AppCompatActivity { public class SearchActivity extends AppCompatActivity {
static final String QUERY_KEY = "QK"; static final String QUERY_KEY = "QK";
private String mQuery;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -36,6 +37,7 @@ public class SearchActivity extends AppCompatActivity {
Intent intent = getIntent(); Intent intent = getIntent();
String query = intent.getExtras().getString(QUERY_KEY); String query = intent.getExtras().getString(QUERY_KEY);
if(query != null) { if(query != null) {
mQuery = query;
setTitle(query); setTitle(query);
} }
} }
@ -58,13 +60,33 @@ public class SearchActivity extends AppCompatActivity {
@Override @Override
public Fragment getItem(int position) { public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page. switch (position) {
// Return a PlaceholderFragment (defined as a static inner class below). case 0: {
PostFragment mFragment = new PostFragment(); PostFragment mFragment = new PostFragment();
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putInt(PostFragment.POST_TYPE_KEY, PostDataSource.TYPE_FRONT_PAGE); bundle.putInt(PostFragment.POST_TYPE_KEY, PostDataSource.TYPE_SEARCH);
mFragment.setArguments(bundle); bundle.putString(PostFragment.NAME_KEY, mQuery);
return mFragment; mFragment.setArguments(bundle);
return mFragment;
}
case 1: {
PostFragment mFragment = new PostFragment();
Bundle bundle = new Bundle();
bundle.putInt(PostFragment.POST_TYPE_KEY, PostDataSource.TYPE_FRONT_PAGE);
bundle.putString(PostFragment.NAME_KEY, mQuery);
mFragment.setArguments(bundle);
return mFragment;
}
default:
{
PostFragment mFragment = new PostFragment();
Bundle bundle = new Bundle();
bundle.putInt(PostFragment.POST_TYPE_KEY, PostDataSource.TYPE_FRONT_PAGE);
bundle.putString(PostFragment.NAME_KEY, mQuery);
mFragment.setArguments(bundle);
return mFragment;
}
}
} }
@Override @Override

View File

@ -7,16 +7,6 @@ import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.browser.customtabs.CustomTabsIntent;
import com.google.android.material.chip.Chip;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.snackbar.Snackbar;
import androidx.core.content.ContextCompat;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
@ -34,6 +24,8 @@ import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target; import com.bumptech.glide.request.target.Target;
import com.google.android.material.chip.Chip;
import com.google.android.material.snackbar.Snackbar;
import com.lsjwzh.widget.materialloadingprogressbar.CircleProgressBar; import com.lsjwzh.widget.materialloadingprogressbar.CircleProgressBar;
import com.multilevelview.MultiLevelRecyclerView; import com.multilevelview.MultiLevelRecyclerView;
import com.santalu.aspectratioimageview.AspectRatioImageView; import com.santalu.aspectratioimageview.AspectRatioImageView;
@ -46,6 +38,14 @@ import javax.inject.Named;
import CustomView.AspectRatioGifImageView; import CustomView.AspectRatioGifImageView;
import SubredditDatabase.SubredditRoomDatabase; import SubredditDatabase.SubredditRoomDatabase;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.cardview.widget.CardView;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import jp.wasabeef.glide.transformations.BlurTransformation; import jp.wasabeef.glide.transformations.BlurTransformation;