com.xengar.android.stocktracker.ui.StockFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.xengar.android.stocktracker.ui.StockFragment.java

Source

/*
 * Copyright (C) 2017 Angel Garcia
 *
 * 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.xengar.android.stocktracker.ui;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

import com.xengar.android.stocktracker.R;
import com.xengar.android.stocktracker.Utility;
import com.xengar.android.stocktracker.data.Contract;
import com.xengar.android.stocktracker.data.PrefUtils;
import com.xengar.android.stocktracker.sync.QuoteSyncJob;

import static com.xengar.android.stocktracker.Utility.LOG;

/**
 * Encapsulates fetching the stocks and displaying it as a
 * {@link android.support.v7.widget.RecyclerView} layout.
 */
public class StockFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>,
        SwipeRefreshLayout.OnRefreshListener, StockAdapter.StockAdapterOnClickHandler {

    public static final String TAG = StockFragment.class.getSimpleName();
    private RecyclerView mRecyclerView;
    private int mPosition = RecyclerView.NO_POSITION;
    private Context mContext;

    private static final int STOCK_LOADER = 0;

    SwipeRefreshLayout swipeRefreshLayout;
    TextView error;
    private StockAdapter adapter;

    private boolean waitingStockCheck = false;
    // Broadcast receiver for the invalid stock
    private BroadcastReceiver stockCheckReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String symbol = intent.getStringExtra(Contract.Quote.COLUMN_SYMBOL);
            Toast.makeText(getActivity().getApplication().getApplicationContext(),
                    getString(R.string.error_stock_not_found, symbol), Toast.LENGTH_LONG).show();
            // As it's invalid remove it from the preferences
            PrefUtils.removeStock(context, symbol);
        }
    };

    /**
     * A callback interface that all activities containing this fragment must
     * implement. This mechanism allows activities to be notified of item
     * selections.
     */
    public interface Callback {
        /**
         * DetailFragmentCallback for when an item has been selected.
         */
        public void onItemSelected(Uri contentUri, StockAdapter.StockViewHolder vh);
    }

    public StockFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        mContext = inflater.getContext();

        View rootView = inflater.inflate(R.layout.fragment_main, container, false);
        // Get a reference to the RecyclerView, and attach this adapter to it.
        mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
        error = (TextView) rootView.findViewById(R.id.error);
        // Set the layout manager
        adapter = new StockAdapter(mContext, new StockAdapter.StockAdapterOnClickHandler() {
            @Override
            public void onClick(String symbol, StockAdapter.StockViewHolder vh) {
                ((Callback) getActivity()).onItemSelected(Contract.Quote.makeUriForStock(symbol), vh);
                mPosition = vh.getAdapterPosition();
            }
        });
        mRecyclerView.setAdapter(adapter);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

        swipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swipe_refresh);
        swipeRefreshLayout.setOnRefreshListener(this);
        swipeRefreshLayout.setRefreshing(true);
        //onRefresh();

        long syncPeriod = PrefUtils.getSyncFrequency(mContext);
        QuoteSyncJob.initialize(mContext, syncPeriod);
        getLoaderManager().initLoader(STOCK_LOADER, null, this);

        new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) {
            @Override
            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
                    RecyclerView.ViewHolder target) {
                return false;
            }

            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                String symbol = adapter.getSymbolAtPosition(viewHolder.getAdapterPosition());
                PrefUtils.removeStock(getActivity(), symbol);
                mContext.getContentResolver().delete(Contract.Quote.makeUriForStock(symbol), null, null);
            }
        }).attachToRecyclerView(mRecyclerView);

        return rootView;
    }

    /**
     *  Instantiate and return a new Loader for the given ID.
     *
     * @param id
     * @param args
     * @return
     */
    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return new CursorLoader(getActivity(), Contract.Quote.uri, Contract.Quote.QUOTE_COLUMNS, null, null,
                Contract.Quote.COLUMN_SYMBOL);
    }

    /**
     * Called when onCreateLoader(int, Bundle) has finished its load.
     *
     * @param loader
     * @param data
     */
    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        swipeRefreshLayout.setRefreshing(false);
        if (data.getCount() != 0) {
            error.setVisibility(View.GONE);
        }
        adapter.setCursor(data);

        // Unregister the stock check
        if (waitingStockCheck) {
            getActivity().unregisterReceiver(stockCheckReceiver);
            waitingStockCheck = false;
        }
    }

    /**
     *  Called when a previously created loader in onCreateLoader(int, Bundle) is being reset,
     *  thus making its data unavailable
     *
     * @param loader
     */
    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        swipeRefreshLayout.setRefreshing(false);
        adapter.setCursor(null);

        // Unregister the stock check
        if (waitingStockCheck) {
            getActivity().unregisterReceiver(stockCheckReceiver);
            waitingStockCheck = false;
        }
    }

    /**
     * Adds the symbol to the preferences and calls for sync.
     *
     * @param symbol
     */
    void addStock(String symbol) {
        if (symbol != null && !symbol.isEmpty()) {

            if (Utility.networkUp(mContext)) {
                swipeRefreshLayout.setRefreshing(true);
            } else {
                String message = getString(R.string.toast_stock_added_no_connectivity, symbol);
                Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
            }

            PrefUtils.addStock(mContext, symbol);
            QuoteSyncJob.syncImmediately(mContext);

            // Register for receiving a message that the stock is invalid
            IntentFilter filter = new IntentFilter();
            filter.addAction(QuoteSyncJob.ACTION_INVALID_STOCK);
            mContext.registerReceiver(stockCheckReceiver, filter);
            waitingStockCheck = true;
        }
    }

    @Override
    public void onRefresh() {
        QuoteSyncJob.syncImmediately(mContext);

        if (!Utility.networkUp(mContext) && adapter.getItemCount() == 0) {
            swipeRefreshLayout.setRefreshing(false);
            error.setText(getString(R.string.error_no_network));
            error.setVisibility(View.VISIBLE);
        } else if (!Utility.networkUp(mContext)) {
            swipeRefreshLayout.setRefreshing(false);
            Toast.makeText(mContext, R.string.toast_no_connectivity, Toast.LENGTH_LONG).show();
        } else if (PrefUtils.getStocks(mContext).size() == 0) {
            if (LOG) {
                Log.d(TAG, getString(R.string.msg_panic));
            }
            swipeRefreshLayout.setRefreshing(false);
            error.setText(getString(R.string.error_no_stocks));
            error.setVisibility(View.VISIBLE);
        } else {
            error.setVisibility(View.GONE);
        }
    }

    @Override
    public void onClick(String symbol, StockAdapter.StockViewHolder vh) {
        if (LOG) {
            Log.d(TAG, getString(R.string.msg_symbol_clicked, symbol));
        }
    }

}