org.hawkular.client.android.fragment.AlertsFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.hawkular.client.android.fragment.AlertsFragment.java

Source

/*
 * Copyright 2015-2017 Red Hat, Inc. and/or its affiliates
 * and other contributors as indicated by the @author tags.
 *
 * 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 org.hawkular.client.android.fragment;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import org.hawkular.client.android.R;
import org.hawkular.client.android.activity.AlertDetailActivity;
import org.hawkular.client.android.adapter.AlertsAdapter;
import org.hawkular.client.android.backend.BackendClient;
import org.hawkular.client.android.backend.model.Alert;
import org.hawkular.client.android.backend.model.Resource;
import org.hawkular.client.android.backend.model.Trigger;
import org.hawkular.client.android.util.ColorSchemer;
import org.hawkular.client.android.util.Fragments;
import org.hawkular.client.android.util.Intents;
import org.hawkular.client.android.util.Time;
import org.hawkular.client.android.util.ViewDirector;
import org.jboss.aerogear.android.pipe.callback.AbstractSupportFragmentCallback;

import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.PopupMenu;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import icepick.Icepick;
import icepick.State;
import timber.log.Timber;

/**
 * Alerts fragment.
 * <p/>
 * Displays alerts as a list with menus allowing some alert-related actions, such as acknowledgement and resolving.
 */
