jumaallan/AndelaCryptoApp

View on GitHub
app/src/main/java/com/androidstudy/andelatrackchallenge/MainActivity.java

Summary

Maintainability
A
1 hr
Test Coverage
package com.androidstudy.andelatrackchallenge;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.androidstudy.andelatrackchallenge.adapter.CardsAdapter;
import com.androidstudy.andelatrackchallenge.cards.OnCardActionListener;
import com.androidstudy.andelatrackchallenge.cards.OnItemClickListener;
import com.androidstudy.andelatrackchallenge.cards.ProfileDialog;
import com.androidstudy.andelatrackchallenge.models.Country;
import com.androidstudy.andelatrackchallenge.models.Country_;
import com.androidstudy.andelatrackchallenge.models.User;
import com.androidstudy.andelatrackchallenge.network.ApiClient;
import com.androidstudy.andelatrackchallenge.picker.currency.CurrencyPickerFragment;
import com.androidstudy.andelatrackchallenge.picker.currency.CurrencyPickerListener;
import com.androidstudy.andelatrackchallenge.settings.Settings;
import com.androidstudy.andelatrackchallenge.settings.SettingsActivity;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.facebook.AccessToken;
import com.facebook.GraphRequest;
import com.facebook.HttpMethod;
import com.facebook.login.LoginManager;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.tingyik90.snackprogressbar.SnackProgressBar;
import com.tingyik90.snackprogressbar.SnackProgressBarManager;
import com.uber.autodispose.AutoDispose;
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider;

import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;
import io.objectbox.Box;
import io.objectbox.BoxStore;
import timber.log.Timber;

