Java tutorial
/* This file is part of the Android Clementine Remote. * Copyright (C) 2013, Andreas Muttscheller <asfa194@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.qspool.clementineremote.ui.fragments; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Fragment; import android.content.SharedPreferences; import android.graphics.drawable.ColorDrawable; import android.os.Build; import android.os.Bundle; import android.os.Message; import android.support.v4.content.ContextCompat; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SearchView; import android.util.SparseBooleanArray; import android.view.ActionMode; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import java.util.LinkedList; import de.qspool.clementineremote.App; import de.qspool.clementineremote.R; import de.qspool.clementineremote.SharedPreferencesKeys; import de.qspool.clementineremote.backend.database.SongSelectItem; import de.qspool.clementineremote.backend.globalsearch.GlobalSearchManager; import de.qspool.clementineremote.backend.globalsearch.GlobalSearchQuery; import de.qspool.clementineremote.backend.listener.OnGlobalSearchResponseListener; import de.qspool.clementineremote.backend.listener.OnSongSelectFinishedListener; import de.qspool.clementineremote.backend.pb.ClementineMessage; import de.qspool.clementineremote.backend.pb.ClementineMessageFactory; import de.qspool.clementineremote.backend.pb.ClementineRemoteProtocolBuffer; import de.qspool.clementineremote.ui.adapter.DynamicSongQueryAdapter; import de.qspool.clementineremote.ui.interfaces.BackPressHandleable; import de.qspool.clementineremote.ui.interfaces.RemoteDataReceiver; public class GlobalSearchFragment extends Fragment implements BackPressHandleable, RemoteDataReceiver, SharedPreferences.OnSharedPreferenceChangeListener, OnGlobalSearchResponseListener { private ActionBar mActionBar; private SwipeRefreshLayout mSwipeRefreshLayout; private SwipeRefreshLayout mEmptyView; private TextView mEmptyText; private ListView mList; private LinkedList<DynamicSongQueryAdapter> mAdapters = new LinkedList<>(); private int mMaxLevels; private int mQueryId; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Get the actionbar mActionBar = ((AppCompatActivity) getActivity()).getSupportActionBar(); setHasOptionsMenu(true); } @SuppressLint({ "InlinedApi", "NewApi" }) @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_global_search, container, false); mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.global_search_refresh_layout); mEmptyView = (SwipeRefreshLayout) view.findViewById(R.id.global_search_empty); mSwipeRefreshLayout.setColorSchemeResources(R.color.orange); mEmptyView.setColorSchemeResources(R.color.orange); mSwipeRefreshLayout.setEnabled(true); mEmptyView.setEnabled(true); mEmptyText = (TextView) view.findViewById(R.id.global_search_empty_txt); mList = (ListView) view.findViewById(R.id.global_search); mList.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { SongSelectItem item = mAdapters.getLast().getItem(position); if (item.getLevel() == mMaxLevels - 1) { Message msg = Message.obtain(); LinkedList<ClementineRemoteProtocolBuffer.SongMetadata> songs = new LinkedList<>(); songs.add(GlobalSearchManager.getInstance().getRequest().getSongFromUrl(item.getUrl())); msg.obj = ClementineMessageFactory .buildInsertSongs(App.Clementine.getPlaylistManager().getActivePlaylistId(), songs); App.ClementineConnection.mHandler.sendMessage(msg); String text = getActivity().getResources().getQuantityString(R.plurals.songs_added, 1, 1); Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show(); } else { GlobalSearchQuery globalSearchQuery = new GlobalSearchQuery(getActivity(), mQueryId); globalSearchQuery.openDatabase(); globalSearchQuery.setLevel(mAdapters.size()); globalSearchQuery.setSelection(item.getSelection()); mAdapters.add(new DynamicSongQueryAdapter(getActivity(), globalSearchQuery)); showList(); } } }); mList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); mList.setMultiChoiceModeListener(new MultiChoiceModeListener() { @Override public boolean onActionItemClicked(ActionMode mode, android.view.MenuItem item) { SparseBooleanArray checkedPositions = mList.getCheckedItemPositions(); final LinkedList<SongSelectItem> selectedItems = new LinkedList<>(); for (int i = 0; i < checkedPositions.size(); ++i) { int position = checkedPositions.keyAt(i); if (checkedPositions.valueAt(i)) { selectedItems.add(mAdapters.getLast().getItem(position)); } } for (SongSelectItem songItem : selectedItems) { OnSongSelectFinishedListener listener; switch (item.getItemId()) { case R.id.global_search_context_add: listener = new OnSongSelectFinishedListener() { @Override public void OnSongSelectFinished(LinkedList<SongSelectItem> l) { addSongsToPlaylist(l); } }; break; default: return false; } queryItems(songItem, listener); } mode.finish(); return true; } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.global_search_context_menu, menu); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { getActivity().getWindow() .setStatusBarColor(ContextCompat.getColor(getActivity(), R.color.grey_cab_status)); } return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public void onDestroyActionMode(ActionMode mode) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { getActivity().getWindow() .setStatusBarColor(ContextCompat.getColor(getActivity(), R.color.actionbar_dark)); } } @Override public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { } }); GlobalSearchManager.getInstance().addOnGlobalSearchResponseListerner(this); setHasOptionsMenu(true); mActionBar.setTitle(""); mActionBar.setSubtitle("/"); return view; } @Override public void onDestroyView() { super.onDestroyView(); GlobalSearchManager.getInstance().removeOnGlobalSearchResponseListerner(this); hideSoftInput(); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { menu.clear(); inflater.inflate(R.menu.global_search_menu, menu); // Create a listener for search change final MenuItem search = menu.findItem(R.id.global_search_menu_search); final SearchView searchView = (SearchView) search.getActionView(); searchView.setIconifiedByDefault(true); searchView.setIconified(false); final SearchView.OnQueryTextListener queryTextListener = new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextChange(String newText) { return false; } @Override public boolean onQueryTextSubmit(String query) { mSwipeRefreshLayout.setRefreshing(true); mEmptyView.setRefreshing(true); Message msg = Message.obtain(); msg.obj = ClementineMessageFactory.buildGlobalSearch(query); App.ClementineConnection.mHandler.sendMessage(msg); hideSoftInput(); // Set the actionbar title mActionBar.setTitle(getResources().getString(R.string.global_search_query, query)); mActionBar.setSubtitle("/"); // Query must be empty in order to collapse the search view. searchView.setQuery("", false); searchView.setIconified(true); // Remove currently present adapters mAdapters.clear(); showList(); return true; } }; searchView.setOnQueryTextListener(queryTextListener); searchView.setQueryHint(getString(R.string.global_search_search)); EditText searchText = (EditText) searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text); searchText.setHintTextColor(ContextCompat.getColor(getActivity(), R.color.searchview_edittext_hint)); super.onCreateOptionsMenu(menu, inflater); } private void hideSoftInput() { InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); View v = getActivity().getCurrentFocus(); if (v != null) { imm.hideSoftInputFromWindow(v.getWindowToken(), 0); } } @Override public void onViewCreated(final View view, final Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mList.setFastScrollEnabled(true); mList.setTextFilterEnabled(true); mList.setSelector(new ColorDrawable(ContextCompat.getColor(getActivity(), android.R.color.transparent))); mList.setDivider(null); mList.setDividerHeight(0); mList.setEmptyView(mEmptyView); } @Override public void MessageFromClementine(ClementineMessage clementineMessage) { } @Override public boolean onBackPressed() { // When we have only one item left, just use the normal back behavior if (mAdapters.size() <= 1) { return false; } // Remove the last element and show the new list mAdapters.removeLast(); showList(); return true; } @Override public void onStatusChanged(final int id, final ClementineRemoteProtocolBuffer.GlobalSearchStatus status) { getActivity().runOnUiThread(new Runnable() { @Override public void run() { if (status == ClementineRemoteProtocolBuffer.GlobalSearchStatus.GlobalSearchFinished) { mQueryId = id; GlobalSearchQuery globalSearchQuery = new GlobalSearchQuery(getActivity(), mQueryId); mMaxLevels = globalSearchQuery.getMaxLevels(); mAdapters.clear(); // Create the adapter globalSearchQuery.openDatabase(); globalSearchQuery.setLevel(0); DynamicSongQueryAdapter a = new DynamicSongQueryAdapter(getActivity(), globalSearchQuery); mAdapters.add(a); showList(); mEmptyView.setRefreshing(false); mSwipeRefreshLayout.setRefreshing(false); } } }); } @Override public void onResultsReceived(int id) { } /** * Show the last element in the list of adapters */ private void showList() { if (mAdapters.isEmpty() || mAdapters.getLast().isEmpty()) { mList.setEmptyView(mEmptyView); } else { DynamicSongQueryAdapter adapter = mAdapters.getLast(); mList.setAdapter(adapter); if (adapter.isEmpty()) { mActionBar.setSubtitle("/ "); } else { SongSelectItem item = adapter.getItem(0); StringBuilder sb = new StringBuilder(); sb.append("/ "); for (int i = 0; i < mAdapters.size() - 1; i++) { sb.append(item.getSelection()[i]); if (i < mAdapters.size() - 2) sb.append(" / "); } mActionBar.setSubtitle(sb.toString()); } } } private void queryItems(SongSelectItem item, OnSongSelectFinishedListener onSongSelectFinishedListener) { if (item.getLevel() == mMaxLevels - 1) { LinkedList<SongSelectItem> result = new LinkedList<>(); result.add(item); onSongSelectFinishedListener.OnSongSelectFinished(result); } else { GlobalSearchQuery globalSearchQuery = new GlobalSearchQuery(getActivity(), mQueryId); globalSearchQuery.openDatabase(); globalSearchQuery.setLevel(mMaxLevels - 1); globalSearchQuery.setSelection(item.getSelection()); globalSearchQuery.addOnLibrarySelectFinishedListener(onSongSelectFinishedListener); globalSearchQuery.selectDataAsync(); } } private void addSongsToPlaylist(LinkedList<SongSelectItem> l) { Message msg = Message.obtain(); LinkedList<ClementineRemoteProtocolBuffer.SongMetadata> songs = new LinkedList<>(); for (SongSelectItem item : l) { songs.add(GlobalSearchManager.getInstance().getRequest().getSongFromUrl(item.getUrl())); } msg.obj = ClementineMessageFactory .buildInsertSongs(App.Clementine.getPlaylistManager().getActivePlaylistId(), songs); App.ClementineConnection.mHandler.sendMessage(msg); String text = getActivity().getResources().getQuantityString(R.plurals.songs_added, songs.size(), songs.size()); Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show(); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals(SharedPreferencesKeys.SP_LIBRARY_GROUPING) || key.equals(SharedPreferencesKeys.SP_LIBRARY_SORTING)) { mAdapters.clear(); showList(); } } }