com.freshdigitable.udonroad.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.freshdigitable.udonroad.MainActivity.java

Source

/*
 * Copyright (c) 2016. Matsuda, Akihit (akihito104)
 *
 * 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.freshdigitable.udonroad;

import android.content.Intent;
import android.content.res.Configuration;
import android.databinding.DataBindingUtil;
import android.os.Build;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.NavigationView.OnNavigationItemSelectedListener;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.Toast;

import com.freshdigitable.udonroad.StatusViewBase.OnUserIconClickedListener;
import com.freshdigitable.udonroad.TimelineFragment.OnFetchTweets;
import com.freshdigitable.udonroad.TweetInputFragment.TweetSendable;
import com.freshdigitable.udonroad.TweetInputFragment.TweetType;
import com.freshdigitable.udonroad.UserAction.Resource;
import com.freshdigitable.udonroad.databinding.ActivityMainBinding;
import com.freshdigitable.udonroad.datastore.SortedCache;
import com.freshdigitable.udonroad.ffab.OnFlingListener.Direction;
import com.freshdigitable.udonroad.module.InjectionUtil;
import com.freshdigitable.udonroad.module.twitter.TwitterApi;
import com.freshdigitable.udonroad.subscriber.ConfigRequestWorker;
import com.freshdigitable.udonroad.subscriber.StatusRequestWorker;
import com.freshdigitable.udonroad.subscriber.UserFeedbackSubscriber;
import com.squareup.picasso.Picasso;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.inject.Inject;

import rx.Observable;
import rx.Subscription;
import rx.functions.Action0;
import rx.functions.Action1;
import twitter4j.Paging;
import twitter4j.Status;
import twitter4j.User;

import static com.freshdigitable.udonroad.TweetInputFragment.TYPE_DEFAULT;
import static com.freshdigitable.udonroad.TweetInputFragment.TYPE_QUOTE;
import static com.freshdigitable.udonroad.TweetInputFragment.TYPE_REPLY;

/**
 * MainActivity shows home timeline for authorized user.
 *
 * Created by akihit
 */
