io.github.tjg1.nori.adapter.ServiceDropdownAdapter.java Source code

Java tutorial

Introduction

Here is the source code for io.github.tjg1.nori.adapter.ServiceDropdownAdapter.java

Source

/*
 * This file is part of nori.
 * Copyright (c) 2014-2016 Tomasz Jan Gralczyk <tomg@fastmail.uk>
 * License: GNU GPLv2
 */

package io.github.tjg1.nori.adapter;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Spinner;
import android.widget.TextView;

import java.util.List;

import io.github.tjg1.library.norilib.clients.SearchClient;
import io.github.tjg1.nori.APISettingsActivity;
import io.github.tjg1.nori.R;
import io.github.tjg1.nori.database.APISettingsDatabase;

/** Adapter populating the Search API picker in the ActionBar. */
public class ServiceDropdownAdapter extends BaseAdapter
        implements LoaderManager.LoaderCallbacks<List<Pair<Integer, SearchClient.Settings>>>,
        AdapterView.OnItemSelectedListener {

    //region Loader IDs
    /** Search client settings loader ID. */
    private static final int LOADER_ID_API_SETTINGS = 0x00;
    //endregion

    //region SharedPreferences keys
    /** Shared preference key used to store the last active {@link io.github.tjg1.library.norilib.clients.SearchClient}. */
    private static final String SHARED_PREFERENCE_LAST_SELECTED_INDEX = "io.github.tjg1.nori.SearchActivity.lastSelectedServiceIndex";
    //endregion

    //region Instance fields
    /** Context this adapter is used in. */
    private final Context context;
    /** Shared preferences of the application. */
    private final SharedPreferences sharedPreferences;
    /** Adapter view populated by this adapter. */
    private final AdapterView<?> adapterView;
    /** Listener used to interact with the {@link android.app.Activity} using this adapter. */
    private final ServiceDropdownAdapter.Listener listener;

    /** List of service settings loaded from {@link io.github.tjg1.nori.database.APISettingsDatabase}. */
    private List<Pair<Integer, SearchClient.Settings>> settingsList;
    /** ID of the last selected item. */
    private long lastSelectedItem;
    //endregion

    //region Constructors
    /**
     * Create a new adapter that populates a {@link Spinner} with a service selection dropdown.
     *
     * @param context           Android context.
     * @param sharedPreferences Shared preferences (used to restore last selection of the spinner).
     * @param loaderManager     Android support library loader manager.
     * @param adapterView       View populated by this adapter (used to restore last selection of the spinner)
     * @param listener          Listener used to interact with the {@link android.app.Activity} using this
     *                          adapter.
     */
    public ServiceDropdownAdapter(@NonNull Context context, @NonNull SharedPreferences sharedPreferences,
            @NonNull LoaderManager loaderManager, @NonNull AdapterView<?> adapterView, @NonNull Listener listener) {
        this.context = context;
        this.sharedPreferences = sharedPreferences;
        this.adapterView = adapterView;
        this.listener = listener;

        // Restore last active item from SharedPreferences.
        lastSelectedItem = this.sharedPreferences.getLong(SHARED_PREFERENCE_LAST_SELECTED_INDEX, 1L);
        // Initialize the search client settings database loader.
        loaderManager.initLoader(LOADER_ID_API_SETTINGS, null, this);
    }
    //endregion

    //region BaseAdapter methods
    @Override
    public int getCount() {
        if (settingsList == null) {
            return 1;
        } else {
            return settingsList.size() + 1;
        }
    }

    @Override
    public SearchClient.Settings getItem(int position) {
        if (settingsList == null || position == settingsList.size()) // APISettingActivity View.
            return null;
        return settingsList.get(position).second;
    }

    @Override
    public long getItemId(int position) {
        if (settingsList == null || position == settingsList.size()) // APISettingActivity View.
            return -1;
        // Return database row ID.
        return settingsList.get(position).first;
    }

    @Override
    public View getView(int position, View recycledView, ViewGroup container) {
        // Reuse recycled view, if possible.
        @SuppressLint("ViewHolder")
        View view = LayoutInflater.from(context).inflate(R.layout.simple_dropdown_item, container, false);

        // Populate views with content.
        TextView text1 = (TextView) view.findViewById(android.R.id.text1);
        SearchClient.Settings settings = getItem(position);
        if (settings != null) {
            text1.setText(settings.getName());
        } else {
            text1.setText(R.string.service_dropdown_settings);
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    context.startActivity(new Intent(context, APISettingsActivity.class));
                }
            });
        }

        return view;
    }
    //endregion

    //region LoaderManager.LoaderCallbacks<List<Pair<Integer, SearchClient.Settings>>> methods
    @Override
    public Loader<List<Pair<Integer, SearchClient.Settings>>> onCreateLoader(int id, Bundle args) {
        if (id == LOADER_ID_API_SETTINGS) {
            return new APISettingsDatabase.Loader(context);
        }
        return null;
    }

    @Override
    public void onLoadFinished(Loader<List<Pair<Integer, SearchClient.Settings>>> loader,
            List<Pair<Integer, SearchClient.Settings>> data) {
        if (loader.getId() == LOADER_ID_API_SETTINGS) {
            // Update adapter data.
            settingsList = data;
            notifyDataSetChanged();
            // Reselect last active item.
            if (!data.isEmpty()) {
                adapterView.setSelection(getPositionByItemId(lastSelectedItem));
            } else {
                // Start APISettingActivity.
                Intent intent = new Intent(context, APISettingsActivity.class);
                intent.setAction(APISettingsActivity.ACTION_CREATE_SERVICE);
                context.startActivity(intent);
            }
        }
    }

    @Override
    public void onLoaderReset(Loader<List<Pair<Integer, SearchClient.Settings>>> loader) {
        // Invalidate adapter's data.
        settingsList = null;
        notifyDataSetInvalidated();
    }
    //endregion

    //region AdapterView.OnItemSelectedListener
    @Override
    public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
        // Save last active item to SharedPreferences.
        if (id != -1) {
            // Notify parent activity.
            listener.onSearchAPISelected(getItem(position), id != lastSelectedItem);
            // Update last selected item id.
            lastSelectedItem = id;
            sharedPreferences.edit().putLong(SHARED_PREFERENCE_LAST_SELECTED_INDEX, id).apply();
        }
    }

    @Override
    public void onNothingSelected(AdapterView<?> adapterView) {
        // Do nothing.
    }
    //endregion

    //region Get adapter item position by SQLite database row ID
    /**
     * Get position of the item with given database row ID.
     *
     * @param id Row ID.
     * @return Position of the item.
     */
    public int getPositionByItemId(long id) {
        for (int i = 0; i < getCount(); i++) {
            if (getItemId(i) == id) {
                return i;
            }
        }
        return 0;
    }
    //endregion

    //region Listener interface
    /** Listener used to interact with the {@link android.app.Activity} using this adapter. */
    public interface Listener {

        /**
         * Called when a new Search API is selected by the user from the action bar dropdown.
         *
         * @param settings         Selected {@link SearchClient.Settings} object.
         * @param expandActionView Should the SearchView action view be expanded?
         */
        public void onSearchAPISelected(SearchClient.Settings settings, boolean expandActionView);
    }
    //endregion
}