ca.mymenuapp.ui.activities.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for ca.mymenuapp.ui.activities.MainActivity.java

Source

/*
 * Copyright (C) 2014 MyMenu, Inc.
 *
 * 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 ca.mymenuapp.ui.activities;

import android.app.ActionBar;
import android.content.Intent;
import android.content.res.Configuration;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import butterknife.InjectView;
import butterknife.OnClick;
import ca.mymenuapp.R;
import ca.mymenuapp.data.MyMenuDatabase;
import ca.mymenuapp.data.api.model.Restaurant;
import ca.mymenuapp.data.api.model.User;
import ca.mymenuapp.data.prefs.ObjectPreference;
import ca.mymenuapp.data.rx.EndlessObserver;
import ca.mymenuapp.ui.fragments.DietaryPreferencesFragment;
import ca.mymenuapp.ui.fragments.RestaurantGridFragment;
import ca.mymenuapp.ui.fragments.RestaurantsMapFragment;
import ca.mymenuapp.ui.fragments.SettingsFragment;
import ca.mymenuapp.ui.fragments.SpecialsGridFragment;
import ca.mymenuapp.ui.widgets.DelegateOnPageChangeListener;
import ca.mymenuapp.ui.widgets.SwipeableActionBarTabsAdapter;
import com.f2prateek.ln.Ln;
import com.google.android.gms.maps.model.LatLng;
import com.google.maps.android.SphericalUtil;
import com.squareup.otto.Produce;
import com.squareup.otto.Subscribe;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import pl.charmas.android.reactivelocation.ReactiveLocationProvider;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import rx.util.functions.Action1;
import rx.util.functions.Func1;
import rx.util.functions.Func2;

import static ca.mymenuapp.data.DataModule.USER_PREFERENCE;

/**
 * The top level activity that is shown first to the user.
 */
public class MainActivity extends BaseActivity {

    @Inject
    @Named(USER_PREFERENCE)
    ObjectPreference<User> userPreference;
    @Inject
    MyMenuDatabase myMenuDatabase;
    @Inject
    ReactiveLocationProvider locationProvider;

    @InjectView(R.id.pager)
    ViewPager viewPager;
    @InjectView(R.id.drawer_layout)
    DrawerLayout drawerLayout;
    @InjectView(R.id.drawer)
    View drawer;
    @InjectView(R.id.search_restaurants)
    EditText searchField;

    ActionBarDrawerToggle drawerToggle;
    List<Restaurant> restaurants = Collections.emptyList();
    LatLng lastLatLng;

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        inflateView(R.layout.activity_main);

        locationProvider.getLastKnownLocation().subscribe(new Action1<Location>() {
            @Override
            public void call(Location location) {
                lastLatLng = new LatLng(location.getLatitude(), location.getLongitude());
                myMenuDatabase.getNearbyRestaurants(location.getLatitude(), location.getLongitude(),
                        new EndlessObserver<List<Restaurant>>() {
                            @Override
                            public void onNext(List<Restaurant> restaurantList) {
                                restaurants = restaurantList;
                                bus.post(new OnRestaurantListAvailableEvent(restaurantList));
                            }
                        });
            }
        });

        setupTabs(savedInstanceState != null ? savedInstanceState.getInt("tab", 0) : 0);
        if (savedInstanceState == null) {
            getFragmentManager().beginTransaction()
                    .add(R.id.restaraunt_grid_container, new RestaurantGridFragment()).commit();
        }

        // start drawer in open state
        drawerLayout.openDrawer(drawer);

