package com.github.miao1007.animewallpaper.ui.activity; import android.content.Context; import android.os.Bundle; import android.support.annotation.UiThread; import android.support.annotation.WorkerThread; import android.support.v7.app.AppCompatActivity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import butterknife.BindView; import butterknife.ButterKnife; import com.github.miao1007.animewallpaper.R; import com.github.miao1007.animewallpaper.support.api.konachan.DanbooruAPI; import com.github.miao1007.animewallpaper.support.api.konachan.Tag; import com.github.miao1007.animewallpaper.ui.widget.SearchBar; import com.github.miao1007.animewallpaper.utils.LogUtils; import com.github.miao1007.animewallpaper.utils.SquareUtils; import com.github.miao1007.animewallpaper.utils.StatusBarUtils; import com.jakewharton.rxbinding.widget.RxTextView; import im.fir.sdk.FIR; import java.io.InterruptedIOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import rx.Observable; import rx.Subscriber; import rx.android.schedulers.AndroidSchedulers; import rx.functions.Action1; import rx.functions.Func1; import rx.functions.Func2; import rx.schedulers.Schedulers; public class SearchActivity extends AppCompatActivity { static final String TAG = LogUtils.makeLogTag(SearchActivity.class); private final DanbooruAPI repo = SquareUtils.getRetrofit(DanbooruAPI.KONACHAN).create(DanbooruAPI.class); @BindView(R.id.search_bar) SearchBar mSearchbar; @BindView(R.id.search_list) ListView mSearchListView; @BindView(R.id.internal_search_progress) ProgressBar progressBar; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_search); ButterKnife.bind(this); StatusBarUtils.from(this) .setActionbarView(mSearchbar) .setTransparentStatusbar(true) .setLightStatusBar(true) .process(); final ArrayList<Tag> arrayList = new ArrayList<>(); final ResultAdapter adapter = new ResultAdapter(this, arrayList); mSearchListView.setAdapter(adapter); mSearchListView.post(new Runnable() { @Override public void run() { mSearchListView.setPadding(0, mSearchbar.getHeight() + StatusBarUtils.getStatusBarOffsetPx(getApplicationContext()), 0, 0); } }); mSearchListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { MainActivity.startRefreshActivity(SearchActivity.this, arrayList.get(position).getName()); } }); //mSearchbar.toggle(true); mSearchbar.setOnButton(new Runnable() { @Override public void run() { finish(); } }); /** * Port from {@link https://github.com/ReactiveX/RxSwift} */ RxTextView.textChanges(mSearchbar.getEditTextSearch()) .subscribeOn(AndroidSchedulers.mainThread()) //delay 500ms //debounce and throttle will use different thread after .throttleWithTimeout(300, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread()) .distinct() .filter(new Func1<CharSequence, Boolean>() { @UiThread @Override public Boolean call(CharSequence charSequence) { //void unnecessary request return charSequence.length() != 0; } }) .map(new Func1<CharSequence, String>() { @UiThread @Override public String call(CharSequence charSequence) { //fit network api doc require return charSequence + "*"; } }) .doOnNext(new Action1<CharSequence>() { @UiThread @Override public void call(CharSequence charSequence) { progressBar.setVisibility(View.VISIBLE); arrayList.clear(); adapter.notifyDataSetChanged(); } }) .observeOn(Schedulers.io()) .switchMap(new Func1<String, Observable<List<Tag>>>() { @WorkerThread @Override public Observable<List<Tag>> call(String s) { return repo.getTags(20, s); } }) .retry(new Func2<Integer, Throwable, Boolean>() { //fix InterruptedIOException bugs on Retrofit // when stop old search @WorkerThread @Override public Boolean call(Integer integer, Throwable throwable) { return throwable instanceof InterruptedIOException; } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<List<Tag>>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { FIR.sendCrashManually(e); progressBar.setVisibility(View.INVISIBLE); e.printStackTrace(); Toast.makeText(SearchActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); } @Override public void onNext(List<Tag> tags) { progressBar.setVisibility(View.INVISIBLE); arrayList.clear(); arrayList.addAll(tags); adapter.notifyDataSetChanged(); } }); } @Override protected void onPause() { super.onPause(); if (isFinishing()) { overridePendingTransition(0, 0); } } static class ResultAdapter extends BaseAdapter { final Context context; final List<Tag> tags; public ResultAdapter(Context context, List<Tag> tags) { this.context = context; this.tags = tags; } @Override public int getCount() { return tags.size(); } @Override public Object getItem(int position) { return tags.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { final ViewHolder holder; if (convertView == null) { holder = new ViewHolder(); convertView = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, null, false); holder.textView = ((TextView) convertView.findViewById(android.R.id.text1)); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.textView.setText(tags.get(position).getName()); return convertView; } static final class ViewHolder { TextView textView; } } }