package yuku.alkitab.base.ac;
import android.app.LoaderManager;
import android.content.AsyncTaskLoader;
import android.content.Intent;
import android.content.Loader;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.TextView;
import yuku.afw.App;
import yuku.afw.V;
import yuku.alkitab.base.S;
import yuku.alkitab.base.ac.base.BaseActivity;
import yuku.alkitab.base.util.SongBookUtil;
import yuku.alkitab.base.util.SongFilter;
import yuku.alkitab.debug.R;
import yuku.alkitab.model.SongInfo;
import java.util.ArrayList;
import java.util.List;
/*
* Everytime we want to do a search, make sure 3 things:
* 1. setProgressBarIndeterminateVisibility(true);
* 2. set new search params
* 3. loader.forceLoad()
*/
public class SongListActivity extends BaseActivity {
public static final String TAG = SongListActivity.class.getSimpleName();
private static final String EXTRA_bookName = "bookName";
private static final String EXTRA_code = "code";
private static final String EXTRA_searchState = "searchState";
SearchView searchView;
ListView lsSong;
TextView bChangeBook;
CheckBox cDeepSearch;
View panelFilter;
View circular_progress;
SongAdapter adapter;
SongLoader loader;
PopupMenu popupChangeBook;
boolean stillUsingInitialSearchState = false;
public static class Result {
public String bookName;
public String code;
public SearchState last_searchState;
}
public static class SearchState implements Parcelable {
public String filter_string;
public List<SongInfo> result;
public int selectedPosition;
public String bookName;
public boolean deepSearch;
public SearchState(String filter_string, List<SongInfo> result, int selectedPosition, String bookName, boolean deepSearch) {
this.filter_string = filter_string;
this.result = result;
this.selectedPosition = selectedPosition;
this.bookName = bookName;
this.deepSearch = deepSearch;
}
SearchState(Parcel in) {
filter_string = in.readString();
in.readList(result = new ArrayList<>(), ((Object) this).getClass().getClassLoader());
selectedPosition = in.readInt();
bookName = in.readString();
deepSearch = in.readByte() != 0;
}
@Override public void writeToParcel(Parcel dest, int flags) {
dest.writeString(filter_string);
dest.writeList(result);
dest.writeInt(selectedPosition);
dest.writeString(bookName);
dest.writeByte((byte) (deepSearch? 1: 0));
}
@Override public int describeContents() {
return 0;
}
public static final Creator<SearchState> CREATOR = new Creator<SearchState>() {
@Override public SearchState createFromParcel(Parcel in) {
return new SearchState(in);
}
@Override public SearchState[] newArray(int size) {
return new SearchState[size];
}
};
}
public static Intent createIntent(@Nullable SearchState searchState_optional) {
Intent res = new Intent(App.context, SongListActivity.class);
if (searchState_optional != null) res.putExtra(EXTRA_searchState, searchState_optional);
return res;
}
public static Result obtainResult(Intent data) {
if (data == null) return null;
Result res = new Result();
res.bookName = data.getStringExtra(EXTRA_bookName);
res.code = data.getStringExtra(EXTRA_code);
res.last_searchState = data.getParcelableExtra(EXTRA_searchState);
return res;
}
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_song_list);
circular_progress = V.get(this, R.id.progress_circular);
final Toolbar toolbar = V.get(this, R.id.toolbar);
setSupportActionBar(toolbar);
final ActionBar ab = getSupportActionBar();
assert ab != null;
ab.setDisplayHomeAsUpEnabled(true);
searchView = V.get(this, R.id.searchView);
lsSong = V.get(this, R.id.lsSong);
bChangeBook = V.get(this, R.id.bChangeBook);
cDeepSearch = V.get(this, R.id.cDeepSearch);
panelFilter = V.get(this, R.id.panelFilter);
searchView.setSubmitButtonEnabled(false);
searchView.setOnQueryTextListener(searchWidget_queryText);
lsSong.setAdapter(adapter = new SongAdapter());
lsSong.setOnItemClickListener(lsSong_itemClick);
popupChangeBook = SongBookUtil.getSongBookPopupMenu(this, true, false, searchView);
popupChangeBook.setOnMenuItemClickListener(SongBookUtil.getSongBookOnMenuItemClickListener(songBookSelected));
bChangeBook.setOnClickListener(v -> popupChangeBook.show());
cDeepSearch.setOnCheckedChangeListener((buttonView, isChecked) -> startSearch());
loader = new SongLoader();
// initial
bChangeBook.setText(R.string.sn_bookselector_all);
SearchState searchState = getIntent().getParcelableExtra(EXTRA_searchState);
if (searchState != null) {
stillUsingInitialSearchState = true; { // prevent triggering
searchView.setQuery(searchState.filter_string, false);
adapter.setData(searchState.result);
cDeepSearch.setChecked(searchState.deepSearch);
lsSong.setSelection(searchState.selectedPosition);
loader.setSelectedBookName(searchState.bookName);
if (searchState.bookName == null) {
bChangeBook.setText(R.string.sn_bookselector_all);
} else {
bChangeBook.setText(SongBookUtil.escapeSongBookName(searchState.bookName));
}
} stillUsingInitialSearchState = false;
setCustomProgressBarIndeterminateVisible(false); // somehow this is needed.
} else {
startSearch();
}
getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<List<SongInfo>>() {
@Override public Loader<List<SongInfo>> onCreateLoader(int id, Bundle args) {
return loader;
}
@Override public void onLoadFinished(Loader<List<SongInfo>> loader, List<SongInfo> data) {
adapter.setData(data);
setCustomProgressBarIndeterminateVisible(false);
}
@Override public void onLoaderReset(Loader<List<SongInfo>> loader) {
adapter.setData(null);
setCustomProgressBarIndeterminateVisible(false);
}
});
}
void startSearch() {
if (stillUsingInitialSearchState) return;
setCustomProgressBarIndeterminateVisible(true);
loader.setFilterString(searchView.getQuery().toString());
loader.setDeepSearch(cDeepSearch.isChecked());
loader.forceLoad();
}
void startSearchSettingBookName(String selectedBookName) {
loader.setSelectedBookName(selectedBookName);
startSearch();
}
final SongBookUtil.OnSongBookSelectedListener songBookSelected = new SongBookUtil.DefaultOnSongBookSelectedListener() {
@Override
public void onAllSelected() {
bChangeBook.setText(R.string.sn_bookselector_all);
startSearchSettingBookName(null);
}
@Override
public void onSongBookSelected(final String name) {
bChangeBook.setText(SongBookUtil.escapeSongBookName(name));
startSearchSettingBookName(name);
}
};
private AdapterView.OnItemClickListener lsSong_itemClick = new AdapterView.OnItemClickListener() {
@Override public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
SongInfo songInfo = adapter.getItem(position);
Intent data = new Intent();
data.putExtra(EXTRA_bookName, songInfo.bookName);
data.putExtra(EXTRA_code, songInfo.code);
// do not pass to Binder more than 1000 songs, because it might exceed Binder data limit
final List<SongInfo> adapterData = adapter.getData();
if (adapterData.size() <= 1000) {
data.putExtra(EXTRA_searchState, new SearchState(searchView.getQuery().toString(), adapterData, position, loader.getSelectedBookName(), cDeepSearch.isChecked()));
}
setResult(RESULT_OK, data);
finish();
}
};
private SearchView.OnQueryTextListener searchWidget_queryText = new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(final String query) {
startSearch();
return true;
}
@Override
public boolean onQueryTextChange(final String newText) {
startSearch();
return true;
}
};
public class SongAdapter extends BaseAdapter {
List<SongInfo> list;
@Override public int getCount() {
return list == null? 0: list.size();
}
public List<SongInfo> getData() {
return this.list;
}
public void setData(List<SongInfo> data) {
this.list = data;
notifyDataSetChanged();
}
@Override public SongInfo getItem(int position) {
return list.get(position);
}
@Override public long getItemId(int position) {
return position;
}
@Override public View getView(int position, View convertView, ViewGroup parent) {
View res = convertView != null? convertView: getLayoutInflater().inflate(R.layout.item_song, parent, false);
TextView lTitle = V.get(res, R.id.lTitle);
TextView lTitleOriginal = V.get(res, R.id.lTitleOriginal);
TextView lBookName = V.get(res, R.id.lBookName);
SongInfo songInfo = getItem(position);
lTitle.setText(songInfo.code + ". " + songInfo.title);
if (songInfo.title_original != null) {
lTitleOriginal.setVisibility(View.VISIBLE);
lTitleOriginal.setText(songInfo.title_original);
} else {
lTitleOriginal.setVisibility(View.GONE);
}
lBookName.setText(SongBookUtil.escapeSongBookName(songInfo.bookName));
return res;
}
}
static class SongLoader extends AsyncTaskLoader<List<SongInfo>> {
public static final String TAG = SongLoader.class.getSimpleName();
private String filter_string;
private String selectedBookName;
private boolean deepSearch;
public SongLoader() {
super(App.context);
}
public void setDeepSearch(boolean deepSearch) {
this.deepSearch = deepSearch;
}
public void setFilterString(String s) {
if (TextUtils.isEmpty(s) || s.trim().length() == 0) {
filter_string = null;
} else {
filter_string = s.trim();
}
}
public String getSelectedBookName() {
return selectedBookName;
}
public void setSelectedBookName(String bookName) {
this.selectedBookName = bookName;
}
@Override public List<SongInfo> loadInBackground() {
List<SongInfo> res;
if (!deepSearch) {
List<SongInfo> songInfos = S.getSongDb().listSongInfosByBookName(getSelectedBookName());
res = SongFilter.filterSongInfosByString(songInfos, filter_string);
} else {
res = S.getSongDb().listSongInfosByBookNameAndDeepFilter(getSelectedBookName(), filter_string);
}
return res;
}
}
void setCustomProgressBarIndeterminateVisible(final boolean visible) {
circular_progress.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
}
}