        // allow user to toggle drawer with the action bar
        drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.drawable.ic_drawer, R.string.drawer_open,
                R.string.drawer_close) {

            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }

            @Override
            public void onDrawerClosed(View drawerView) {
                super.onDrawerClosed(drawerView);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }
        };
        drawerLayout.setDrawerListener(drawerToggle);
        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);
        searchField.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                searchRestaurantsInMemory(s.toString());
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        });
    }

    /** Setup the tabs to display our fragments. */
    private void setupTabs(int tab) {
        DelegateOnPageChangeListener delegateOnPageChangeListener = new DelegateOnPageChangeListener();
        viewPager.setOnPageChangeListener(delegateOnPageChangeListener);

        final ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        SwipeableActionBarTabsAdapter tabsAdapter = new SwipeableActionBarTabsAdapter(this, viewPager,
                delegateOnPageChangeListener);
        tabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.map)), RestaurantsMapFragment.class, null);
        tabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.specials)), SpecialsGridFragment.class,
                null);
        if (!userPreference.get().isGuest()) {
            tabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.dietary_preferences)),
                    DietaryPreferencesFragment.class, null);
            tabsAdapter.addTab(actionBar.newTab().setText(getString(R.string.settings)), SettingsFragment.class,
                    null);
        }
        actionBar.setSelectedNavigationItem(tab);

        delegateOnPageChangeListener.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                if (position == 0) {
                    // Enable user to slide the drawer layout
                    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
                    drawerToggle.setDrawerIndicatorEnabled(true);
                    getActionBar().setDisplayHomeAsUpEnabled(true);
                    getActionBar().setHomeButtonEnabled(true);
                } else {
                    // Disable user from sliding the drawer layout
                    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
                    drawerToggle.setDrawerIndicatorEnabled(false);
                    getActionBar().setDisplayHomeAsUpEnabled(false);
                    getActionBar().setHomeButtonEnabled(false);
                }
            }

            @Override
            public void onPageSelected(int position) {
                // ignore
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                // ignore
            }
        });
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        drawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        drawerToggle.onConfigurationChanged(newConfig);
    }

    @OnClick({ R.id.sort_distance, R.id.sort_rating, R.id.sort_cuisine })
    void onSortButtonClicked(TextView button) {
        switch (button.getId()) {
        case R.id.sort_distance:
            sortRestaurants(new Comparator<Restaurant>() {
                @Override
                public int compare(Restaurant lhs, Restaurant rhs) {
                    return Double.compare(SphericalUtil.computeDistanceBetween(lastLatLng, lhs.getPosition()),
                            SphericalUtil.computeDistanceBetween(lastLatLng, rhs.getPosition()));
                }
            });
            break;
        case R.id.sort_rating:
            sortRestaurants(new Comparator<Restaurant>() {
                @Override
                public int compare(Restaurant lhs, Restaurant rhs) {
                    // sort descending
                    return Double.compare(rhs.rating, lhs.rating);
                }
            });
            break;
        case R.id.sort_cuisine:
            sortRestaurants(new Comparator<Restaurant>() {
                @Override
                public int compare(Restaurant lhs, Restaurant rhs) {
                    return lhs.category.compareTo(rhs.category);
                }
            });
            break;
        default:
            throw new IllegalArgumentException("Not handled!");
        }
    }

    @Subscribe
    public void onRestaurantClicked(OnRestaurantClickEvent event) {
        Intent intent = new Intent(this, RestaurantActivity.class);
        intent.putExtra(RestaurantActivity.ARGS_RESTAURANT_ID, event.restaurant.id);
        startActivity(intent);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if (userPreference.get().isGuest()) {
            menu.removeItem(R.id.logout);
        } else {
            menu.removeItem(R.id.login);
        }
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Pass the event to ActionBarDrawerToggle, if it returns
        // true, then it has handled the app icon touch event
        if (drawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        // Handle other action bar items...
        switch (item.getItemId()) {
        case R.id.logout:
            userPreference.delete();
            Intent logoutIntent = new Intent(this, LoginActivity.class);
            logoutIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(logoutIntent);
            finish();
            return true;
        case R.id.login:
            userPreference.delete();
            Intent loginIntent = new Intent(this, LoginActivity.class);
            loginIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(loginIntent);
            finish();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    private void searchRestaurantsInMemory(final String searchText) {
        Ln.d(searchText);
        // Filter ones in memory quickly
        Observable.from(restaurants).filter(new Func1<Restaurant, Boolean>() {
            @Override
            public Boolean call(Restaurant restaurant) {
                return restaurant.businessName.toLowerCase().contains(searchText.toLowerCase());
            }
        }).toList().subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new EndlessObserver<List<Restaurant>>() {
                    @Override
                    public void onNext(List<Restaurant> restaurantList) {
                        bus.post(new OnRestaurantListAvailableEvent(restaurantList));
                        searchRestaurantsFromNetwork(searchText);
                    }
                });
    }

    private void searchRestaurantsFromNetwork(final String searchText) {
        // todo: actually test this against the network, we don;t have enough restaurants for now
        myMenuDatabase.getNearbyRestaurantsByName(lastLatLng.latitude, lastLatLng.longitude, searchText,
                new EndlessObserver<List<Restaurant>>() {
                    @Override
                    public void onNext(List<Restaurant> restaurantList) {
                        bus.post(new OnRestaurantListAvailableEvent(restaurantList));
                    }
                });
    }

    private void sortRestaurants(final Comparator<Restaurant> restaurantComparator) {
        Observable.from(restaurants).toSortedList(new Func2<Restaurant, Restaurant, Integer>() {
            @Override
            public Integer call(Restaurant lhs, Restaurant rhs) {
                return restaurantComparator.compare(lhs, rhs);
            }
        }).subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new EndlessObserver<List<Restaurant>>() {
                    @Override
                    public void onNext(List<Restaurant> restaurantList) {
                        bus.post(new OnRestaurantListAvailableEvent(restaurantList));
                    }
                });
    }

    public static class OnRestaurantClickEvent {
        public final Restaurant restaurant;

        public OnRestaurantClickEvent(Restaurant restaurant) {
            this.restaurant = restaurant;
        }
    }

    public static class OnRestaurantListAvailableEvent {
        public final List<Restaurant> restaurants;

        public OnRestaurantListAvailableEvent(List<Restaurant> restaurants) {
            this.restaurants = restaurants;
        }
    }

    @Produce
    public OnRestaurantListAvailableEvent produceRestaurants() {
        Ln.d("Producing %d restaurants.", restaurants.size());
        return new OnRestaurantListAvailableEvent(restaurants);
    }
}