package org.fdroid.fdroid.views.fragments;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.compat.ArrayAdapterCompat;
import org.fdroid.fdroid.compat.CursorAdapterCompat;
import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.CategoryProvider;
import org.fdroid.fdroid.views.AppListAdapter;
import org.fdroid.fdroid.views.AvailableAppListAdapter;
import java.util.ArrayList;
import java.util.List;
public class AvailableAppsFragment extends AppListFragment implements
LoaderManager.LoaderCallbacks<Cursor> {
private static final String TAG = "AvailableAppsFragment";
private static final String PREFERENCES_FILE = "CategorySpinnerPosition";
private static final String CATEGORY_KEY = "Selection";
private static String defaultCategory;
private List<String> categories;
@Nullable
private View categoryWrapper;
@Nullable
private Spinner categorySpinner;
private String currentCategory;
private AppListAdapter adapter;
@Override
protected String getFromTitle() {
return getString(R.string.tab_available_apps);
}
@Override
protected AppListAdapter getAppListAdapter() {
if (adapter == null) {
final AppListAdapter a = AvailableAppListAdapter.create(getActivity(), null, CursorAdapterCompat.FLAG_AUTO_REQUERY);
Preferences.get().registerUpdateHistoryListener(new Preferences.ChangeListener() {
@Override
public void onPreferenceChange() {
a.notifyDataSetChanged();
}
});
adapter = a;
}
return adapter;
}
private class CategoryObserver extends ContentObserver {
private final ArrayAdapter<String> adapter;
CategoryObserver(ArrayAdapter<String> adapter) {
// Using Looper.getMainLooper() ensures that the onChange method is run on the main thread.
super(new Handler(Looper.getMainLooper()));
this.adapter = adapter;
}
@Override
public void onChange(boolean selfChange) {
final Activity activity = getActivity();
if (!isAdded() || adapter == null || activity == null) {
return;
}
// Because onChange is always invoked on the main thread (see constructor), we want to
// run the database query on a background thread. Afterwards, the UI is updated
// on a foreground thread.
new AsyncTask<Void, Void, List<String>>() {
@Override
protected List<String> doInBackground(Void... params) {
return CategoryProvider.Helper.categories(activity);
}
@Override
protected void onPostExecute(List<String> loadedCategories) {
adapter.clear();
categories = loadedCategories;
ArrayAdapterCompat.addAll(adapter, translateCategories(activity, loadedCategories));
}
}.execute();
}
@Override
public void onChange(boolean selfChange, Uri uri) {
onChange(selfChange);
}
}
/**
* Attempt to translate category names with fallback to default name if no translation available
*/
private static List<String> translateCategories(Context context, List<String> categories) {
List<String> translatedCategories = new ArrayList<>(categories.size());
Resources res = context.getResources();
String pkgName = context.getPackageName();
for (String category : categories) {
String resId = category.replace(" & ", "_").replace(" ", "_").replace("'", "");
int id = res.getIdentifier("category_" + resId, "string", pkgName);
translatedCategories.add(id == 0 ? category : context.getString(id));
}
return translatedCategories;
}
private Spinner setupCategorySpinner(Spinner spinner) {
categorySpinner = spinner;
categorySpinner.setId(R.id.category_spinner);
categories = CategoryProvider.Helper.categories(getActivity());
ArrayAdapter<String> adapter = new ArrayAdapter<>(
getActivity(), android.R.layout.simple_spinner_item, translateCategories(getActivity(), categories));
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
categorySpinner.setAdapter(adapter);
getActivity().getContentResolver().registerContentObserver(
AppProvider.getContentUri(), false, new CategoryObserver(adapter));
categorySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
getListView().setSelection(0);
setCurrentCategory(categories.get(pos));
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
setCurrentCategory(null);
}
});
return categorySpinner;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.available_app_list, container, false);
categoryWrapper = view.findViewById(R.id.category_wrapper);
setupCategorySpinner((Spinner) view.findViewById(R.id.category_spinner));
defaultCategory = CategoryProvider.Helper.getCategoryWhatsNew(getActivity());
return view;
}
@Override
protected Uri getDataUri() {
if (currentCategory == null || currentCategory.equals(CategoryProvider.Helper.getCategoryAll(getActivity()))) {
return AppProvider.getContentUri();
}
if (currentCategory.equals(CategoryProvider.Helper.getCategoryRecentlyUpdated(getActivity()))) {
return AppProvider.getRecentlyUpdatedUri();
}
if (currentCategory.equals(CategoryProvider.Helper.getCategoryWhatsNew(getActivity()))) {
return AppProvider.getNewlyAddedUri();
}
return AppProvider.getCategoryUri(currentCategory);
}
@Override
protected Uri getDataUri(String query) {
return AppProvider.getSearchUri(query);
}
@Override
protected int getEmptyMessage() {
return R.string.empty_available_app_list;
}
@Override
protected int getNoSearchResultsMessage() {
return R.string.empty_search_available_app_list;
}
private void setCurrentCategory(String category) {
currentCategory = category;
Utils.debugLog(TAG, "Category '" + currentCategory + "' selected.");
getLoaderManager().restartLoader(0, null, this);
}
@Override
public void onResume() {
/* restore the saved Category Spinner position */
Activity activity = getActivity();
SharedPreferences p = activity.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE);
currentCategory = p.getString(CATEGORY_KEY, defaultCategory);
if (categorySpinner != null) {
for (int i = 0; i < categorySpinner.getCount(); i++) {
if (currentCategory.equals(categorySpinner.getItemAtPosition(i).toString())) {
categorySpinner.setSelection(i);
break;
}
}
}
setCurrentCategory(currentCategory);
super.onResume();
}
@Override
public void onPause() {
super.onPause();
/* store the Category Spinner position for when we come back */
SharedPreferences p = getActivity().getSharedPreferences(PREFERENCES_FILE,
Context.MODE_PRIVATE);
SharedPreferences.Editor e = p.edit();
e.putString(CATEGORY_KEY, currentCategory);
e.apply();
}
@Override
protected void onSearch() {
if (categoryWrapper != null) {
categoryWrapper.setVisibility(View.GONE);
}
}
@Override
protected void onSearchStopped() {
if (categoryWrapper != null) {
categoryWrapper.setVisibility(View.VISIBLE);
}
}
}