public final class AlertsFragment extends Fragment
        implements AlertsAdapter.AlertListener, SwipeRefreshLayout.OnRefreshListener {
    @BindView(R.id.list)
    ListView list;

    @BindView(R.id.content)
    SwipeRefreshLayout contentLayout;

    @State
    @Nullable
    ArrayList<Trigger> triggers;

    @State
    @Nullable
    ArrayList<Alert> alerts;

    @State
    @Nullable
    ArrayList<Alert> alertsDump;

    @State
    boolean isActionPlus;

    @State
    @IdRes
    int alertsTimeMenu;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) {
        return inflater.inflate(R.layout.fragment_list, container, false);
    }

    @Override
    public void onActivityCreated(Bundle state) {
        super.onActivityCreated(state);

        setUpState(state);

        setUpBindings();

        setUpList();
        setUpMenu();

        isActionPlus = false;

        setUpRefreshing();

        setUpAlertsUi();
    }

    private void setUpState(Bundle state) {
        Icepick.restoreInstanceState(this, state);
    }

    private void setUpBindings() {
        ButterKnife.bind(this, getView());
    }

    private void setUpList() {
        list.setSelector(android.R.color.transparent);
    }

    private void setUpMenu() {
        setHasOptionsMenu(true);
    }

    private void setUpRefreshing() {
        contentLayout.setOnRefreshListener(this);
        contentLayout.setColorSchemeResources(ColorSchemer.getScheme());
    }

    @Override
    public void onRefresh() {
        setUpAlertsRefreshed();
    }

    @OnClick(R.id.button_retry)
    public void setUpAlertsUi() {
        if (alerts == null) {
            alertsTimeMenu = R.id.menu_time_hour;

            setUpAlertsForced();
        } else {
            setUpAlerts(alertsDump);
        }
    }

    private void setUpAlertsRefreshed() {
        setUpAlerts();
    }

    private void setUpAlertsForced() {
        showProgress();

        setUpAlerts();
    }

    private void setUpAlerts() {
        if (getResource() == null) {
            BackendClient.of(this).getAlerts(getAlertsTime(), Time.current(), null, new AlertsCallback());
        } else if (!areTriggersAvailable()) {
            setUpTriggers();
        } else {
            BackendClient.of(this).getAlerts(getAlertsTime(), Time.current(), triggers, new AlertsCallback());
        }
    }

    private boolean areTriggersAvailable() {
        return (triggers != null) && !triggers.isEmpty();
    }

    private void setUpTriggers() {
        BackendClient.of(this).getTriggers(new TriggersCallback());
    }

    private Date getAlertsTime() {
        switch (alertsTimeMenu) {
        case R.id.menu_time_hour:
            return Time.hourAgo();

        case R.id.menu_time_day:
            return Time.dayAgo();

        case R.id.menu_time_week:
            return Time.weekAgo();

        case R.id.menu_time_month:
            return Time.monthAgo();

        case R.id.menu_time_year:
            return Time.yearAgo();

        default:
            return Time.hourAgo();
        }
    }

    private void showProgress() {
        ViewDirector.of(this).using(R.id.animator).show(R.id.progress);
    }

    private void setUpAlertsTriggers(List<Trigger> triggers) {
        this.triggers = new ArrayList<>(filterTriggers(triggers));

        setUpAlerts();
    }

    private List<Trigger> filterTriggers(List<Trigger> triggers) {
        // TODO: think about better backend API.
        // This is mostly a hack, as trigger usage at all, actually.
        // Caused by a lack of API connecting Inventory and Alerts components.

        Resource resource = getResource();

        List<Trigger> filteredTriggers = new ArrayList<>();

        for (Trigger trigger : triggers) {
            if (trigger.getTags() != null && trigger.getTags().get("resourceId").equals(resource.getId())) {
                filteredTriggers.add(trigger);
            }
        }

        return filteredTriggers;
    }

    private Resource getResource() {
        return getArguments().getParcelable(Fragments.Arguments.RESOURCE);
    }

    private void setUpAlerts(final List<Alert> alerts) {
        this.alertsDump = new ArrayList<>(alerts);

        sortAlerts(this.alertsDump);

        if (isActionPlus) {
            this.alerts = alertsDump;
            if (this.alerts != null) {
                list.setAdapter(new AlertsAdapter(getActivity(), this, this.alerts));
            }
        } else {
            this.alerts = removeResolved();
            if (this.alerts != null) {
                list.setAdapter(new AlertsAdapter(getActivity(), this, this.alerts));
            }
        }

        hideRefreshing();

        if (this.alerts.isEmpty()) {
            showMessage();
        } else {
            showList();
        }
    }

    private ArrayList<Alert> removeResolved() {
        this.alerts = new ArrayList<>();
        for (Alert alert : alertsDump) {
            if (!alert.getStatus().equals("RESOLVED"))
                alerts.add(alert);
        }
        return alerts;
    }

    private void sortAlerts(List<Alert> alerts) {
        Collections.sort(alerts, new AlertsComparator());
    }

    @Override
    public void onAlertBodyClick(View alertView, int alertPosition) {
        Intent intent = new Intent(getActivity(), AlertDetailActivity.class);
        Alert alert = getAlertsAdapter().getItem(alertPosition);
        intent.putExtra(Intents.Extras.ALERT, alert);
        startActivity(intent);
    }

    @Override
    public void onAlertMenuClick(View alertView, int alertPosition) {
        showAlertMenu(alertView, alertPosition);
    }

    private void showAlertMenu(final View alertView, final int alertPosition) {
        PopupMenu alertMenu = new PopupMenu(getActivity(), alertView);

        alertMenu.getMenuInflater().inflate(R.menu.popup_alerts, alertMenu.getMenu());

        alertMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem menuItem) {
                Alert alert = getAlertsAdapter().getItem(alertPosition);

                switch (menuItem.getItemId()) {
                case R.id.menu_resolve:
                    BackendClient.of(AlertsFragment.this).resolveAlert(alert, new AlertActionCallback());
                    return true;

                case R.id.menu_acknowledge:
                    BackendClient.of(AlertsFragment.this).acknowledgeAlert(alert, new AlertActionCallback());
                    return true;

                default:
                    return false;
                }
            }
        });

        alertMenu.show();
    }

    private AlertsAdapter getAlertsAdapter() {
        return (AlertsAdapter) list.getAdapter();
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
        super.onCreateOptionsMenu(menu, menuInflater);

        menuInflater.inflate(R.menu.toolbar_alerts, menu);
    }

    @Override
    public void onPrepareOptionsMenu(Menu menu) {
        super.onPrepareOptionsMenu(menu);

        menu.findItem(alertsTimeMenu).setChecked(true);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem menuItem) {
        switch (menuItem.getItemId()) {
        case R.id.menu_time_hour:
        case R.id.menu_time_day:
        case R.id.menu_time_week:
        case R.id.menu_time_month:
        case R.id.menu_time_year:
            alertsTimeMenu = menuItem.getItemId();
            menuItem.setChecked(true);

            setUpAlertsForced();

            return true;

        case R.id.show_hide_res:
            isActionPlus = !isActionPlus;
            setUpAlerts(alertsDump);
            if (isActionPlus) {
                menuItem.setTitle(R.string.hide_resolved);
            } else {
                menuItem.setTitle(R.string.show_resolved);
            }
            return true;

        default:
            return super.onOptionsItemSelected(menuItem);
        }
    }

    private void cleanDump() {
        this.alertsDump = new ArrayList<>();
    }

    private void hideRefreshing() {
        contentLayout.setRefreshing(false);
    }

    private void showList() {
        ViewDirector.of(this).using(R.id.animator).show(R.id.content);
    }

    private void showMessage() {
        ViewDirector.of(this).using(R.id.animator).show(R.id.message);
    }

    private void showError() {
        ViewDirector.of(this).using(R.id.animator).show(R.id.error);
    }

    @Override
    public void onSaveInstanceState(Bundle state) {
        super.onSaveInstanceState(state);

        tearDownState(state);
    }

    private void tearDownState(Bundle state) {
        Icepick.saveInstanceState(this, state);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();

        tearDownBindings();
    }

    private void tearDownBindings() {
        //TODO: Modify it
        //ButterKnife.unbind(this);
    }

    private static final class TriggersCallback extends AbstractSupportFragmentCallback<List<Trigger>> {
        @Override
        public void onSuccess(List<Trigger> triggers) {
            if (triggers.isEmpty()) {
                Timber.d("Triggers list is empty, this should not happen.");

                getAlertsFragment().showError();
                return;
            }

            getAlertsFragment().setUpAlertsTriggers(triggers);
        }

        @Override
        public void onFailure(Exception e) {
            Timber.d(e, "Triggers fetching failed.");

            getAlertsFragment().showError();
        }

        private AlertsFragment getAlertsFragment() {
            return (AlertsFragment) getSupportFragment();
        }
    }

    private static final class AlertsCallback extends AbstractSupportFragmentCallback<List<Alert>> {
        @Override
        public void onSuccess(List<Alert> alerts) {
            if (!alerts.isEmpty()) {
                getAlertsFragment().setUpAlerts(alerts);
            } else {
                getAlertsFragment().showMessage();
                getAlertsFragment().cleanDump();
            }
        }

        @Override
        public void onFailure(Exception e) {
            Timber.d(e, "Alerts fetching failed.");

            getAlertsFragment().showError();
        }

        private AlertsFragment getAlertsFragment() {
            return (AlertsFragment) getSupportFragment();
        }
    }

    private static final class AlertActionCallback extends AbstractSupportFragmentCallback<List<String>> {
        @Override
        public void onSuccess(List<String> result) {
            getAlertsFragment().setUpAlertsRefreshed();
        }

        @Override
        public void onFailure(Exception e) {
        }

        private AlertsFragment getAlertsFragment() {
            return (AlertsFragment) getSupportFragment();
        }
    }

    private static final class AlertsComparator implements Comparator<Alert> {
        @Override
        public int compare(Alert leftAlert, Alert rightAlert) {
            Date leftAlertTimestamp = new Date(leftAlert.getTimestamp());
            Date rightAlertTimestamp = new Date(rightAlert.getTimestamp());

            return leftAlertTimestamp.compareTo(rightAlertTimestamp);
        }
    }
}