ca.zadrox.dota2esportticker.ui.LiveContentView.java Source code

Java tutorial

Introduction

Here is the source code for ca.zadrox.dota2esportticker.ui.LiveContentView.java

Source

/*
 * Copyright 2014 Nicholas Liu
 *
 * 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 ca.zadrox.dota2esportticker.ui;

import android.app.LoaderManager;
import android.content.Loader;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.widget.Toolbar;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;

import ca.zadrox.dota2esportticker.R;
import ca.zadrox.dota2esportticker.data.gson.model.DotaGameData;
import ca.zadrox.dota2esportticker.data.gson.model.FinishedGame;
import ca.zadrox.dota2esportticker.data.gson.model.Game;
import ca.zadrox.dota2esportticker.ui.widget.ObservableScrollView;
import ca.zadrox.dota2esportticker.util.DotaMapModel;
import ca.zadrox.dota2esportticker.util.LogUtils;
import ca.zadrox.dota2esportticker.util.PrefUtils;
import ca.zadrox.dota2esportticker.util.StringUtils;
import ca.zadrox.dota2esportticker.util.UIUtils;
import ca.zadrox.dota2esportticker.util.steamapi.SAPIGameResultLoader;
import ca.zadrox.dota2esportticker.util.steamapi.SAPISingleLiveGameLoader;
import ca.zadrox.dota2esportticker.util.xform.CropImageTransform;

interface LiveContentView {
    void initPlayerMapIcon(int playerSlot, int heroId);

    void setViewVisible(int resId, boolean isVisible);

    void updatePlayerMapIcon(int playerSlot, float x, float y, int state);

    void initPlayerView(int playerSlot, String name);

    void setPlayerKDA(int playerSlot, int k, int d, int a);

    void setPlayerCS(int playerSlot, int lh, int d);

    void setPlayerPortrait(int playerSlot, int resId);

    void setPlayerItem(int playerSlot, int itemSlot, int resId);

    void setPlayerDesc(int playerSlot, int playerLevel, String heroName);

    void setGameTime(String gameTime);

    void setGameScores(int radiantScore, int direScore);

    void setTeamHeaders(String radiantName, String direName);

    void addTick(int resId, String name, String details, int team);

    void addTickSeparator(String time);
}

/**
 * Created by Acco on 11/3/2014.
 */