public class MainActivity extends ThemableActivity implements CurrencyPickerListener,
        OnItemClickListener<Country>, OnCardActionListener, GoogleApiClient.OnConnectionFailedListener {
    @BindView(R.id.coordinator_layout)
    CoordinatorLayout coordinatorLayout;
    @BindView(R.id.toolbar)
    Toolbar toolbar;
    @BindView(R.id.fab)
    FloatingActionButton fab;
    @BindView(R.id.layout_empty)
    View emptyView;
    @BindView(R.id.text_empty)
    TextView emptyText;
    @BindView(R.id.recycler_view)
    RecyclerView recyclerView;
    @BindView(R.id.swipe_refresh)
    SwipeRefreshLayout swipeRefreshLayout;

    private GoogleApiClient mGoogleApiClient;
    private boolean isShowColoredCards = Settings.isShowColoredCards();

    private SnackProgressBarManager snackProgressBarManager;
    private ProfileDialog profileDialog;
    private CardsAdapter adapter;
    private Box<Country> countryBox;
    private Box<User> userBox;
    private User user;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        setSupportActionBar(toolbar);

        BoxStore boxStore = ((AndelaTrackChallenge) getApplicationContext()).getBoxStore();
        userBox = boxStore.boxFor(User.class);
        countryBox = boxStore.boxFor(Country.class);
        user = userBox.query().build().findFirst();

        profileDialog = ProfileDialog.newInstance(((dialog, which) -> logout()));

        // Configure sign-in to request the user's ID, email address, and basic
        // profile. ID and basic profile are included in DEFAULT_SIGN_IN.
        GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestEmail()
                .build();
        // Build a GoogleApiClient with access to the Google Sign-In Api and the
        // options specified by gso.
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
                .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                .build();
        init();

        fab.setOnClickListener(v ->
                CurrencyPickerFragment
                        .newInstance(countryBox.getAll())
                        .show(MainActivity.this.getSupportFragmentManager(), "currency-picker"));

        snackProgressBarManager = new SnackProgressBarManager(coordinatorLayout)
                .setProgressBarColor(R.color.colorAccent)
                .setOverlayLayoutAlpha(0.6f);
    }

    private void init() {
        emptyText.setText(Html.fromHtml(getString(R.string.text_empty_message)));

        adapter = new CardsAdapter();
        adapter.setOnItemClickListener(this);
        adapter.setOnCardActionListener(this);
        adapter.setEmptyView(emptyView);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);

        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(adapter);

        List<Country> all = countryBox.getAll();
        adapter.setCountries(all);
        loadRates(all.toArray(new Country[0]));

        swipeRefreshLayout.setOnRefreshListener(() ->
                loadRates(adapter.getCountries().toArray(new Country[0])));
    }

    private void loadRates(Country... countries) {
        for (Country country : countries) {
            ApiClient.loadRate(country)
                    .doOnSubscribe(d -> swipeRefreshLayout.setRefreshing(true))
                    .doAfterTerminate(() -> swipeRefreshLayout.setRefreshing(false))
                    .to(AutoDispose.with(AndroidLifecycleScopeProvider.from(this)).forSingle())
                    .subscribe(newCountry -> {
                        countryBox.put(country);
                        adapter.replace(country);
                    }, Timber::e);
        }
    }

    private void logout() {
        if (!Settings.isLoggedIn()) {
            return;
        }

        SnackProgressBar snackProgressBar = new SnackProgressBar(
                SnackProgressBar.TYPE_INDETERMINATE,
                "Logging out...")
                .setSwipeToDismiss(false);

        fab.hide();
        fab.setClickable(false);
        // Show snack progress during logout
        snackProgressBarManager.dismissAll();
        snackProgressBarManager.show(snackProgressBar, SnackProgressBarManager.LENGTH_INDEFINITE);

        boolean facebook = Settings.isFacebook();
        if (facebook) {
            new GraphRequest(AccessToken.getCurrentAccessToken(), "/me/permissions/", null, HttpMethod.DELETE, graphResponse -> {
                LoginManager.getInstance().logOut();
                //Clear Shared Pref File
                Settings.setLoggedInSharedPref(false);
                //Clear Local DB
                userBox.removeAll();
                //Redirect User to Login Page
                Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
                startActivity(intent);
                finish();

            }).executeAsync();
        } else {
            Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(status -> {
                //Clear Shared Pref File
                Settings.setLoggedInSharedPref(false);
                //Clear Local DB
                userBox.removeAll();
                //Redirect User to Login Page
                Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
                startActivity(intent);
                finish();
            });
        }

        //Unreachable anyway
        snackProgressBarManager.dismiss();
    }

    @Override
    protected boolean shouldRestart() {
        return super.shouldRestart() || (isShowColoredCards != Settings.isShowColoredCards());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        MenuItem profileItem = menu.findItem(R.id.action_profile);
        Glide.with(this)
                .asBitmap()
                .load(user.imageUrl)
                .apply(RequestOptions.circleCropTransform())
                .into(new SimpleTarget<Bitmap>(100, 100) {
                    @Override
                    public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
                        profileItem.setIcon(new BitmapDrawable(getResources(), resource));
                    }
                });
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        if (id == R.id.action_profile) {
            profileDialog.show(getSupportFragmentManager(), "profile");
            return true;
        } else if (id == R.id.action_settings) {
            startActivity(new Intent(this, SettingsActivity.class));
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onPicked(Country country, int position) {
        if (adapter.getCountries().contains(country)) {
            return;
        }

        Country existingCountry = countryBox.query().equal(Country_.code, country.code).build()
                .findFirst();
        if (existingCountry != null) {
            return;
        }

        countryBox.put(country);
        adapter.add(country);
        loadRates(country);
        Toast.makeText(this, "Added " + country.name, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onItemClick(Country item, int position) {
        Intent intent = new Intent(this, ConverterActivity.class);
        intent.putExtra(ConverterActivity.COUNTRY, item);
        startActivity(intent);
    }

    @Override
    public void onToggleStar(Country country) {
        country.isFavorite = !country.isFavorite;
        countryBox.put(country);
        adapter.moveToPosition(country);
    }

    @Override
    public void onRemoved(Country country) {
        countryBox.remove(country);
        adapter.remove(country);
        Toast.makeText(this, "Removed " + country.name, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onEdited(Country country) {
        // open editing
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        Timber.e(connectionResult.getErrorMessage());
    }
}