public class SuggestionsAdapter extends BaseAdapter<String> {

    // region Static Variables
    private static String currentQuery = "";
    private static Typeface font;
    // endregion

    // region Member Variables
    private OnItemLongClickListener onItemLongClickListener;
    private OnSearchSuggestionCompleteClickListener onSearchSuggestionCompleteClickListener;
    // endregion

    // region Interfaces
    public interface OnItemLongClickListener {
        void onItemLongClick(int position, View view);
    }

    public interface OnSearchSuggestionCompleteClickListener {
        void onSearchSuggestionCompleteClickListener(int position, TextView textView);
    }
    // endregion

    // region Constructors
    public SuggestionsAdapter() {
        super();
        font = FontCache.getTypeface("Ubuntu-Bold.ttf", LoopApplication.getInstance().getApplicationContext());
    }
    // endregion

    @Override
    public int getItemViewType(int position) {
        return ITEM;
    }

    @Override
    protected RecyclerView.ViewHolder createHeaderViewHolder(ViewGroup parent) {
        return null;
    }

    @Override
    protected RecyclerView.ViewHolder createItemViewHolder(ViewGroup parent) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.suggestion, parent, false);

        final SuggestionViewHolder holder = new SuggestionViewHolder(v);

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int adapterPos = holder.getAdapterPosition();
                if(adapterPos != RecyclerView.NO_POSITION){
                    if (onItemClickListener != null) {
                        onItemClickListener.onItemClick(adapterPos, holder.itemView);
                    }
                }
            }
        });

        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                int adapterPos = holder.getAdapterPosition();
                if(adapterPos != RecyclerView.NO_POSITION){
                    if (onItemLongClickListener != null) {
                        onItemLongClickListener.onItemLongClick(adapterPos, holder.itemView);
                    }
                }
                return true;
            }
        });

        holder.suggestionCompleteImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int adapterPos = holder.getAdapterPosition();
                if(adapterPos != RecyclerView.NO_POSITION){
                    if (onSearchSuggestionCompleteClickListener != null) {
                        onSearchSuggestionCompleteClickListener.onSearchSuggestionCompleteClickListener(adapterPos, holder.suggestionTextView);
                    }
                }
            }
        });

        return holder;
    }

    @Override
    protected RecyclerView.ViewHolder createFooterViewHolder(ViewGroup parent) {
        return null;
    }

    @Override
    protected void bindHeaderViewHolder(RecyclerView.ViewHolder viewHolder) {

    }

    @Override
    protected void bindItemViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
        final SuggestionViewHolder holder = (SuggestionViewHolder) viewHolder;

        final String suggestion = getItem(position);
        if (!TextUtils.isEmpty(suggestion)) {
            holder.bind(suggestion);
        }
    }

    @Override
    protected void bindFooterViewHolder(RecyclerView.ViewHolder viewHolder) {

    }

    @Override
    protected void displayLoadMoreFooter() {

    }

    @Override
    protected void displayErrorFooter() {

    }

    @Override
    public void addFooter() {

    }

    // region Helper Methods
    public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {
        this.onItemLongClickListener = onItemLongClickListener;
    }

    public void setOnSearchSuggestionCompleteClickListener(OnSearchSuggestionCompleteClickListener onSearchSuggestionCompleteClickListener) {
        this.onSearchSuggestionCompleteClickListener = onSearchSuggestionCompleteClickListener;
    }

    public void setCurrentQuery(String query){
        currentQuery = query;
    }
    // endregion

    // region Inner Classes

    public static class SuggestionViewHolder extends RecyclerView.ViewHolder {
        // region Views
        @BindView(R.id.suggestion_tv)
        TextView suggestionTextView;
        @BindView(R.id.search_suggest_complete_iv)
        ImageView suggestionCompleteImageView;
        // endregion

        // region Constructors
        public SuggestionViewHolder(View view) {
            super(view);
            ButterKnife.bind(this, view);
        }
        // endregion

        // region Helper Methods
        private void bind(String suggestion){
            setUpSuggestion(suggestionTextView, suggestion);
        }

        private void setUpSuggestion(TextView tv, String suggestion){
            if(!TextUtils.isEmpty(suggestion)){
                if(!TextUtils.isEmpty(currentQuery)){
                    CharSequence formattedSuggestion = Trestle.getFormattedText(
                            new Span.Builder(suggestion)
                                    .regex(new Regex(currentQuery, Regex.CASE_INSENSITIVE))
                                    .foregroundColor(ContextCompat.getColor(tv.getContext(), R.color.primary)) // Pass resolved color instead of resource id
                                    .typeface(font)
                                    .build());

                    tv.setText(formattedSuggestion);
                } else {
                    tv.setText(suggestion);
                }
            }
        }
        // endregion
    }

    // endregion

} public class RxBus {

    private static final PublishSubject<Object> bus = PublishSubject.create();
//    private static final BehaviorSubject<Object> bus = BehaviorSubject.create();


    // If multiple threads are going to emit events to this
    // then it must be made thread-safe like this instead
//    private final Subject<Object, Object> _bus = new SerializedSubject<>(PublishSubject.create());

    public void send(Object o) {
        bus.onNext(o);
    }

    public Observable<Object> toObserverable() {
        return bus;
    }

    public boolean hasObservers() {
        return bus.hasObservers();
    }

    public static RxBus getInstance() {
        return new RxBus();
    }

    private RxBus() {
        // No instances.
    }
} public class FilterClickedEvent {
} public class HideSearchSuggestionsEvent {

    // region Constructors
    public HideSearchSuggestionsEvent(){
    }
    // endregion
} public class LeftDrawableClickedEvent {

    private Type type;

    public LeftDrawableClickedEvent(Type type){
        this.type = type;
    }

    public Type getType() {
        return type;
    }

    public void setType(Type type) {
        this.type = type;
    }

    public enum Type {
        BACK,
        MENU,
        SEARCH
    }
} public class SearchPerformedEvent {

    // region Member Variables
    private String query;
    // endregion

    // region Constructors
    public SearchPerformedEvent(String query){
        this.query = query;
    }
    // endregion

    public String getQuery() {
        return query;
    }

    public void setQuery(String query) {
        this.query = query;
    }
} public class ShowSearchSuggestionsEvent {

    // region Member Variables
    private String query;
    // endregion

    // region Constructors
    public ShowSearchSuggestionsEvent(String query){
        this.query = query;
    }
    // endregion

    public String getQuery() {
        return query;
    }

    public void setQuery(String query) {
        this.query = query;
    }
} public class RealmUtility {

    public static void saveQuery(String query){
        Realm realm = Realm.getDefaultInstance();
        try {
            RealmSuggestion realmSuggestion = new RealmSuggestion();
            realmSuggestion.setToken(query);
            realmSuggestion.setTimestamp(new Date());
            realm.beginTransaction();
            // This will create a new one in Realm
            // realm.copyToRealm(obj);
            // This will update a existing one with the same id or create a new one instead
            realm.copyToRealmOrUpdate(realmSuggestion);

            realm.commitTransaction();
        } finally {
            realm.close();
        }
    }

    public static void deleteQuery(String query){
        Realm realm = Realm.getDefaultInstance();
        try {
            realm.beginTransaction();

            RealmSuggestion realmSuggestion
                    = realm.where(RealmSuggestion.class)
                    .equalTo("token", query)
                    .findFirst();

            if(realmSuggestion != null){
                realmSuggestion.deleteFromRealm();
            }

            realm.commitTransaction();
        } finally {
            realm.close();
        }
    }

    public static List<String> getSuggestions(String query) {
        List<String> suggestions = new ArrayList<>();

        Realm realm = Realm.getDefaultInstance();
        try {
            RealmResults<RealmSuggestion> realmResults
                    = realm.where(RealmSuggestion.class)
                    .contains("token", query)
                    .findAll();

            realmResults = realmResults.sort("timestamp", Sort.DESCENDING);

            if (realmResults != null) {
                int size = (realmResults.size() > 5) ? 5 : realmResults.size();
                for (int i = 0; i < size; i++) {
                    RealmSuggestion realmSuggestion = realmResults.get(i);
                    if (realmSuggestion != null) {
                        String token = realmSuggestion.getToken();
                        if (!TextUtils.isEmpty(token)) {
                            suggestions.add(suggestions.size(), token);
                        }
                    }
                }
            }
        } finally {
            realm.close();
        }

        return suggestions;
    }
} public class DisplayUtility {

    // region Utility Methods
    public static int dp2px(Context context, int dp) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();

        DisplayMetrics displaymetrics = new DisplayMetrics();
        display.getMetrics(displaymetrics);

        return (int) (dp * displaymetrics.density + 0.5f);
    }

    public static int px2dp(Context context, int px) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();

        DisplayMetrics displaymetrics = new DisplayMetrics();
        display.getMetrics(displaymetrics);

        return (int) (px / displaymetrics.density + 0.5f);
    }

    public static int getScreenWidth(Context context){
        Point size = new Point();
        ((Activity)context).getWindowManager().getDefaultDisplay().getSize(size);
        return size.x;
    }

    public static boolean isInLandscapeMode(Context context){
        boolean isLandscape = false;
        if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
            isLandscape =  true;
        }
        return isLandscape;
    }

    public static void hideKeyboard(Context context, View view) {
        if (context != null) {
            InputMethodManager inputMethodManager = (InputMethodManager) context.getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            if (inputMethodManager != null) {
                if (view != null) {
                    inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
                }
            }
        }
    }

    public static void showKeyboard(Context context, View view) {
        view.requestFocus();
        InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (inputMethodManager != null) {
            inputMethodManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
        }
    }

    public static int getPressedAvatarBackgroundColor(User user, Context context){
        int avatarBackgroundColor = 0;
        String name = user.getName();
        int hash = 7;
        int firstNameLength = name.length();
        for (int i = 0; i < firstNameLength; i++) {
            hash = hash*31 + name.charAt(i);
        }

        int modulo = Math.abs(hash) % 17;
        String[] avatarBgColors = context.getResources().getStringArray(R.array.pressed_avatar_bg_colors);
        avatarBackgroundColor = Color.parseColor(avatarBgColors[modulo]);
        return avatarBackgroundColor;
    }

    public static int getDefaultAvatarBackgroundColor(User user, Context context){
        int avatarBackgroundColor = 0;
        String name = user.getName();
        int hash = 7;
        int firstNameLength = name.length();
        for (int i = 0; i < firstNameLength; i++) {
            hash = hash*31 + name.charAt(i);
        }

        int modulo = Math.abs(hash) % 17;
        String[] avatarBgColors = context.getResources().getStringArray(R.array.default_avatar_bg_colors);
        avatarBackgroundColor = Color.parseColor(avatarBgColors[modulo]);
        return avatarBackgroundColor;
    }
    // endregion
} public class FontCache {

    private static Map<String, Typeface> fontCache = new HashMap<>(8);

    public static Typeface getTypeface(String fontname, Context context) {
        Typeface typeface = fontCache.get(fontname);

        if (typeface == null) {
            try {
                typeface = Typeface.createFromAsset(context.getAssets(), String.format("fonts/%s", fontname));
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }

            fontCache.put(fontname, typeface);
        }

        return typeface;
    }
} public class TrestleUtility {

    public static CharSequence getFormattedText(String text, Typeface font) {
        return Trestle.getFormattedText(
                new Span.Builder(text)
                        .typeface(font)
                        .build());
    }

    public static CharSequence getFormattedText(String text, Typeface font, int size) {
        return Trestle.getFormattedText(
                new Span.Builder(text)
                        .typeface(font)
                        .absoluteSize(size)
                        .build());
    }
}
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.etiennelawlor.loop.R;
import com.etiennelawlor.loop.adapters.SuggestionsAdapter;
import com.etiennelawlor.loop.bus.RxBus;
import com.etiennelawlor.loop.bus.events.FilterClickedEvent;
import com.etiennelawlor.loop.bus.events.HideSearchSuggestionsEvent;
import com.etiennelawlor.loop.bus.events.LeftDrawableClickedEvent;
import com.etiennelawlor.loop.bus.events.SearchPerformedEvent;
import com.etiennelawlor.loop.bus.events.ShowSearchSuggestionsEvent;
import com.etiennelawlor.loop.realm.RealmUtility;
import com.etiennelawlor.loop.utilities.DisplayUtility;
import com.etiennelawlor.loop.utilities.FontCache;
import com.etiennelawlor.loop.utilities.TrestleUtility;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnFocusChange;
import butterknife.OnTextChanged;
import de.hdodenhof.circleimageview.CircleImageView;
            }

            setUpLeftDrawable(false);
            setUpCardView();
            setUpHintText();
            setUpListeners();
        }
    }

    private void setUpCardView() {
        LayoutParams params = new LayoutParams(
                cardView.getLayoutParams());
        params.topMargin = marginTop;
        params.bottomMargin = marginBottom;
        params.leftMargin = marginLeft;
        params.rightMargin = marginRight;

        cardView.setLayoutParams(params);
    }

    private void setUpListeners() {
        searchEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {

                if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                    hideSearchSuggestions();
                    RxBus.getInstance().send(new SearchPerformedEvent(getQuery()));
                    return true;
                } else {
                    return false;
                }
            }
        });
    }

    private void setUpLeftDrawable(boolean showingSearchSuggestions) {
        if (showingSearchSuggestions) {
            leftDrawableImageView.setImageDrawable(ContextCompat.getDrawable(getContext(), R.drawable.ic_arrow_back_dark));
            leftDrawableRoundedImageView.setVisibility(View.GONE);
            leftDrawableImageView.setVisibility(View.VISIBLE);
        } else {
            switch (leftDrawableType) {
                case MENU:
                    leftDrawableImageView.setImageDrawable(ContextCompat.getDrawable(getContext(), R.drawable.ic_menu_dark));
                    break;
                case BACK:
                    leftDrawableImageView.setImageDrawable(ContextCompat.getDrawable(getContext(), R.drawable.ic_arrow_back_dark));
                    break;
                case SEARCH:
                    leftDrawableImageView.setImageDrawable(ContextCompat.getDrawable(getContext(), R.drawable.ic_search));
                    break;
                case AVATAR:
                    break;
                default:
                    break;
            }

            if (leftDrawableType == AVATAR) {
                leftDrawableImageView.setVisibility(View.GONE);
                leftDrawableRoundedImageView.setVisibility(View.VISIBLE);
            } else {
                leftDrawableRoundedImageView.setVisibility(View.GONE);
                leftDrawableImageView.setVisibility(View.VISIBLE);
            }
        }
    }

    public void setLeftDrawableType(int type) {
        leftDrawableType = type;
    }

    private void setUpHintText() {
        if (searchEditText != null)
            searchEditText.setHint(hintText);
    }

    private void showSearchSuggestions() {
        RxBus.getInstance().send(new ShowSearchSuggestionsEvent(getQuery()));

        suggestionsAdapter.setOnItemClickListener(this);
        suggestionsAdapter.setOnItemLongClickListener(this);
        suggestionsAdapter.setOnSearchSuggestionCompleteClickListener(this);

        CustomLinearLayoutManager layoutManager = new CustomLinearLayoutManager(getContext());
//        LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
        recyclerView.setLayoutManager(layoutManager);

        dividerItemDecoration = new DividerItemDecoration(ContextCompat.getDrawable(getContext(), R.drawable.divider));
        recyclerView.addItemDecoration(dividerItemDecoration);
//        recyclerView.setItemAnimator(new SlideInUpAnimator());
        recyclerView.setAdapter(suggestionsAdapter);

        if (!(suggestionsAdapter.isEmpty())) {
            recyclerView.setVisibility(View.VISIBLE);
            dividerView.setVisibility(View.VISIBLE);
        } else {
            recyclerView.setVisibility(View.GONE);
            dividerView.setVisibility(View.GONE);
        }

        backgroundCoverFrameLayout.setVisibility(View.VISIBLE);

        setUpLeftDrawable(true);

        areSearchSuggestionsVisible = true;
    }

    private void hideSearchSuggestions() {
        dividerView.setVisibility(View.GONE);
        backgroundCoverFrameLayout.setVisibility(View.GONE);

        setUpLeftDrawable(false);

        recyclerView.setVisibility(View.GONE);
        recyclerView.removeItemDecoration(dividerItemDecoration);

        searchEditText.clearFocus();
        areSearchSuggestionsVisible = false;

        RxBus.getInstance().send(new HideSearchSuggestionsEvent());