public class LiveGameStatsActivity extends BaseActivity
        implements ObservableScrollView.Callbacks, LoaderManager.LoaderCallbacks<DotaGameData>, LiveContentView {

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

    private static final float PHOTO_ASPECT_RATIO = 1.5f;
    private static final int GAME_UPDATE_INTERVAL = 20000; // 20s
    public static String ARGS_GAME_TNL = "team_name_left";
    public static String ARGS_GAME_TNR = "team_name_right";
    public static String ARGS_GAME_TLL = "team_logo_left";
    public static String ARGS_GAME_TLR = "team_logo_right";
    public static String ARGS_GAME_TN = "tournament_name";
    public static String ARGS_GAME_BO = "best_of";
    public static String ARGS_GAME_MID = "match_id";

    private final int[] mPlayerMiniMapIcons = new int[] { R.id.radiant_player_one, R.id.radiant_player_two,
            R.id.radiant_player_three, R.id.radiant_player_four, R.id.radiant_player_five, R.id.dire_player_one,
            R.id.dire_player_two, R.id.dire_player_three, R.id.dire_player_four, R.id.dire_player_five };

    private final int[] itemViewIds = new int[] { R.id.player_item_one, R.id.player_item_two,
            R.id.player_item_three, R.id.player_item_four, R.id.player_item_five, R.id.player_item_six };

    private Handler mHandler = new Handler();
    private View[] mPlayerLayouts = new View[10];
    private double gameTime;
    private String mUrl;
    private String mMatchScore;
    private boolean mStarred;
    private boolean mInitStarred;
    private MenuItem mShareMenuItem;
    private View mScrollViewChild;
    private TextView mTitle;
    private TextView mSubtitle;
    private Callback mLoadMapCallback = new Callback() {
        @Override
        public void onSuccess() {
            mDetailsContainer.animate().alpha(1).translationY(0).setDuration(400).start();
        }

        @Override
        public void onError() {

        }
    };
    private ObservableScrollView mScrollView;
    private ImageView mapView;
    private View mHeaderBox;
    private View mDetailsContainer;
    private int mPhotoHeightPixels;
    private int mHeaderHeightPixels;
    private int mapX;
    private int mapY;
    private long matchId;
    private boolean mHasPhoto;
    private View mGameViewContainer;
    private ImageView mGameImageView;
    private TextView mGameScoreViewLeft;
    private TextView mGameScoreViewRight;
    private TextView mGameTimeView;
    private ProgressBar mUpdateProgressBar;
    private ProgressBarAnimation mUpdateProgressAnim;

    private boolean gameCompleted = false;
    private static final String KEY_GAME_COMPLETE = "game_complete";

    private LinearLayout tickerLayout;
    private DrawerLayout mDrawerLayout;
    private Runnable mGameUpdaterRunnable = new Runnable() {
        @Override
        public void run() {
            Loader loader = getLoaderManager().getLoader(0);
            if (loader != null)
                loader.forceLoad();
        }
    };

    private Runnable mGameResultRunnable = new Runnable() {
        @Override
        public void run() {
            Loader loader = getLoaderManager().getLoader(1);
            if (loader != null)
                loader.forceLoad();
        }
    };

    private LiveTickerAdapter mLiveTickerAdapter;
    private ListView mDrawerListView;
    private float mMaxHeaderElevation;
    private LiveContentPresenter mPresenter;
    private ViewTreeObserver.OnGlobalLayoutListener mGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            recomputePhotoAndScrollingMetrics();
        }
    };

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.menu_ticker:
            mDrawerLayout.openDrawer(Gravity.END);
        }
        return super.onOptionsItemSelected(item);
    }

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

    private void setBundleContents() {
        final Toolbar toolbar = getActionBarToolbar();

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mTitle.setText(getIntent().getStringExtra(ARGS_GAME_TNL) + " vs "
                        + getIntent().getStringExtra(ARGS_GAME_TNR));
                mSubtitle.setText(getIntent().getStringExtra(ARGS_GAME_TN) + " - "
                        + getIntent().getStringExtra(ARGS_GAME_BO));
                toolbar.setTitle("");
            }
        });

        toolbar.setNavigationIcon(R.drawable.ic_up);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onBackPressed();
            }
        });

        matchId = getIntent().getLongExtra(ARGS_GAME_MID, 1);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_live_stats);

        mMaxHeaderElevation = getResources().getDimensionPixelSize(R.dimen.session_detail_max_header_elevation);

        mScrollView = (ObservableScrollView) findViewById(R.id.game_scroll_view);
        mScrollView.addCallbacks(this);
        ViewTreeObserver vto = mScrollView.getViewTreeObserver();
        if (vto.isAlive()) {
            vto.addOnGlobalLayoutListener(mGlobalLayoutListener);
        }

        mScrollViewChild = findViewById(R.id.game_scroll_view_child);

        mDetailsContainer = findViewById(R.id.game_details_container);

        mDetailsContainer.setAlpha(0);
        mDetailsContainer.setY(1200);

        mHeaderBox = findViewById(R.id.header_game);
        mGameViewContainer = findViewById(R.id.game_photo_container);

        mGameImageView = (ImageView) findViewById(R.id.game_photo);
        mGameTimeView = (TextView) findViewById(R.id.game_time_view);
        mGameScoreViewLeft = (TextView) findViewById(R.id.game_score_view_left);
        mGameScoreViewRight = (TextView) findViewById(R.id.game_score_view_right);
        tickerLayout = (LinearLayout) findViewById(R.id.sidedrawer);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mTitle = (TextView) findViewById(R.id.header_title);
        mSubtitle = (TextView) findViewById(R.id.header_subtitle);
        mUpdateProgressBar = (ProgressBar) findViewById(R.id.header_progressbar);

        mapView = (ImageView) findViewById(R.id.game_map_view);
        mHasPhoto = true;
        mGameImageView.setColorFilter(Color.rgb(123, 123, 123), android.graphics.PorterDuff.Mode.MULTIPLY);

        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();

        Picasso.with(this).load(R.drawable.drawable_dota_bg_dire_ancient).config(Bitmap.Config.ARGB_8888)
                .resize(Math.round(displayMetrics.widthPixels * PHOTO_ASPECT_RATIO * 2 / 3),
                        displayMetrics.widthPixels * 2 / 3)
                .transform(new CropImageTransform(displayMetrics.heightPixels, displayMetrics.widthPixels))
                .into(mGameImageView);

        setBundleContents();
        initMapView();

        mPresenter = new LiveStatsPresenter(this);
        mLiveTickerAdapter = new LiveTickerAdapter(this, R.layout.sidedrawer_list_item);

        if (savedInstanceState != null) {
            mLiveTickerAdapter.onRestoreInstanceState(savedInstanceState);
            gameCompleted = savedInstanceState.getBoolean(KEY_GAME_COMPLETE, false);
        }

        mDrawerListView = (ListView) findViewById(R.id.sidedrawer_items_list);
        mDrawerListView.setAdapter(mLiveTickerAdapter);

        mUpdateProgressAnim = new ProgressBarAnimation(mUpdateProgressBar, 2000, 0);
        mUpdateProgressAnim.setDuration(GAME_UPDATE_INTERVAL);
        mUpdateProgressAnim.setInterpolator(new LinearInterpolator());

        if (!PrefUtils.hasLiveDrawerBeenShown(this)) {
            mDrawerLayout.openDrawer(Gravity.END);
            Toast.makeText(this, "Match events are shown in the right drawer", Toast.LENGTH_SHORT).show();
            PrefUtils.setLiveDrawerShown(this);
        }
    }

    private void recomputePhotoAndScrollingMetrics() {
        mHeaderHeightPixels = mHeaderBox.getHeight();

        mPhotoHeightPixels = 0;
        if (mHasPhoto) {
            mPhotoHeightPixels = (int) (mGameImageView.getWidth() / PHOTO_ASPECT_RATIO);
            mPhotoHeightPixels = Math.min(mPhotoHeightPixels, mScrollView.getHeight() * 2 / 3);
        }

        ViewGroup.LayoutParams lp;
        lp = mGameViewContainer.getLayoutParams();
        if (lp.height != mPhotoHeightPixels) {
            lp.height = mPhotoHeightPixels;
            mGameViewContainer.setLayoutParams(lp);
        }

        ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) mDetailsContainer.getLayoutParams();
        if (mlp.topMargin != mHeaderHeightPixels + mPhotoHeightPixels) {
            mlp.topMargin = mHeaderHeightPixels + mPhotoHeightPixels;
            mDetailsContainer.setLayoutParams(mlp);
        }

        onScrollChanged(0, 0); // trigger scroll handling
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mGameUpdaterRunnable != null) {
            mHandler.removeCallbacks(mGameUpdaterRunnable);
        }

        if (mGameResultRunnable != null) {
            mHandler.removeCallbacks(mGameResultRunnable);
        }

        if (mScrollView == null) {
            return;
        }

        ViewTreeObserver vto = mScrollView.getViewTreeObserver();
        if (vto.isAlive()) {
            vto.removeOnGlobalLayoutListener(mGlobalLayoutListener);
        }
    }

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

        LoaderManager manager = getLoaderManager();
        manager.initLoader(0, null, this);
        manager.initLoader(1, null, this);
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mGameUpdaterRunnable != null) {
            mHandler.removeCallbacks(mGameUpdaterRunnable);
        }
    }

    @Override
    public void onScrollChanged(int deltaX, int deltaY) {
        int scrollY = mScrollView.getScrollY();

        float newTop = Math.max(mPhotoHeightPixels, scrollY);
        mHeaderBox.setTranslationY(newTop);

        float gapFillProgress = 1;
        if (mPhotoHeightPixels != 0) {
            gapFillProgress = Math.min(Math.max(UIUtils.getProgress(scrollY, 0, mPhotoHeightPixels), 0), 1);
        }

        ViewCompat.setElevation(mHeaderBox, gapFillProgress * mMaxHeaderElevation);

        // Move background photo (parallax effect)
        mGameViewContainer.setTranslationY(scrollY * 0.5f);
    }

    private void initMapView() {
        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();

        int minHeight = displayMetrics.widthPixels > displayMetrics.heightPixels
                ? displayMetrics.heightPixels - UIUtils.calculateActionBarSize(this)
                : displayMetrics.widthPixels;

        mapX = mapY = minHeight - getResources().getDimensionPixelSize(R.dimen.keyline_1) * 2;

        Picasso.with(this).load(R.drawable.dota2_map).config(Bitmap.Config.RGB_565).resize(mapX, mapY).into(mapView,
                mLoadMapCallback);

        for (int i = 0; i < DotaMapModel.DIRE_TOWERS.length; i++) {
            int x = DotaMapModel.scaleToNewMapSize(DotaMapModel.DIRE_TOWERS_X[i], mapX);
            int y = DotaMapModel.scaleToNewMapSize(DotaMapModel.DIRE_TOWERS_Y[i], mapY);

            View v = findViewById(DotaMapModel.DIRE_TOWERS[i]);
            v.setX(x);
            v.setY(y);
            v.setBackground(getResources().getDrawable(R.drawable.dire_tower));
        }

        for (int i = 0; i < DotaMapModel.DIRE_STRUCTURES.length; i++) {
            int x = DotaMapModel.scaleToNewMapSize(DotaMapModel.DIRE_STRUCTURES_X[i], mapX);
            int y = DotaMapModel.scaleToNewMapSize(DotaMapModel.DIRE_STRUCTURES_Y[i], mapY);

            View v = findViewById(DotaMapModel.DIRE_STRUCTURES[i]);
            v.setX(x);
            v.setY(y);
            v.setBackground(getResources().getDrawable(R.drawable.dire_hero_oval));
        }

        for (int i = 0; i < DotaMapModel.RADIANT_TOWERS.length; i++) {
            int x = DotaMapModel.scaleToNewMapSize(DotaMapModel.RADIANT_TOWERS_X[i], mapX);
            int y = DotaMapModel.scaleToNewMapSize(DotaMapModel.RADIANT_TOWERS_Y[i], mapY);

            View v = findViewById(DotaMapModel.RADIANT_TOWERS[i]);
            v.setX(x);
            v.setY(y);
            v.setBackground(getResources().getDrawable(R.drawable.radiant_tower));
        }

        for (int i = 0; i < DotaMapModel.RADIANT_STRUCTURES.length; i++) {
            int x = DotaMapModel.scaleToNewMapSize(DotaMapModel.RADIANT_STRUCTURES_X[i], mapX);
            int y = DotaMapModel.scaleToNewMapSize(DotaMapModel.RADIANT_STRUCTURES_Y[i], mapY);

            View v = findViewById(DotaMapModel.RADIANT_STRUCTURES[i]);
            v.setX(x);
            v.setY(y);
            v.setBackground(getResources().getDrawable(R.drawable.radiant_hero_oval));
        }

        final int iconSizeRoshan = Math.round(
                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics()));

        ImageView v = (ImageView) findViewById(DotaMapModel.ROSHAN);
        v.setX(DotaMapModel.scaleToNewMapSize(DotaMapModel.ROSHAN_X, mapX));
        v.setY(DotaMapModel.scaleToNewMapSize(DotaMapModel.ROSHAN_Y, mapY));

        Picasso.with(this).load(R.drawable.drawable_map_roshan).resize(iconSizeRoshan, iconSizeRoshan).centerCrop()
                .into(v);
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        getLoaderManager().destroyLoader(0);
        getLoaderManager().destroyLoader(1);
        finish();
        overridePendingTransition(R.anim.anim_scale_in, R.anim.anim_slide_out);
    }

    public void setViewVisible(int viewId, boolean isVisible) {
        findViewById(viewId).setVisibility(isVisible ? View.VISIBLE : View.INVISIBLE);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mLiveTickerAdapter.onSaveInstanceState(outState);
        outState.putBoolean(KEY_GAME_COMPLETE, gameCompleted);
    }

    @Override
    public void initPlayerMapIcon(int playerSlot, int resId) {
        int iconSize = Math.round(
                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics()));

        int paddingSize = Math.round(
                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics()));

        (findViewById(mPlayerMiniMapIcons[playerSlot])).setPadding(paddingSize, paddingSize, paddingSize,
                paddingSize);

        Picasso.with(this).load(resId).resize(iconSize, iconSize).centerCrop()
                .into((ImageView) findViewById(mPlayerMiniMapIcons[playerSlot]));
    }

    @Override
    public void updatePlayerMapIcon(int playerSlot, float x, float y, int resId) {
        int scaledX = DotaMapModel.scaleXFromAPI(x, mapX);
        int scaledY = DotaMapModel.scaleYFromAPI(y, mapY);

        (findViewById(mPlayerMiniMapIcons[playerSlot])).animate().setDuration(250).translationX(scaledX)
                .translationY(scaledY).setInterpolator(new AccelerateDecelerateInterpolator()).start();

        findViewById(mPlayerMiniMapIcons[playerSlot]).setBackground(getResources().getDrawable(resId));
    }

    @Override
    public void initPlayerView(int playerSlot, String name) {

        final ViewGroup teamBlock = (playerSlot < 5 ? (ViewGroup) findViewById(R.id.game_radiant_block)
                : (ViewGroup) findViewById(R.id.game_dire_block));

        mPlayerLayouts[playerSlot] = getLayoutInflater().inflate(R.layout.player_live_detail, teamBlock, false);

        ((TextView) mPlayerLayouts[playerSlot].findViewById(R.id.player_name)).setText(name);

        teamBlock.addView(mPlayerLayouts[playerSlot]);

    }

    @Override
    public void setPlayerKDA(int playerSlot, int k, int d, int a) {
        ((TextView) mPlayerLayouts[playerSlot].findViewById(R.id.player_kda)).setText(k + " / " + d + " / " + a);
    }

    @Override
    public void setPlayerCS(int playerSlot, int lh, int d) {
        ((TextView) mPlayerLayouts[playerSlot].findViewById(R.id.player_lhd)).setText(lh + " / " + d);
    }

    @Override
    public void setPlayerPortrait(int playerSlot, int resId) {
        Picasso.with(this).load(resId)
                .into((ImageView) mPlayerLayouts[playerSlot].findViewById(R.id.player_hero_logo));
    }

    @Override
    public void setPlayerItem(int playerSlot, int itemSlot, int resId) {
        ImageView imageView = (ImageView) mPlayerLayouts[playerSlot].findViewById(itemViewIds[itemSlot]);
        switch (resId) {
        case 0:
            imageView.animate().setDuration(200).alpha(0).setInterpolator(new AccelerateInterpolator());
        default:
            imageView.setImageResource(resId);
            imageView.animate().setDuration(200).alpha(1).setInterpolator(new DecelerateInterpolator());
        }
    }

    @Override
    public void setPlayerDesc(int playerSlot, int playerLevel, String heroName) {
        ((TextView) mPlayerLayouts[playerSlot].findViewById(R.id.player_hero_detail))
                .setText("Lv " + playerLevel + " " + heroName);
    }

    @Override
    public void setGameTime(String gameTime) {
        mGameTimeView.setText(gameTime);
    }

    @Override
    public void setGameScores(int radiantScore, int direScore) {
        mGameScoreViewLeft.setText(Integer.toString(radiantScore));
        mGameScoreViewRight.setText(Integer.toString(direScore));
    }

    @Override
    public void setTeamHeaders(String radiantName, String direName) {
        ((TextView) findViewById(R.id.game_radiant_header)).setText(radiantName);
        ((TextView) findViewById(R.id.game_dire_header)).setText(direName);

        ImageView mGameTeamLeftImageView = (ImageView) findViewById(R.id.game_team_left_photo);
        ImageView mGameTeamRightImageView = (ImageView) findViewById(R.id.game_team_right_photo);

        String intentLeftName = getIntent().getStringExtra(ARGS_GAME_TNL);

        if (StringUtils.compareTokensToTokens(intentLeftName, direName)) {
            Picasso.with(this).load(getIntent().getStringExtra(ARGS_GAME_TLL)).fit().into(mGameTeamRightImageView);
            Picasso.with(this).load(getIntent().getStringExtra(ARGS_GAME_TLR)).fit().into(mGameTeamLeftImageView);

        } else {

            Picasso.with(this).load(getIntent().getStringExtra(ARGS_GAME_TLL)).fit().into(mGameTeamLeftImageView);
            Picasso.with(this).load(getIntent().getStringExtra(ARGS_GAME_TLR)).fit().into(mGameTeamRightImageView);

        }
    }

    @Override
    public void addTick(int resId, String name, String details, int team) {
        if (gameCompleted) {
            return;
        }

        TickerEvent tickerEvent = new TickerEvent();
        tickerEvent.resId = resId;
        tickerEvent.pName = name;
        tickerEvent.pEvents = details;
        tickerEvent.team = team;

        mLiveTickerAdapter.insert(tickerEvent, 0);
    }

    @Override
    public void addTickSeparator(String time) {
        TickerSeparator tickerSeparator = new TickerSeparator();
        tickerSeparator.time = time;

        mLiveTickerAdapter.insert(tickerSeparator, 0);
    }

    @Override
    public Loader<DotaGameData> onCreateLoader(int id, Bundle args) {
        if (id == 0) {
            return new SAPISingleLiveGameLoader(this, matchId);
        } else {
            return new SAPIGameResultLoader(this, matchId);
        }
    }

    @Override
    public void onLoadFinished(Loader<DotaGameData> loader, DotaGameData data) {
        if (data == null && loader.getId() == 0) {

            // if data is null, then we didn't receive anything from valve servers.
            // there's a chance that the game is done, so...

            mHandler.post(mGameResultRunnable);

        } else if (data == null && loader.getId() == 1) {

            // there's a chance that the steam api is down, should "wait", but attempt to fetch
            // new data.

            mHandler.postDelayed(mGameUpdaterRunnable, GAME_UPDATE_INTERVAL);

            mUpdateProgressBar.setProgress(2000);
            mUpdateProgressBar.startAnimation(mUpdateProgressAnim);

        } else if (data.getType() == 50) {

            // this only comes from gameresulttaskloader indicating that there's no result:
            // only means that the game may still be live, so we'll try to grab new data.

            mHandler.postDelayed(mGameUpdaterRunnable, GAME_UPDATE_INTERVAL);

            mUpdateProgressBar.setProgress(2000);
            mUpdateProgressBar.startAnimation(mUpdateProgressAnim);

        } else if (data.getType() == 0) {

            // this only comes from gamedetailtaskloader indicating that there's data.
            // we should process it, then schedule an update to fetch new data.
            // we should keep the logic for doing live/result data here only.

            mPresenter.processNewData((Game) data);
            mHandler.postDelayed(mGameUpdaterRunnable, GAME_UPDATE_INTERVAL);

            LogUtils.LOGD(TAG, "gotMatchData");

            mUpdateProgressBar.setProgress(2000);
            mUpdateProgressBar.startAnimation(mUpdateProgressAnim);

        } else if (data.getType() == 1) {

            // this only comes from gameresulttaskloader indicating result was found:
            // we should process it, then not bother scheduling any further updates.

            LogUtils.LOGD(TAG, "gotResultData");

            mPresenter.processResultData((FinishedGame) data);

            gameCompleted = true;

        }

    }

    @Override
    public void onLoaderReset(Loader<DotaGameData> loader) {

    }

    class ProgressBarAnimation extends Animation {
        private ProgressBar progressBar;
        private float mStart;
        private float mEnd;

        public ProgressBarAnimation(ProgressBar progressBar, float start, float end) {
            super();
            this.progressBar = progressBar;
            mStart = start;
            mEnd = end;
        }

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            float value = mStart + (mEnd - mStart) * interpolatedTime;
            progressBar.setProgress((int) value);
        }
    }

}