Back to project page PathOfExileStatistics.
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.
/* * 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(); } } }