/*
* Copyright 2016 Gleb Godonoga.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.andrada.sitracker.ui;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.SearchManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.IntentCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.SearchView;
import android.widget.Spinner;
import com.andrada.sitracker.Constants;
import com.andrada.sitracker.R;
import com.andrada.sitracker.analytics.AnalyticsManager;
import com.andrada.sitracker.contracts.AppUriContract;
import com.andrada.sitracker.ui.fragment.RemoteAuthorsFragment;
import com.github.amlcurran.showcaseview.ShowcaseView;
import com.github.amlcurran.showcaseview.targets.ViewTarget;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.FragmentById;
import org.androidannotations.annotations.InstanceState;
import org.androidannotations.annotations.OptionsMenu;
import java.util.ArrayList;
import java.util.List;
import static com.andrada.sitracker.util.LogUtils.LOGD;
import static com.andrada.sitracker.util.LogUtils.LOGW;
import static com.andrada.sitracker.util.LogUtils.makeLogTag;
@SuppressLint("Registered")
@EActivity(R.layout.activity_search)
@OptionsMenu(R.menu.search_menu)
public class SearchActivity extends BaseActivity {
private static final String TAG = makeLogTag(SearchActivity.class);
@FragmentById(R.id.remote_authors_fragment)
RemoteAuthorsFragment mAuthorsFragment;
SearchView mSearchView = null;
@InstanceState
String mQuery = "";
@InstanceState
int mCurrentSearchType = 0;
@AfterViews
protected void afterViews() {
super.afterViews();
Toolbar toolbar = getActionBarToolbar();
toolbar.setTitle(R.string.title_search);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss(true);
}
});
String query = getIntent().getStringExtra(SearchManager.QUERY);
if (query == null && mQuery != null) {
query = mQuery;
}
mQuery = query;
if (mSearchView != null) {
mSearchView.setQuery(query, false);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
doEnterAnim();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
overridePendingTransition(0, 0);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
populateSearchVariants();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
final MenuItem searchItem = menu.findItem(R.id.action_search);
if (searchItem != null) {
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
final SearchView view = (SearchView) MenuItemCompat.getActionView(searchItem);
mSearchView = view;
if (view == null) {
LOGW(TAG, "Could not set up search view, view is null.");
} else {
view.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
view.setIconified(false);
view.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
view.clearFocus();
if (mAuthorsFragment != null) {
mAuthorsFragment.requestQueryUpdate(s, mCurrentSearchType);
}
return true;
}
@Override
public boolean onQueryTextChange(String s) {
mQuery = s;
return true;
}
});
view.setOnCloseListener(new SearchView.OnCloseListener() {
@Override
public boolean onClose() {
dismiss(false);
return false;
}
});
new ShowcaseView.Builder(this)
.setTarget(new ViewTarget(mSearchView))
.setContentTitle(getString(R.string.showcase_search_title))
.setContentText(getString(R.string.showcase_search_detail))
.setStyle(R.style.ShowcaseView_Base)
.singleShot(Constants.SHOWCASE_ADD_AUTHORS_SEARCH_SHOT_ID).build();
if (!TextUtils.isEmpty(mQuery)) {
view.setQuery(mQuery, false);
}
}
}
return true;
}
@Override
public void onBackPressed() {
dismiss(true);
}
public void dismiss(boolean navigateUp) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
doExitAnim(navigateUp);
} else {
ActivityCompat.finishAfterTransition(this);
}
}
/**
* On Lollipop+ perform a circular reveal animation (an expanding circular mask) when showing
* the search panel.
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void doEnterAnim() {
// Fade in a background scrim as this is a floating window. We could have used a
// translucent window background but this approach allows us to turn off window animation &
// overlap the fade with the reveal animation – making it feel snappier.
View scrim = findViewById(R.id.scrim);
scrim.animate()
.alpha(1f)
.setDuration(500L)
.setInterpolator(
AnimationUtils.loadInterpolator(this, android.R.interpolator.fast_out_slow_in))
.start();
// Next perform the circular reveal on the search panel
final View searchPanel = findViewById(R.id.fragment_container);
if (searchPanel != null) {
// We use a view tree observer to set this up once the view is measured & laid out
searchPanel.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
searchPanel.getViewTreeObserver().removeOnPreDrawListener(this);
// As the height will change once the initial suggestions are delivered by the
// loader, we can't use the search panels height to calculate the final radius
// so we fall back to it's parent to be safe
int revealRadius = ((ViewGroup) searchPanel.getParent()).getHeight();
// Center the animation on the top right of the panel i.e. near to the
// search button which launched this screen.
Animator show = ViewAnimationUtils.createCircularReveal(searchPanel,
searchPanel.getRight(), searchPanel.getTop(), 0f, revealRadius);
show.setDuration(250L);
show.setInterpolator(AnimationUtils.loadInterpolator(SearchActivity.this,
android.R.interpolator.fast_out_slow_in));
show.start();
return false;
}
});
}
}
/**
* On Lollipop+ perform a circular animation (a contracting circular mask) when hiding the
* search panel.
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void doExitAnim(final boolean navigateUp) {
final View searchPanel = findViewById(R.id.fragment_container);
// Center the animation on the top right of the panel i.e. near to the search button which
// launched this screen. The starting radius therefore is the diagonal distance from the top
// right to the bottom left
int revealRadius = (int) Math.sqrt(Math.pow(searchPanel.getWidth(), 2)
+ Math.pow(searchPanel.getHeight(), 2));
// Animating the radius to 0 produces the contracting effect
Animator shrink = ViewAnimationUtils.createCircularReveal(searchPanel,
searchPanel.getRight(), searchPanel.getTop(), revealRadius, 0f);
shrink.setDuration(200L);
shrink.setInterpolator(AnimationUtils.loadInterpolator(SearchActivity.this,
android.R.interpolator.fast_out_slow_in));
shrink.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
searchPanel.setVisibility(View.INVISIBLE);
if (navigateUp) {
navigateUpToFromChild(SearchActivity.this,
IntentCompat.makeMainActivity(new ComponentName(SearchActivity.this,
SiMainActivity_.class)));
} else {
ActivityCompat.finishAfterTransition(SearchActivity.this);
}
}
});
shrink.start();
// We also animate out the translucent background at the same time.
findViewById(R.id.scrim).animate()
.alpha(0f)
.setDuration(200L)
.setInterpolator(
AnimationUtils.loadInterpolator(SearchActivity.this,
android.R.interpolator.fast_out_slow_in))
.start();
}
@Override
protected void onNewIntent(Intent intent) {
LOGD(TAG, "SearchActivity.onNewIntent: " + intent);
setIntent(intent);
String query = intent.getStringExtra(SearchManager.QUERY);
Bundle args = intentToFragmentArguments(
new Intent(Intent.ACTION_VIEW, AppUriContract.buildSamlibSearchUri(query, 0)));
if (mAuthorsFragment != null) {
mAuthorsFragment.reloadFromArguments(args);
}
}
private void populateSearchVariants() {
Spinner searchOptionSpinner = (Spinner) findViewById(R.id.search_option_spinner);
if (searchOptionSpinner != null) {
List<String> items = new ArrayList<String>();
items.add(getString(R.string.search_type_name));
items.add(getString(R.string.search_type_keyword));
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.search_spinner_item,
android.R.id.text1, items);
adapter.setDropDownViewResource(R.layout.search_spinner_item_dropdown);
searchOptionSpinner.setAdapter(adapter);
searchOptionSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
if (position >= 0 && position < 2) {
onSearchTypeSelected(position);
}
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
if (mCurrentSearchType > 0) {
searchOptionSpinner.setSelection(mCurrentSearchType);
}
}
}
private void onSearchTypeSelected(int position) {
if (mCurrentSearchType == position) {
return;
}
mCurrentSearchType = position;
if (mAuthorsFragment != null && !TextUtils.isEmpty(mQuery)) {
if (mSearchView != null) {
mSearchView.clearFocus();
}
mAuthorsFragment.requestQueryUpdate(mQuery, mCurrentSearchType);
}
}
}