package what.whatandroid.request; import android.app.Activity; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.support.v7.app.AlertDialog; import android.text.Editable; import android.text.TextWatcher; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.Spinner; import android.widget.TextView; import api.cli.Utils; import api.requests.Request; import api.soup.MySoup; import what.whatandroid.R; /** * Dialog for selecting amount of bounty to add to some request */ public class VoteDialog extends DialogFragment implements TextWatcher, AdapterView.OnItemSelectedListener { /** * Receive the amount of bounty the user is adding in bytes */ public interface VoteDialogListener { /** * Add some amount of bounty to the request * * @param request id of request to add bounty to * @param amt amount of bounty in bytes */ public void addBounty(int request, long amt); } /** * Constants for size of megabyte and gigabyte in bytes and the minimum vote (20 MB) */ private static final long megaByte = 1048576, gigaByte = 1073741824, minVote = 20 * megaByte; private static final String REQUEST_TAX = "what.whatandroid.REQUEST_TAX"; /** * Request we're deciding to vote on and its tax percentage */ private int requestId = -1; private float taxPercent; /** * Input text to enter size and spinner to select units */ private EditText size; private Spinner units; /** * Views to display the amount after tax, user's upload and ratio if they make the vote */ private TextView afterTax, upload, ratio, warning; /** * The dialog itself, so we can disable the positive button on invalid input */ private AlertDialog dialog; /** * Listener to send an add bounty request too */ private VoteDialogListener listener; /** * Use this factory method to create a vote dialog displaying a bounty vote prompt for * the request */ public static VoteDialog newInstance(Request r){ VoteDialog d = new VoteDialog(); Bundle args = new Bundle(); args.putInt(RequestActivity.REQUEST_ID, r.getResponse().getRequestId().intValue()); args.putFloat(REQUEST_TAX, r.getResponse().getRequestTax().floatValue()); d.setArguments(args); return d; } public VoteDialog(){ //Required empty ctor } @Override public Dialog onCreateDialog(Bundle savedInstanceState){ requestId = getArguments().getInt(RequestActivity.REQUEST_ID); taxPercent = getArguments().getFloat(REQUEST_TAX); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); LayoutInflater inflater = getActivity().getLayoutInflater(); View view = inflater.inflate(R.layout.dialog_request_vote, null); size = (EditText)view.findViewById(R.id.size); units = (Spinner)view.findViewById(R.id.units); afterTax = (TextView)view.findViewById(R.id.after_tax); upload = (TextView)view.findViewById(R.id.new_upload); ratio = (TextView)view.findViewById(R.id.new_ratio); warning = (TextView)view.findViewById(R.id.warning); size.addTextChangedListener(this); ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getActivity(), R.array.vote_units, android.R.layout.simple_spinner_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); units.setAdapter(adapter); units.setOnItemSelectedListener(this); initText(); builder.setView(view) .setTitle("Select Vote Amount") .setPositiveButton(R.string.vote, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { long unitsAmt = units.getSelectedItemPosition() == 0 ? megaByte : gigaByte; float voteAmt = Float.parseFloat(size.getText().toString()); listener.addBounty(requestId, (long) (voteAmt * unitsAmt)); } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which){ dialog.cancel(); } }); dialog = builder.create(); //Start the view with the site minimum vote of 20 MB size.setText("20"); size.setSelection(2); return dialog; } /** * Listen to changes on the vote amount and update the new upload/ratio fields appropriately */ @Override public void afterTextChanged(Editable s){ String input = s.toString(); if (input.isEmpty()){ initText(); if (dialog.getButton(DialogInterface.BUTTON_POSITIVE) != null){ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); } warning.setVisibility(View.VISIBLE); warning.setText("Minumum vote: " + Utils.toHumanReadableSize(minVote)); } else { updateVote(Float.parseFloat(input)); } } /** * Listen to changes on the vote size and update the new upload/ratio fields appropriately */ @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id){ String input = size.getText().toString(); if (!input.isEmpty()){ updateVote(Float.parseFloat(input)); } } /** * Compute the new user stats as a result of this vote and validate that the vote is ok * to make */ private void updateVote(float voteAmt){ long unitsAmt = units.getSelectedItemPosition() == 0 ? megaByte : gigaByte; long voteBytes = (long)(voteAmt * unitsAmt); long newUpload = MySoup.getIndex().getResponse().getUserstats().getUploaded().longValue() - voteBytes; float newRatio = newUpload / MySoup.getIndex().getResponse().getUserstats().getDownloaded().floatValue(); float requiredRatio = MySoup.getIndex().getResponse().getUserstats().getRequiredRatio().floatValue(); if (voteBytes < minVote || newUpload < 0){ if (dialog.getButton(DialogInterface.BUTTON_POSITIVE) != null){ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false); } warning.setVisibility(View.VISIBLE); if (voteBytes < minVote){ warning.setText("Minumum vote: " + Utils.toHumanReadableSize(minVote)); } else { warning.setText("You can't afford that vote"); } initText(); } else { if (dialog.getButton(DialogInterface.BUTTON_POSITIVE) != null){ dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true); } afterTax.setText(Utils.toHumanReadableSize((long)(voteBytes - voteBytes * taxPercent))); upload.setText(Utils.toHumanReadableSize(newUpload)); setRatio(newRatio); //Also warn the user about voting themselves into ratio watch but don't prevent it if (newRatio < requiredRatio){ warning.setVisibility(View.VISIBLE); warning.setText("Your ratio will fall below your required ratio"); } else { warning.setVisibility(View.GONE); } } } /** * Initialize the text views to their initial values (ie no vote) */ private void initText(){ afterTax.setText("0.00 MB"); upload.setText(Utils.toHumanReadableSize(MySoup.getIndex().getResponse().getUserstats().getUploaded().longValue())); setRatio(MySoup.getIndex().getResponse().getUserstats().getRatio().floatValue()); } /** * Set the updated ratio for the vote. -1 is interpreted as infinity since that's what the API * gives us back for infinite ratio in the index */ private void setRatio(float userRatio){ if (userRatio == -1){ userRatio = Float.POSITIVE_INFINITY; } ratio.setText(String.format("%.2f", userRatio) + " / " + String.format("%.2f", MySoup.getIndex().getResponse().getUserstats().getRequiredRatio().floatValue())); } @Override public void onAttach(Activity activity){ super.onAttach(activity); try { listener = (VoteDialogListener)activity; } catch (ClassCastException e){ throw new ClassCastException(activity.toString() + " must implement VoteDialogListener"); } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after){ } @Override public void onTextChanged(CharSequence s, int start, int before, int count){ } @Override public void onNothingSelected(AdapterView<?> parent){ } }