public class MainActivity extends AppCompatActivity
        implements TweetSendable, OnUserIconClickedListener, OnFetchTweets, FabHandleable {
    private static final String TAG = MainActivity.class.getSimpleName();
    private ActivityMainBinding binding;
    private ActionBarDrawerToggle actionBarDrawerToggle;
    private TimelineFragment<Status> tlFragment;
    private TweetInputFragment tweetInputFragment;

    @Inject
    TwitterApi twitterApi;
    private SortedCache<Status> homeTimeline;
    @Inject
    StatusRequestWorker<SortedCache<Status>> statusRequestWorker;
    @Inject
    UserStreamUtil userStream;
    private final Map<Direction, UserAction> actionMap = new HashMap<>();
    @Inject
    ConfigRequestWorker configRequestWorker;
    @Inject
    UserFeedbackSubscriber userFeedback;

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

        InjectionUtil.getComponent(this).inject(this);
        if (!twitterApi.loadAccessToken()) {
            startActivity(new Intent(this, OAuthActivity.class));
            finish();
            return;
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
        }
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        binding.navDrawer.setNavigationItemSelectedListener(new OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                int itemId = item.getItemId();
                if (itemId == R.id.menu_home) {
                    Log.d(TAG, "home is selected");
                    binding.navDrawerLayout.closeDrawer(binding.navDrawer);
                } else if (itemId == R.id.menu_mention) {
                    Log.d(TAG, "mention is selected");
                    binding.navDrawerLayout.closeDrawer(binding.navDrawer);
                } else if (itemId == R.id.menu_fav) {
                    Log.d(TAG, "fav is selected");
                    binding.navDrawerLayout.closeDrawer(binding.navDrawer);
                } else if (itemId == R.id.menu_license) {
                    startActivity(new Intent(getApplicationContext(), LicenseActivity.class));
                    binding.navDrawerLayout.closeDrawer(binding.navDrawer);
                }
                return false;
            }
        });

        binding.ffab.hide();
        setupHomeTimeline();
        setupTweetInputView();
    }

    private void setupHomeTimeline() {
        statusRequestWorker.open("home");
        homeTimeline = statusRequestWorker.getCache();
        homeTimeline.clearPool();

        tlFragment = new TimelineFragment<>();
        tlFragment.setSortedCache(homeTimeline);

        configRequestWorker.open();
        configRequestWorker.setup(new Action0() {
            @Override
            public void call() {
                getSupportFragmentManager().beginTransaction().replace(R.id.main_timeline_container, tlFragment)
                        .commit();
            }
        });
    }

    private void attachToolbar(Toolbar toolbar) {
        actionBarDrawerToggle = new ActionBarDrawerToggle(this, binding.navDrawerLayout, toolbar,
                R.string.drawer_open, R.string.drawer_close) {
            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                tlFragment.stopScroll();
            }

            @Override
            public void onDrawerClosed(View drawerView) {
                super.onDrawerClosed(drawerView);
                tlFragment.startScroll();
            }
        };
        actionBarDrawerToggle.setDrawerIndicatorEnabled(true);
        binding.navDrawerLayout.addDrawerListener(actionBarDrawerToggle);
        actionBarDrawerToggle.syncState();
    }

    private Subscription subscription;

    private void setupNavigationDrawer() {
        subscription = configRequestWorker.getAuthenticatedUser().subscribe(new Action1<User>() {
            @Override
            public void call(User user) {
                setupNavigationDrawer(user);
            }
        });
    }

    private void setupNavigationDrawer(@Nullable User user) {
        if (user == null) {
            return;
        }

        final CombinedScreenNameTextView account = (CombinedScreenNameTextView) binding.navDrawer
                .findViewById(R.id.nav_header_account);
        if (account != null) {
            account.setNames(user);
        }
        final ImageView icon = (ImageView) binding.navDrawer.findViewById(R.id.nav_header_icon);
        if (icon != null) {
            Picasso.with(binding.navDrawer.getContext()).load(user.getProfileImageURLHttps()).fit().into(icon);
        }
        attachToolbar(binding.mainToolbar);
    }

    @Override
    public void onPostCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
        super.onPostCreate(savedInstanceState, persistentState);
        actionBarDrawerToggle.syncState();
    }

    @Override
    protected void onStart() {
        super.onStart();
        userStream.connect(homeTimeline);
        setupNavigationDrawer();

        binding.mainToolbar.setTitle("Home");
        setSupportActionBar(binding.mainToolbar);
        final ActionBar supportActionBar = getSupportActionBar();
        if (supportActionBar != null) {
            supportActionBar.setDisplayHomeAsUpEnabled(true);
            supportActionBar.setHomeButtonEnabled(true);
        }

        setupActionMap();
        UserAction.setupFlingableFAB(binding.ffab, actionMap, getApplicationContext());
    }

    private StatusDetailFragment statusDetail;

    private void showStatusDetail(long status) {
        statusDetail = StatusDetailFragment.getInstance(status);
        getSupportFragmentManager().beginTransaction().hide(tlFragment)
                .add(R.id.main_timeline_container, statusDetail)
                .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).commit();
        tlFragment.stopScroll();
        if (tlFragment.isTweetSelected()) {
            binding.ffab.hide();
        }
    }

    private boolean hideStatusDetail() {
        if (statusDetail == null) {
            return false;
        }
        getSupportFragmentManager().beginTransaction().remove(statusDetail).show(tlFragment)
                .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE).commit();
        statusDetail = null;
        tlFragment.startScroll();
        if (tlFragment.isTweetSelected()) {
            binding.ffab.show();
        }
        return true;
    }

    @Override
    protected void onResume() {
        Log.d(TAG, "onResume: ");
        super.onResume();
        statusRequestWorker.registerRootView(binding.mainTimelineContainer);
    }

    @Override
    protected void onPause() {
        super.onPause();
        statusRequestWorker.unregisterRootView(binding.mainTimelineContainer);
    }

    @Override
    protected void onStop() {
        super.onStop();
        binding.ffab.setOnFlingListener(null);
        actionMap.clear();
        if (subscription != null && !subscription.isUnsubscribed()) {
            subscription.unsubscribe();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (userStream != null) {
            userStream.disconnect();
        }
        if (binding != null) {
            binding.ffab.setOnFlingListener(null);
            binding.navDrawer.setNavigationItemSelectedListener(null);
        }
        configRequestWorker.close();
        statusRequestWorker.close();
        userFeedback.close();
    }

    @Override
    public void onBackPressed() {
        if (binding.navDrawerLayout.isDrawerOpen(binding.navDrawer)) {
            binding.navDrawerLayout.closeDrawer(binding.navDrawer);
            return;
        }
        if (tweetInputFragment != null && tweetInputFragment.isStatusInputViewVisible()) {
            cancelWritingSelected();
            return;
        }
        if (statusDetail != null && statusDetail.isVisible()) {
            hideStatusDetail();
            return;
        }
        if (tlFragment.isTweetSelected()) {
            tlFragment.clearSelectedTweet();
            return;
        }
        super.onBackPressed();
    }

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

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int itemId = item.getItemId();
        if (itemId == R.id.action_write) {
            sendStatusSelected(TYPE_DEFAULT, -1);
        } else if (itemId == R.id.action_cancel) {
            cancelWritingSelected();
        }
        return actionBarDrawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
    }

    private void sendStatusSelected(@TweetType int type, long statusId) {
        if (binding.ffab.getVisibility() == View.VISIBLE) {
            binding.ffab.hide();
        }
        tlFragment.stopScroll();
        if (type != TYPE_DEFAULT) {
            tweetInputFragment.stretchTweetInputView(type, statusId);
        }
        if (type == TYPE_REPLY) {
            binding.mainToolbar.setTitle("?");
        } else if (type == TYPE_QUOTE) {
            binding.mainToolbar.setTitle("?");
        } else {
            binding.mainToolbar.setTitle("??????");
        }
    }

    private void cancelWritingSelected() {
        tlFragment.startScroll();
        if (tlFragment.isTweetSelected() && tlFragment.isVisible()) {
            binding.ffab.show();
        }
        binding.mainToolbar.setTitle("Home");
    }

    private void setupTweetInputView() {
        tweetInputFragment = TweetInputFragment.create();
        tweetInputFragment.setTweetSendFab(binding.mainSendTweet);
        getSupportFragmentManager().beginTransaction().add(R.id.main_appbar_container, tweetInputFragment).commit();
    }

    private void showToast(String text) {
        Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void setupInput(@TweetType int type, long statusId) {
        sendStatusSelected(type, statusId);
    }

    @Override
    public void observeUpdateStatus(Observable<Status> updateStatusObservable) {
        updateStatusObservable.subscribe(new Action1<Status>() {
            @Override
            public void call(Status status) {
                cancelWritingSelected();
            }
        }, new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
                showToast("send tweet: failure...");
                Log.e(TAG, "update status: " + throwable);
            }
        });
    }

    @Override
    public void fetchTweet() {
        statusRequestWorker.fetchHomeTimeline();
    }

    @Override
    public void fetchTweet(Paging paging) {
        statusRequestWorker.fetchHomeTimeline(paging);
    }

    private void setupActionMap() {
        actionMap.put(Direction.UP, new UserAction(Resource.FAV, new Runnable() {
            @Override
            public void run() {
                statusRequestWorker.createFavorite(tlFragment.getSelectedTweetId());
            }
        }));
        actionMap.put(Direction.RIGHT, new UserAction(Resource.RETWEET, new Runnable() {
            @Override
            public void run() {
                statusRequestWorker.retweetStatus(tlFragment.getSelectedTweetId());
            }
        }));
        actionMap.put(Direction.UP_RIGHT, new UserAction(null, new Runnable() {
            @Override
            public void run() {
                final long selectedTweetId = tlFragment.getSelectedTweetId();
                Observable
                        .concatDelayError(Arrays.asList(statusRequestWorker.observeCreateFavorite(selectedTweetId),
                                statusRequestWorker.observeRetweetStatus(selectedTweetId)))
                        .subscribe(StatusRequestWorker.<Status>nopSubscriber());
            }
        }));
        actionMap.put(Direction.LEFT, new UserAction(Resource.MENU, new Runnable() {
            @Override
            public void run() {
                showStatusDetail(tlFragment.getSelectedTweetId());
            }
        }));
        actionMap.put(Direction.DOWN, new UserAction(Resource.REPLY, new Runnable() {
            @Override
            public void run() {
                sendStatusSelected(TYPE_REPLY, tlFragment.getSelectedTweetId());
            }
        }));
        actionMap.put(Direction.DOWN_RIGHT, new UserAction(Resource.QUOTE, new Runnable() {
            @Override
            public void run() {
                sendStatusSelected(TYPE_QUOTE, tlFragment.getSelectedTweetId());
            }
        }));
    }

    @Override
    public void showFab() {
        binding.ffab.show();
    }

    @Override
    public void hideFab() {
        binding.ffab.hide();
    }

    @Override
    public void onUserIconClicked(View view, User user) {
        if (tweetInputFragment != null && tweetInputFragment.isStatusInputViewVisible()) {
            return;
        }
        binding.ffab.hide();
        tlFragment.stopScroll();
        UserInfoActivity.start(this, user, view);
    }
}