Android Open Source - PathOfExileStatistics Main Activity






From Project

Back to project page PathOfExileStatistics.

License

The source code is released under:

Copyright ? 2013 by Adam Hellberg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Sof...

If you think the Android project PathOfExileStatistics listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (c) 2013 by Adam Hellberg.//  w ww. j a v a2s  . c  o  m
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package com.f16gaming.pathofexilestatistics;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle;
import android.view.*;
import android.widget.*;
import net.simonvt.numberpicker.NumberPicker;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.json.JSONException;

import java.util.ArrayList;
import java.util.Collections;

/**
 * Created with IntelliJ IDEA.
 * User: Gamer
 * Date: 2013-02-28
 * Time: 02:27
 * To change this template use File | Settings | File Templates.
 */
public class MainActivity extends Activity {
    private final String statsUrl = "http://api.pathofexile.com/leagues/%s?ladder=1&ladderOffset=%d&ladderLimit=%d";
    private final String normalLeague = "Standard";
    private final String hardcoreLeague = "Hardcore";
    private final int limit = 200;
    private final int max = 15000;
    private final int refreshWarningLimit = 4000; // Show warning if user tries to refresh more than this amount of entries

    private ProgressDialog progressDialog;
    private AlertDialog refreshWarningDialog;
    private AlertDialog rankGoDialog;
    private NumberPicker numberPicker;

    private ListView statsView;
    private View listFooter;

    private int offset = 0; // Num entries to load = limit + limit * offset
    private boolean showHardcore = false;
    private int refreshOffset = 0; // Current refresh offset
    private int refreshTopOffset = 0; // Cached top offset for refresh

    private ArrayList<PoeEntry> poeEntries;
    private EntryAdapter adapter;

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

        setContentView(R.layout.main);

        LayoutInflater inflater = getLayoutInflater();

        poeEntries = new ArrayList<PoeEntry>();

        statsView = (ListView) findViewById(R.id.statsView);

        listFooter = inflater.inflate(R.layout.list_footer, null);

        statsView.addFooterView(listFooter);

