com.daskiworks.ghwatch.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.daskiworks.ghwatch.MainActivity.java

Source

/*
 * Copyright 2014 contributors as indicated by the @authors tag.
 * 
 * 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.daskiworks.ghwatch;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;

import com.daskiworks.ghwatch.LoginDialogFragment.LoginDialogListener;
import com.daskiworks.ghwatch.backend.GHConstants;
import com.daskiworks.ghwatch.backend.UnreadNotificationsService;
import com.daskiworks.ghwatch.backend.ViewDataReloadStrategy;
import com.daskiworks.ghwatch.image.ImageLoader;
import com.daskiworks.ghwatch.model.BaseViewData;
import com.daskiworks.ghwatch.model.LoadingStatus;
import com.daskiworks.ghwatch.model.NotifCount;
import com.daskiworks.ghwatch.model.Notification;
import com.daskiworks.ghwatch.model.NotificationStreamViewData;
import com.daskiworks.ghwatch.model.StringViewData;

/**
 * Activity used to show list of Notifications.
 * 
 * @author Vlastimil Elias <vlastimil.elias@worldonline.cz>
 * 
 */
public class MainActivity extends ActivityBase implements LoginDialogListener, OnRefreshListener {

    private static final String STATE_FILTER_REPOSITORY = "STATE_FILTER_REPOSITORY";

    public static String INTENT_ACTION_DISMISS_ALL = "ACTION_MARK_ALL_READ";
    public static String INTENT_ACTION_SHOW = "ACTION_SHOW";

    private static final String TAG = MainActivity.class.getSimpleName();

    // common fields
    private DataLoaderTask dataLoader;

    // view components
    private ListView notificationsListView;
    private NotificationListAdapter notificationsListAdapter;

    private ListView repositoriesListView;
    private NotificationRepositoriesListAdapter repositoriesListAdapter;

    // backend services
    private ImageLoader imageLoader;
    private UnreadNotificationsService unreadNotificationsService;

    // filters
    private String filterByRepository = null;

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

        if (savedInstanceState != null) {
            filterByRepository = savedInstanceState.getString(STATE_FILTER_REPOSITORY);
        }

        setContentView(R.layout.activity_main);

        imageLoader = ImageLoader.getInstance(getApplicationContext());
        unreadNotificationsService = new UnreadNotificationsService(getBaseContext());

        initNavigationDrawer(NAV_DRAWER_ITEM_UNREAD_NOTIF);

        repositoriesListView = (ListView) findViewById(R.id.repositories_list);
        repositoriesListView.setOnItemClickListener(new RepositoriesListItemClickListener());

        // initialization of main content
        notificationsListView = (ListView) findViewById(R.id.list);
        notificationsListView.setVerticalFadingEdgeEnabled(true);
        SwipeDismissListViewTouchListener touchListener = new SwipeDismissListViewTouchListener(
                notificationsListView, new NotificationsListSwipeDismissListener());
        notificationsListView.setOnTouchListener(touchListener);
        // Setting this scroll listener is required to ensure that during ListView scrolling,
        // we don't look for swipes.
        notificationsListView.setOnScrollListener(touchListener.makeScrollListener());

        initSwipeLayout(this);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putCharSequence(STATE_FILTER_REPOSITORY, filterByRepository);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (!checkUserLoggedIn()) {
            finish();
            return;
        }
        ActivityTracker.sendView(this, TAG);