        statsView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                onStatsViewClick(position);
            }
        });

        AlertDialog.Builder refreshWarningBuilder = new AlertDialog.Builder(this);
        refreshWarningBuilder.setTitle(R.string.refresh_warning)
                             .setMessage(R.string.refresh_warning_message)
                             .setCancelable(true)
                             .setNegativeButton(R.string.refresh_warning_reset, new DialogInterface.OnClickListener() {
                                 @Override
                                 public void onClick(DialogInterface dialogInterface, int i) {
                                     resetList();
                                 }
                             })
                             .setPositiveButton(R.string.refresh_warning_confirm, new DialogInterface.OnClickListener() {
                                 @Override
                                 public void onClick(DialogInterface dialogInterface, int i) {
                                     refreshList(true);
                                 }
                             });

        refreshWarningDialog = refreshWarningBuilder.create();

        AlertDialog.Builder rankGoBuilder = new AlertDialog.Builder(this);
        View view = inflater.inflate(R.layout.rank_go_dialog, null);

        numberPicker = (net.simonvt.numberpicker.NumberPicker) view.findViewById(R.id.number_picker);
        numberPicker.setMinValue(1);
        numberPicker.setMaxValue(max);

        rankGoBuilder.setTitle(R.string.rank_go_dialog_title)
                     .setView(view)
                     .setCancelable(true)
                     .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
                         @Override
                         public void onClick(DialogInterface dialogInterface, int i) {
                             // Do nothing
                         }
                     })
                     .setPositiveButton(R.string.go, new DialogInterface.OnClickListener() {
                         @Override
                         public void onClick(DialogInterface dialogInterface, int i) {
                             int rawOffset = numberPicker.getValue() - 1;
                             if (rawOffset >= limit * offset && rawOffset <= limit + limit * offset)
                                 showToast(String.format(getString(R.string.toast_rank_showing), rawOffset + 1));
                             else
                                 updateList(showHardcore, false, rawOffset);
                         }
                     });

        rankGoDialog = rankGoBuilder.create();

        resetList();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        super.onPrepareOptionsMenu(menu);
        MenuItem toggleItem = menu.findItem(R.id.menu_toggle);
        toggleItem.setTitle(showHardcore ? R.string.menu_normal : R.string.menu_hardcore);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_refresh:
                refreshList();
                return true;
            case R.id.menu_search:
                rankGoDialog.show();
                return true;
            case R.id.menu_reset:
                resetList();
                return true;
            case R.id.menu_toggle:
                toggleList();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    /**
     * Gets the list offset relative to list start entry.
     * @return The zero-based offset relative to the start entry on the list.
     */
    private int getRelativeOffset() {
        return (int) Math.floor((double) poeEntries.size() / (double) limit) - 1;
    }

    /**
     * Gets the offset of the top list entry.
     * @return The zero-based offset value for the top entry on the list.
     */
    private int getTopOffset() {
        return offset - getRelativeOffset();
    }

    private void showToast(CharSequence text) {
        Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
    }

    private void showProgress(CharSequence text) {
        showProgress("", text);
    }

    private void showProgress(CharSequence title, CharSequence text) {
        if (progressDialog != null) {
            progressDialog.setTitle(title);
            progressDialog.setMessage(text);
            return;
        }

        progressDialog = ProgressDialog.show(this, title, text, true, false);
    }

    private void showProgress(CharSequence title, String format, Object... args) {
        showProgress(title, String.format(format, args));
    }

    private void hideProgress() {
        if (progressDialog == null)
            return;
        progressDialog.dismiss();
        progressDialog = null;
    }

    private void resetList() {
        offset = -1;
        updateList(showHardcore);
    }

    private void toggleList() {
        updateList(!showHardcore);
    }

    private void refreshList() {
        if (poeEntries.size() > refreshWarningLimit)
        {
            String message = getResources().getString(R.string.refresh_warning_message);
            refreshWarningDialog.setMessage(String.format(message, poeEntries.size()));
            refreshWarningDialog.show();
        } else
            refreshList(true);
    }

    private void refreshList(boolean confirmed) {
        if (!confirmed)
            return;

        // Get the offset we need to start loading from when refreshing
        // (Current offset subtracted with the number of offsets previously loaded)
        refreshOffset = getTopOffset();
        refreshTopOffset = getTopOffset();
        updateList(showHardcore,  true);
    }

    private void updateList(boolean hardcore) {
        updateList(hardcore, false);
    }

    private void updateList(boolean hardcore, boolean refresh) {
        updateList(hardcore, refresh, 0);
    }

    private void updateList(boolean hardcore, boolean refresh, int rawOffset) {
        if (hardcore != showHardcore) // Switching mode
            offset = 0;
        else if (!refresh && rawOffset == 0) // Not refreshing or jumping, load more entries
            offset++;
        else if (rawOffset > 0) // Calculate actual offset
            offset = (int) Math.floor((double) rawOffset / (double) limit);

        if (refresh)
            showProgress(getString(R.string.refreshing), getString(R.string.refreshing_page), refreshOffset + 1, offset + 1);
        else
            showProgress(getString(R.string.retrieving_data));

        // Get the league we want to load from
        String league = hardcore ? hardcoreLeague : normalLeague;

        // Construct proper URL
        // Refreshes start at 0 then build up to offset var, hence the separate refreshOffset var
        String url = refresh ?
                String.format(statsUrl, league, limit * refreshOffset, limit)
                : String.format(statsUrl, league, limit * offset, limit);

        // Create the task object to handle our request
        new RetrieveStatsTask(new RetrieveStatsListener() {
            @Override
            public void handleResponse(StatsResponse response, boolean hardcore, boolean refresh, boolean jump) {
                updateList(response, hardcore, refresh, jump);
            }
        }, hardcore, refresh, rawOffset > 0).execute(url); // And execute it!
    }

    private void updateList(StatsResponse response, boolean hardcore, boolean refresh, boolean jump) {
        if (response == null) {
            // Something went wrong and we didn't even get a response body
            showToast(getString(R.string.retrieve_data_fail));
            hideProgress();
            return;
        }

        try {
            StatusLine status = response.getStatus();
            // Should probably make this handle status codes listed on PoE API
            if (status.getStatusCode() == HttpStatus.SC_OK) {
                String responseString = response.getResponseString();
                PoeEntry[] newEntries = PoeEntry.getEntriesFromJSONString(responseString);

                // This was a mode switch, refresh or jump; clear the previous entries
                // We also clear it if the offset is 0 (first execution or list reset)
                if (offset == 0 || hardcore != showHardcore || (refresh && refreshOffset == refreshTopOffset) || jump)
                    poeEntries.clear();

                // Add the newly loaded entries
                Collections.addAll(poeEntries, newEntries);

                // Continue loading entries if this is a refresh and it's not done yet
                if (refresh && refreshOffset < offset) {
                    refreshOffset++;
                    updateList(hardcore, true);
                    return;
                }

                // If adapter var is null, this is the first updateList execution
                if (adapter == null) {
                    adapter = new EntryAdapter(this, poeEntries, this, getResources());
                    statsView.setAdapter(adapter);
                } else { // Otherwise just notify it that data has changed
                    adapter.notifyDataSetChanged();
                }

                // Show a toast to the user telling them the data is updated
                showToast(hardcore ? getString(R.string.hardcore_updated) : getString(R.string.normal_updated));

                // Remove the "Load more entries" at bottom of list if we reached the maximum
                if (hardcore == showHardcore && limit + limit * offset >= max)
                    statsView.removeFooterView(listFooter);
                else if (hardcore != showHardcore)
                {
                    // Otherwise add it back if it's not there
                    if (statsView.getFooterViewsCount() == 0)
                        statsView.addFooterView(listFooter);
                    statsView.setSelection(0);
                }

                // Update the showHardcore var to reflect new value
                showHardcore = hardcore;

                // Update title to new mode
                setTitle(showHardcore ? R.string.hardcore : R.string.normal);

                // Invalidate the options menu to update the text properly
                // (This is only needed and supported on SDK level >= 11, since older versions
                // always update the menu every time it's shown
                if (Build.VERSION.SDK_INT >= 11)
                    invalidateOptionsMenu();
            } else {
                showToast(getString(R.string.retrieve_data_fail));
            }
        } catch (JSONException e) { // Invalid JSON returned
            showToast(getString(R.string.json_parse_error));
        } catch (ClassCastException e) { // Usually indicative of a JSON parsing error
            showToast(getString(R.string.retrieve_data_fail));
        }

        hideProgress();
    }

    private void onStatsViewClick(int index) {
        if (poeEntries == null || index < 0)
            return;

        if (index >= poeEntries.size() && index == statsView.getCount() - 1) {
            updateList(showHardcore);
        } else {
            PoeEntry entry = poeEntries.get(index);
            AlertDialog dialog = entry.getInfoDialog(this, getResources());
            dialog.show();
        }
    }
}




Java Source Code List

com.f16gaming.pathofexilestatistics.EntryAdapter.java
com.f16gaming.pathofexilestatistics.MainActivity.java
com.f16gaming.pathofexilestatistics.PoeEntry.java
com.f16gaming.pathofexilestatistics.RetrieveStatsListener.java
com.f16gaming.pathofexilestatistics.RetrieveStatsTask.java
com.f16gaming.pathofexilestatistics.StatsResponse.java