        Intent intent = getIntent();
        Log.d(TAG, "Intent who runs us : " + getIntent());
        if (intent != null && INTENT_ACTION_DISMISS_ALL.equals(intent.getAction())) {
            showMarkAllNotificationsAsReadDialog();
            intent.setAction(null);
        } else {
            if (SupportAppDevelopmentDialogFragment.isAutoShowScheduled(this)) {
                showSupportAppDevelopmentDialog();
            }
        }
        refreshList(ViewDataReloadStrategy.IF_TIMED_OUT, false);
        unreadNotificationsService.markAndroidWidgetsAsRead();
        unreadNotificationsService.markAndroidNotificationsRead();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main_activity_actions, menu);
        MenuItem mi = menu.findItem(R.id.action_notifCheck);
        if (mi != null) {
            mi.setVisible(GHConstants.DEBUG);
        }
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        menu.findItem(R.id.action_all_read)
                .setVisible(notificationsListAdapter != null && !notificationsListAdapter.isEmpty());
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (dataLoader != null)
            dataLoader.cancel(true);
        notifyDataSetChanged();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (super.onOptionsItemSelected(item)) {
            return true;
        }

        switch (item.getItemId()) {
        case R.id.action_all_read:
            showMarkAllNotificationsAsReadDialog();
            return true;
        case R.id.action_notifCheck:
            Toast.makeText(MainActivity.this, "New notification check started with empty store", Toast.LENGTH_SHORT)
                    .show();
            unreadNotificationsService.flushPersistentStore();
            unreadNotificationsService.newNotificationCheck();
            return true;
        default:
            return false;
        }
    }

    /**
     * Called when "Swipe to refresh" is finished.
     */
    @Override
    public void onRefresh() {
        ActivityTracker.sendEvent(this, ActivityTracker.CAT_UI, "unread_notifications_refresh", "", 0L);
        refreshList(ViewDataReloadStrategy.ALWAYS, false);
    }

    public void refreshList(ViewDataReloadStrategy reloadStrateg, boolean supressErrorMessages) {
        if (dataLoader == null)
            (dataLoader = new DataLoaderTask(reloadStrateg, supressErrorMessages)).execute();
    }

    private final class NotificationsListSwipeDismissListener
            implements SwipeDismissListViewTouchListener.DismissCallbacks {
        @Override
        public boolean canDismiss(int position) {
            return true;
        }

        @Override
        public void onDismiss(ListView listView, int[] reverseSortedPositions) {
            for (int position : reverseSortedPositions) {
                Notification tr = (Notification) notificationsListAdapter.getItem(position);
                if (tr != null) {
                    new MarkNotificationAsReadTask().execute(tr.getId());
                    ActivityTracker.sendEvent(MainActivity.this, ActivityTracker.CAT_UI,
                            "notification_mark_read_swipe", "", 0L);
                    notificationsListAdapter.removeNotificationByPosition(position);
                }
            }
            notifyDataSetChanged();
        }
    }

    private final class NotificationsListItemClickListener implements OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Notification notification = (Notification) notificationsListAdapter.getItem(position);
            if (notification != null) {
                new ShowNotificationTask().execute(notification);
                ActivityTracker.sendEvent(MainActivity.this, ActivityTracker.CAT_UI, "notification_show", "", 0L);
            }
        }
    }

    private final class NotificationsListItemMenuClickListener
            implements NotificationListAdapter.OnItemMenuClickedListener {
        @Override
        public boolean onMenuItemClick(Notification notification, MenuItem item) {
            switch (item.getItemId()) {
            case R.id.action_view:
                new ShowNotificationTask().execute(notification);
                ActivityTracker.sendEvent(MainActivity.this, ActivityTracker.CAT_UI, "notification_show_menu", "",
                        0L);
            case R.id.action_mark_read:
                new MarkNotificationAsReadTask().execute(notification.getId());
                notificationsListAdapter.removeNotificationById(notification.getId());
                ActivityTracker.sendEvent(MainActivity.this, ActivityTracker.CAT_UI, "notification_mark_read_menu",
                        "", 0L);
                notifyDataSetChanged();
                return true;
            case R.id.action_mute_thread:
                new MuteNotificationThreadTask().execute(notification.getId());
                notificationsListAdapter.removeNotificationById(notification.getId());
                ActivityTracker.sendEvent(MainActivity.this, ActivityTracker.CAT_UI, "notification_mute_thread", "",
                        0L);
                notifyDataSetChanged();
                return true;
            default:
                return false;
            }
        }
    }

    private final class RepositoriesListItemClickListener implements ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            if (repositoriesListView != null) {
                NotifCount nc = (NotifCount) repositoriesListAdapter.getItem(position);
                if (nc != null) {
                    if (filterByRepository != null && filterByRepository.equals(nc.title)) {
                        filterByRepository = null;
                        repositoriesListView.setItemChecked(position, false);
                    } else {
                        filterByRepository = nc.title;
                    }
                    if (notificationsListAdapter != null) {
                        notificationsListAdapter.setFilterByRepository(filterByRepository);
                    }
                    ActivityTracker.sendEvent(MainActivity.this, ActivityTracker.CAT_UI,
                            "notification_filter_by_repository", filterByRepository != null ? "SET" : "RESET", 0L);
                }
            }
            navigationDrawerClose();

        }
    }

    private final class DataLoaderTask extends AsyncTask<String, String, NotificationStreamViewData> {

        ViewDataReloadStrategy reloadStrategy = null;
        boolean supressErrorMessages = false;

        DataLoaderTask(ViewDataReloadStrategy reloadStrategy, boolean supressErrorMessages) {
            this.reloadStrategy = reloadStrategy;
            this.supressErrorMessages = supressErrorMessages;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected NotificationStreamViewData doInBackground(String... args) {
            return unreadNotificationsService.getNotificationStreamForView(reloadStrategy);
        }

        @Override
        protected void onPostExecute(final NotificationStreamViewData viewData) {
            try {
                if (isCancelled() || viewData == null)
                    return;
                if (viewData.loadingStatus != LoadingStatus.OK) {
                    if (!supressErrorMessages)
                        showServerCommunicationErrorAllertDialog(viewData.loadingStatus,
                                viewData.notificationStream != null);
                }
                if (viewData.notificationStream != null) {

                    if (notificationsListAdapter != null) {
                        notificationsListAdapter.setNotificationStream(viewData.notificationStream);
                        notificationsListAdapter.notifyDataSetChanged();
                    } else {
                        notificationsListAdapter = new NotificationListAdapter(MainActivity.this,
                                viewData.notificationStream, imageLoader);
                        notificationsListView.setAdapter(notificationsListAdapter);
                        notificationsListAdapter
                                .setOnItemMenuClickedListener(new NotificationsListItemMenuClickListener());
                        notificationsListView.setOnItemClickListener(new NotificationsListItemClickListener());
                    }

                    if (repositoriesListAdapter != null) {
                        repositoriesListAdapter.setNotificationStream(viewData.notificationStream);
                        repositoriesListAdapter.notifyDataSetChanged();
                    } else {
                        repositoriesListAdapter = new NotificationRepositoriesListAdapter(MainActivity.this,
                                viewData.notificationStream);
                        repositoriesListView.setAdapter(repositoriesListAdapter);
                    }
                    if (!repositoriesListAdapter.setSelectionForFilter(repositoriesListView, filterByRepository)) {
                        // repo no more in data so reset filter
                        filterByRepository = null;
                    }
                    if (notificationsListAdapter != null) {
                        notificationsListAdapter.setFilterByRepository(filterByRepository);
                    }

                    if (viewData.notificationStream.size() == 0) {
                        swipeLayout2.setVisibility(View.VISIBLE);
                        swipeLayout.setVisibility(View.GONE);
                    } else {
                        swipeLayout2.setVisibility(View.GONE);
                        swipeLayout.setVisibility(View.VISIBLE);
                    }
                }
            } finally {
                dataLoader = null;
                swipeLayout.setRefreshing(false);
                swipeLayout2.setRefreshing(false);
                hideInitialProgressBar();
                invalidateOptionsMenu();
            }
        }
    }

    private final class ShowNotificationTask extends AsyncTask<Notification, String, StringViewData> {

        ProgressDialog progress;

        @Override
        protected void onPreExecute() {
            progress = ProgressDialog.show(MainActivity.this, null, getString(R.string.progress_get_view_url_title),
                    true, true, new OnCancelListener() {

                        @Override
                        public void onCancel(DialogInterface dialog) {
                            ShowNotificationTask.this.cancel(true);
                        }
                    });
        }

        @Override
        protected StringViewData doInBackground(Notification... params) {
            return unreadNotificationsService.getGithubDataHtmlUrl(params[0].getViewBaseUrl());
        }

        @Override
        protected void onPostExecute(StringViewData result) {
            if (isCancelled() || result == null) {
                progress.dismiss();
                return;
            }
            if (result.loadingStatus != LoadingStatus.OK) {
                progress.dismiss();
                showServerCommunicationErrorAllertDialog(result.loadingStatus, false);
            } else if (result.data != null) {
                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(result.data));
                startActivity(browserIntent);
                progress.dismiss();
            }
        }
    }

    private final class MarkNotificationAsReadTask extends AsyncTask<Long, String, BaseViewData> {

        @Override
        protected BaseViewData doInBackground(Long... params) {

            return unreadNotificationsService.markNotificationAsRead(params[0]);
        }

        @Override
        protected void onPostExecute(final BaseViewData viewData) {
            if (isCancelled() || viewData == null)
                return;
            if (viewData.loadingStatus != LoadingStatus.OK) {
                showServerCommunicationErrorAllertDialog(viewData.loadingStatus, false);
                refreshList(ViewDataReloadStrategy.NEVER, true);
            } else {
                // Toast.makeText(MainActivity.this, R.string.message_notification_marked_read, Toast.LENGTH_SHORT).show();
            }
        }
    }

    private final class MuteNotificationThreadTask extends AsyncTask<Long, String, BaseViewData> {

        @Override
        protected BaseViewData doInBackground(Long... params) {

            return unreadNotificationsService.muteNotificationThread(params[0]);
        }

        @Override
        protected void onPostExecute(final BaseViewData viewData) {
            if (isCancelled() || viewData == null)
                return;
            if (viewData.loadingStatus != LoadingStatus.OK) {
                showServerCommunicationErrorAllertDialog(viewData.loadingStatus, false);
                refreshList(ViewDataReloadStrategy.NEVER, true);
            } else {
                Toast.makeText(MainActivity.this, R.string.message_notification_thread_muted, Toast.LENGTH_SHORT)
                        .show();
            }
        }
    }

    private final class MarkAllNotificationsAsReadTask extends AsyncTask<Object, String, BaseViewData> {

        @Override
        protected void onPreExecute() {
            swipeLayout.setRefreshing(true);
        }

        @Override
        protected BaseViewData doInBackground(Object... params) {
            return unreadNotificationsService.markAllNotificationsAsRead(filterByRepository);
        }

        @Override
        protected void onPostExecute(final BaseViewData viewData) {
            boolean supressErrorMessage = false;
            ViewDataReloadStrategy reloadStrategy = ViewDataReloadStrategy.ALWAYS;
            try {
                if (isCancelled() || viewData == null)
                    return;
                if (viewData.loadingStatus != LoadingStatus.OK) {
                    showServerCommunicationErrorAllertDialog(viewData.loadingStatus, false);
                    supressErrorMessage = true;
                    reloadStrategy = ViewDataReloadStrategy.NEVER;
                } else {
                    supressErrorMessage = false;
                    reloadStrategy = ViewDataReloadStrategy.ALWAYS;
                    // Toast.makeText(MainActivity.this, R.string.message_notifications_all_marked_read, Toast.LENGTH_SHORT).show();
                }
            } finally {
                refreshList(reloadStrategy, supressErrorMessage);
            }
        }
    }

    private void showServerCommunicationErrorAllertDialog(LoadingStatus loadingStatus,
            boolean showStaledDataWarning) {
        StringBuilder sb = new StringBuilder();
        sb.append(getString(loadingStatus.getResId()));
        if (showStaledDataWarning) {
            sb.append("\n").append(getString(R.string.message_staled_data));
        }
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(sb).setCancelable(true).setPositiveButton(R.string.button_ok,
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int id) {
                    }
                });

        builder.create().show();
    }

    private void showMarkAllNotificationsAsReadDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.message_confirm_notifications_all_mark_read_title);
        if (filterByRepository == null) {
            builder.setMessage(R.string.message_confirm_notifications_all_mark_read);
        } else {
            builder.setMessage(R.string.message_confirm_notifications_all_mark_read_repo);
        }
        builder.setCancelable(true);
        builder.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int id) {
                ActivityTracker.sendEvent(MainActivity.this, ActivityTracker.CAT_UI, "notifications_mark_read_all",
                        "", 0L);
                new MarkAllNotificationsAsReadTask().execute();
            }
        });
        builder.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int id) {
            }
        });
        builder.create().show();
    }

    @Override
    public void afterLoginSuccess(LoginDialogFragment dialog) {
        refreshList(ViewDataReloadStrategy.ALWAYS, false);
    }

    protected void notifyDataSetChanged() {
        if (notificationsListAdapter != null)
            notificationsListAdapter.notifyDataSetChanged();
        if (repositoriesListAdapter != null) {
            repositoriesListAdapter.notifyDataSetChanged();
        }
    }
}