package com.markupartist.iglaset.activity;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.DialogInterface.OnClickListener;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationUtils;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RatingBar;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.RatingBar.OnRatingBarChangeListener;
import android.widget.SimpleAdapter.ViewBinder;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import com.markupartist.android.widget.ActionBar;
import com.markupartist.android.widget.ActionBar.IntentAction;
import com.markupartist.iglaset.IglasetApplication;
import com.markupartist.iglaset.R;
import com.markupartist.iglaset.provider.AuthStore;
import com.markupartist.iglaset.provider.AuthStore.Authentication;
import com.markupartist.iglaset.provider.AuthenticationException;
import com.markupartist.iglaset.provider.BarcodeStore;
import com.markupartist.iglaset.provider.Comment;
import com.markupartist.iglaset.provider.CommentsStore;
import com.markupartist.iglaset.provider.Drink;
import com.markupartist.iglaset.provider.DrinksStore;
import com.markupartist.iglaset.provider.Drink.Volume;
import com.markupartist.iglaset.provider.Tag;
import com.markupartist.iglaset.util.ListUtils;
import com.markupartist.iglaset.util.MultiHashMap;
import com.markupartist.iglaset.widget.DrinkDescriptionAdapter;
import com.markupartist.iglaset.widget.SearchAction;
import com.markupartist.iglaset.widget.SectionedAdapter;
import com.markupartist.iglaset.widget.SectionedAdapter.Section;
import com.markupartist.iglaset.widget.VolumeAdapter;
public class DrinkDetailActivity extends ListActivity implements View.OnClickListener {
/**
* The id for the rating dialog
*/
private static final int DIALOG_RATE = 0;
/**
* The id for the not authenticated dialog
*/
private static final int DIALOG_NOT_AUTHENTICATED = 1;
/**
* The id for suggest barcode failed dialog
*/
private static final int DIALOG_SUGGEST_BARCODE_FAIL = 2;
/**
* The id for the choose add barcode method dialog
*/
private static final int DIALOG_CHOOSE_ADD_BARCODE_METHOD = 3;
/**
* The id for the add barcode manual dialog
*/
private static final int DIALOG_ADD_BARCODE_MANUAL = 4;
/**
* The id for showing the drink image dialog.
*/
private static final int DIALOG_SHOW_DRINK_IMAGE = 5;
/**
* The id for showing the comment add dialog.
*/
private static final int DIALOG_ADD_COMMENT = 6;
/**
* The id for the network problem dialog.
*/
private static final int DIALOG_SEARCH_NETWORK_PROBLEM = 7;
/**
* The request code for indicating that settings has been changed
*/
protected static final int REQUEST_CODE_SETTINGS_CHANGED = 0;
/**
* The log tag
*/
private static final String TAG = DrinkDetailActivity.class.getSimpleName();
private CommentsStore mCommentsStore = new CommentsStore();
private SimpleAdapter mCommentsAdapter;
private ArrayList<Comment> mComments;
private static Drink sDrink;
private UserRatingAdapter mUserRatingAdapter;
private AuthStore.Authentication mAuthentication;
private GetDrinkTask mGetDrinkTask;
private GetCommentsTask mGetCommentsTask;
private DrinkViewHolder mViewHolder;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drink_details);
mAuthentication = getAuthentication();
Bundle extras = getIntent().getExtras();
final Drink drink = extras.getParcelable(Intents.EXTRA_DRINK);
sDrink = drink;
ActionBar actionBar = (ActionBar) findViewById(R.id.actionbar);
actionBar.setHomeAction(new IntentAction(this, StartActivity.createIntent(this), R.drawable.ic_actionbar_home_default));
actionBar.setTitle(sDrink.getName());
actionBar.addAction(new SearchAction() {
@Override
public void performAction(View view) {
onSearchRequested();
}
});
// Populate drink details
View detailsLayout = this.findViewById(R.id.drink_detail_layout);
mViewHolder = new DrinkViewHolder(detailsLayout);
mViewHolder.populate(this, drink, mImageClickListener);
float rating = (drink.hasEstimatedRating() ? drink.getEstimatedRating() : drink.getAverageRating());
mViewHolder.getRateView().setRating(rating);
mUserRatingAdapter = new UserRatingAdapter(this, 0);
this.updateUserRatingInUi(drink.getUserRating());
mSectionedAdapter.addSectionFirst(0, getText(R.string.my_rating), mUserRatingAdapter);
if (mAuthentication != null && mAuthentication.looksValid()) {
launchGetDrinkTask(drink);
}
if(true == drink.hasDescription()) {
DrinkDescriptionAdapter adapter = new DrinkDescriptionAdapter(this, drink.getDescription());
mSectionedAdapter.addSection(0, getText(R.string.manufacturers_description), adapter);
}
ArrayList<Tag> tags = drink.getTags();
if(tags.isEmpty() == false) {
MultiHashMap<String, Tag> tagMap = ListUtils.toMultiHashMap(tags);
Set<Entry<String, List<Tag>>> nameSet = tagMap.entrySet();
for (Entry<String, List<Tag>> entry : nameSet) {
mSectionedAdapter.addSection(0, entry.getKey(),
new ArrayAdapter<Tag>(this,
R.layout.simple_row, entry.getValue()));
}
}
ArrayList<Volume> volumes = drink.getVolumes();
if (!volumes.isEmpty()) {
VolumeAdapter volumeAdapter = new VolumeAdapter(this, volumes);
mSectionedAdapter.addSection(1, (String) getText(R.string.packings), volumeAdapter);
}
// This is temporary till we have fixed a proper comments adapter.
mSectionedAdapter.addSection(2, (String) getText(R.string.comments),
createLoadingAdapter(getText(R.string.loading_comments)));
// Check if already have some data, used if screen is rotated.
@SuppressWarnings("unchecked")
final ArrayList<Comment> comments = (ArrayList<Comment>) getLastNonConfigurationInstance();
if (comments != null) {
updateCommentsInUi(comments);
} else if(drink.getCommentCount() == 0) {
// Update the comment list with an empty array
updateCommentsInUi(new ArrayList<Comment>());
} else {
launchGetCommentsTask(drink);
}
setListAdapter(mSectionedAdapter);
// Orphan barcode handler layout
View orphanLayout = findViewById(R.id.orphan_barcode_layout);
TextView textView = (TextView) orphanLayout.findViewById(R.id.orphan_barcode_text);
textView.setText(String.format(this.getString(R.string.add_suggested_barcode), getApp().getOrphanBarcode()));
Button buttonAdd = (Button) orphanLayout.findViewById(R.id.btn_add_orphan_code);
buttonAdd.setOnClickListener(this);
Button buttonForget = (Button) orphanLayout.findViewById(R.id.btn_forget_orphan_barcode);
buttonForget.setOnClickListener(this);
Button buttonCancel = (Button) orphanLayout.findViewById(R.id.btn_cancel);
buttonCancel.setOnClickListener(this);
this.registerReceiver(mBroadcastReceiver, new IntentFilter(Intents.ACTION_PUBLISH_DRINK));
}
@Override
public void onClick(View view) {
switch(view.getId()) {
case R.id.btn_add_orphan_code:
hideOrphanBarcodeLayout();
new SuggestBarcodeTask().execute(getApp().getOrphanBarcode(), sDrink, mAuthentication);
break;
case R.id.btn_forget_orphan_barcode:
hideOrphanBarcodeLayout();
getApp().clearOrphanBarcode();
break;
case R.id.btn_cancel:
hideOrphanBarcodeLayout();
break;
}
}
private final View.OnClickListener mImageClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
showDialog(DIALOG_SHOW_DRINK_IMAGE);
}
};
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(Intents.ACTION_PUBLISH_DRINK)) {
final Drink drink = (Drink) intent.getExtras().get(Intents.EXTRA_DRINK);
DrinkDetailActivity.this.onUpdatedDrink(drink);
}
}
};
private void showOrphanBarcodeLayout() {
View orphanLayout = findViewById(R.id.orphan_barcode_layout);
orphanLayout.setVisibility(View.VISIBLE);
Animation animation = AnimationUtils.loadAnimation(getBaseContext(), R.anim.push_up_in);
orphanLayout.startAnimation(animation);
}
private void hideOrphanBarcodeLayout() {
final View orphanLayout = findViewById(R.id.orphan_barcode_layout);
Animation animation = AnimationUtils.loadAnimation(getBaseContext(), R.anim.push_down_out);
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationEnd(Animation anim) {
orphanLayout.setVisibility(View.GONE);
}
@Override
public void onAnimationRepeat(Animation anim) {}
@Override
public void onAnimationStart(Animation anim) {}
});
orphanLayout.startAnimation(animation);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
if(shouldShowOrphanBarcodeLayout()) {
showOrphanBarcodeLayout();
}
}
private boolean shouldShowOrphanBarcodeLayout() {
return !TextUtils.isEmpty(getApp().getOrphanBarcode()) && isLoggedIn();
}
private IglasetApplication getApp() {
return (IglasetApplication) getApplication();
}
private AuthStore.Authentication getAuthentication() {
try {
return AuthStore.getInstance().getAuthentication(this);
} catch (AuthenticationException e) {
return null;
}
}
private boolean isLoggedIn() {
return mAuthentication != null && mAuthentication.looksValid();
}
@Override
protected void onResume() {
super.onResume();
mAuthentication = getAuthentication();
}
@Override
protected void onDestroy() {
cancelGetDrinkTask();
cancelGetCommentsTask();
unregisterReceiver(mBroadcastReceiver);
super.onDestroy();
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
restoreLocalState(savedInstanceState);
}
/**
* Restores the local state.
* @param savedInstanceState the bundle containing the saved state
*/
private void restoreLocalState(Bundle savedInstanceState) {
restoreBarcode(savedInstanceState);
}
/**
* Restores the barcode.
* @param savedInstanceState the saved state
*/
private void restoreBarcode(Bundle savedInstanceState) {
if (savedInstanceState.containsKey(Intents.EXTRA_BARCODE)) {
mBarcode = savedInstanceState.getString(Intents.EXTRA_BARCODE);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
saveBarcodeState(outState);
}
/**
* If there is any running search for routes, save it and process it later
* on.
* @param outState the out state
*/
private void saveBarcodeState(Bundle outState) {
outState.putString(Intents.EXTRA_BARCODE, mBarcode);
}
/**
* Called before this activity is destroyed, returns the previous search
* result. This list is used if the screen is rotated. Then we don't need
* to search for it again.
*/
@Override
public Object onRetainNonConfigurationInstance() {
return mComments;
}
private SimpleAdapter createLoadingAdapter(CharSequence loadingText) {
ArrayList<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
Map<String, Object> map = new HashMap<String, Object>();
map.put("text", loadingText);
list.add(map);
SimpleAdapter commentsAdapter = new SimpleAdapter(this, list,
R.layout.progress_bar,
new String[] { "text" },
new int[] {
R.id.search_progress_text
}
);
return commentsAdapter;
}
private void onUpdatedDrink(Drink drink) {
updateUserRatingInUi(drink.getUserRating());
mViewHolder.update(this, drink);
}
private void updateUserRatingInUi(float rating) {
final RatingBar userRatingBar = (RatingBar) findViewById(R.id.user_drink_rating);
mUserRatingAdapter.setUserRating(rating);
if (userRatingBar != null) {
userRatingBar.setRating(rating);
}
}
/**
* Update comments view.
* @param comments the comments
*/
private void updateCommentsInUi(ArrayList<Comment> comments) {
// Save the result to return it from onRetainNonConfigurationInstance.
mComments = comments;
ArrayList<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
if (comments.isEmpty()) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("text", getText(R.string.no_comments));
list.add(map);
mCommentsAdapter = new SimpleAdapter(this, list,
R.layout.simple_row,
new String[] { "text" },
new int[] {
R.id.simple_row_text
}
);
} else {
for (Comment comment : comments) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("nickname", comment.getNickname());
map.put("created", comment.getCreated());
map.put("comment", comment.getComment());
map.put("rating", comment.getRating());
list.add(map);
}
mCommentsAdapter = new SimpleAdapter(this, list,
R.layout.comment_row,
new String[] { "nickname", "created", "comment", "rating" },
new int[] {
R.id.comment_nickname,
R.id.comment_created,
R.id.comment_comment,
R.id.comment_rating,
}
);
mCommentsAdapter.setViewBinder(new ViewBinder() {
public boolean setViewValue(View view, Object data,
String textRepresentation) {
switch (view.getId()) {
case R.id.comment_nickname:
TextView nicknameView = (TextView) view;
nicknameView.setText(textRepresentation);
return true;
case R.id.comment_created:
TextView createdView = (TextView) view;
createdView.setText(textRepresentation);
return true;
case R.id.comment_comment:
TextView commentView = (TextView) view;
commentView.setText(textRepresentation);
return true;
case R.id.comment_rating:
RatingBar rateView = (RatingBar) view;
rateView.setRating(Float.parseFloat(textRepresentation));
return true;
}
return false;
}
});
}
mSectionedAdapter.removeSection(2);
mSectionedAdapter.addSection(2, (String) getText(R.string.comments), mCommentsAdapter);
// This is really ugly, but notifyDataSetChanged is crashing on some items...
setListAdapter(mSectionedAdapter);
//mSectionedAdapter.notifyDataSetChanged();
}
SectionedAdapter mSectionedAdapter = new SectionedAdapter() {
protected View getHeaderView(Section section, int index,
View convertView, ViewGroup parent) {
TextView result = (TextView) convertView;
if (convertView == null)
result = (TextView) getLayoutInflater().inflate(R.layout.header, null);
result.setText(section.caption);
return (result);
}
};
private String mBarcode;
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Section section = mSectionedAdapter.getSection(position);
Object item = mSectionedAdapter.getItem(position);
if (item instanceof Volume) {
Volume volume = (Volume) item;
startActivity(createInventoryIntent(volume));
} else if (item instanceof Tag) {
Tag tag = (Tag) item;
ArrayList<Integer> tags = new ArrayList<Integer>();
tags.add(tag.getId());
Intent searchIntent = new Intent(this, SearchResultActivity.class);
searchIntent.putExtra(SearchResultActivity.EXTRA_SEARCH_TAGS, tags);
searchIntent.putExtra(SearchResultActivity.EXTRA_SEARCH_TAGS_SELECTED, tag.getName());
startActivity(searchIntent);
} else if (section.adapter instanceof UserRatingAdapter) {
tryShowAuthenticatedDialog(DIALOG_RATE);
} else if (section.adapter instanceof DrinkDescriptionAdapter) {
DrinkDescriptionAdapter description = (DrinkDescriptionAdapter) section.adapter;
description.toggleVisibility();
}
}
@Override
public boolean onSearchRequested() {
startSearch(null, false, null, false);
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.options_menu_drink_detail, menu);
//TODO is this ("Search") really needed?
menu.removeItem(4);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_goto_iglaset:
// Since iglaset.se does not really care about the name we just
// removes the slash because otherwise iglaset.se will parse it
// as a directory.
String name = URLEncoder.encode(sDrink.getName().replace("/", ""));
Intent browserIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse("http://www.iglaset.se/dryck/" + name + "/" + sDrink.getId()));
startActivity(browserIntent);
return true;
case R.id.menu_search:
onSearchRequested();
return true;
case R.id.menu_rate:
tryShowAuthenticatedDialog(DIALOG_RATE);
return true;
case R.id.menu_scan:
tryShowAuthenticatedDialog(DIALOG_CHOOSE_ADD_BARCODE_METHOD);
return true;
case R.id.menu_add_comment:
tryShowAuthenticatedDialog(DIALOG_ADD_COMMENT);
return true;
case R.id.menu_home:
startActivity(new Intent(this, StartActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Try to show a dialog which requires that the user is logged in. If the
* user is logged in then the specified dialog will be shown, otherwise the
* standard authentication (DIALOG_NOT_AUTHENTICATED) dialog will be shown.
* @param dialog
*/
private void tryShowAuthenticatedDialog(int dialog) {
if(isLoggedIn()) {
showDialog(dialog);
} else {
showDialog(DIALOG_NOT_AUTHENTICATED);
}
}
@Override
protected Dialog onCreateDialog(int id) {
switch(id) {
case DIALOG_SUGGEST_BARCODE_FAIL:
return new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle("Ett fel inträffade")
.setMessage("Misslyckades med att spara streckkoden")
.setPositiveButton(R.string.retry, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new SuggestBarcodeTask().execute(mBarcode, sDrink, mAuthentication);
}
})
.setNegativeButton(getText(android.R.string.cancel), new OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
if(shouldShowOrphanBarcodeLayout()) {
showOrphanBarcodeLayout();
}
dismissDialog(DIALOG_SUGGEST_BARCODE_FAIL);
}
})
.create();
case DIALOG_RATE:
float userRating = mUserRatingAdapter.getUserRating();
final View layout = getLayoutInflater().inflate(R.layout.user_rating_dialog, null);
final TextView ratingValue = (TextView) layout.findViewById(R.id.add_user_rating_value);
ratingValue.setText("Ditt betyg " + userRating);
final RatingBar ratingBar = (RatingBar) layout.findViewById(R.id.add_user_rating);
ratingBar.setNumStars(5);
ratingBar.setStepSize(0.5f);
ratingBar.setRating(userRating / 2);
ratingBar.setOnRatingBarChangeListener(new OnRatingBarChangeListener() {
public void onRatingChanged(RatingBar ratingBar, float rating,
boolean fromUser) {
ratingValue.setText("Ditt betyg " + rating * 2);
}
});
return new AlertDialog.Builder(this)
.setTitle(getText(R.string.add_rating))
.setView(layout)
.setPositiveButton(android.R.string.ok, new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
new SetUserRatingTask().execute(ratingBar.getRating() * 2);
}
})
.setNegativeButton(android.R.string.cancel, new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
;
}
})
.create();
case DIALOG_NOT_AUTHENTICATED:
return new AlertDialog.Builder(this)
.setTitle(getText(R.string.not_logged_in))
.setMessage(R.string.login_to_proceed_message)
.setPositiveButton("Logga in", new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent i = new Intent(DrinkDetailActivity.this, BasicPreferenceActivity.class);
startActivityForResult(i, REQUEST_CODE_SETTINGS_CHANGED);
}
})
.setNegativeButton(R.string.back, null)
.create();
case DIALOG_CHOOSE_ADD_BARCODE_METHOD:
CharSequence[] methods = {"Scanna", "Manuellt"};
return new AlertDialog.Builder(this)
.setTitle("Hur vill du lägga in koden?")
.setItems(methods, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
IntentIntegrator.initiateScan(DrinkDetailActivity.this);
break;
case 1:
showDialog(DIALOG_ADD_BARCODE_MANUAL);
break;
}
}
})
.create();
case DIALOG_ADD_BARCODE_MANUAL:
final View addBarcodeLayout = getLayoutInflater().inflate(
R.layout.add_barcode_dialog, null);
final EditText addBarcodeEditText =
(EditText) addBarcodeLayout.findViewById(R.id.add_barcode);
addBarcodeEditText.setSelected(true);
return new AlertDialog.Builder(this)
.setTitle(getText(R.string.add_barcode))
.setView(addBarcodeLayout)
.setPositiveButton("Spara", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mBarcode = addBarcodeEditText.getText().toString();
new SuggestBarcodeTask().execute(mBarcode, sDrink, mAuthentication);
}
})
.setNegativeButton("Cancel", null)
.create();
case DIALOG_SHOW_DRINK_IMAGE:
return new DrinkImageViewerDialog(this, sDrink);
case DIALOG_ADD_COMMENT:
final View addCommentLayout = getLayoutInflater().inflate(R.layout.add_comment_dialog, null);
final EditText commentText = (EditText) addCommentLayout.findViewById(R.id.add_comment_text);
final AlertDialog dialog = new AlertDialog.Builder(this)
.setTitle(R.string.add_comment)
.setView(addCommentLayout)
.setIcon(android.R.drawable.sym_action_chat)
.setPositiveButton(android.R.string.ok, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new AddCommentTask().execute(
commentText.getText().toString(),
sDrink,
mAuthentication);
}
})
.setNegativeButton(android.R.string.cancel, null)
.create();
// Attach listener which will toggle the "Ok" button's activeness
// based on if the text view is empty or not.
commentText.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable editable) {
View button = dialog.getButton(Dialog.BUTTON_POSITIVE);
button.setEnabled(editable.length() > 0);
}
@Override
public void beforeTextChanged(CharSequence text, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence text, int start, int before, int cout) {}
});
return dialog;
case DIALOG_SEARCH_NETWORK_PROBLEM:
return DialogFactory.createNetworkProblemDialog(
this,
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch(which) {
case Dialog.BUTTON_POSITIVE:
launchGetDrinkTask(sDrink);
break;
case Dialog.BUTTON_NEGATIVE:
break;
}
}
});
}
return null;
}
@Override
protected void onPrepareDialog(final int id, final Dialog dialog) {
switch(id) {
case DIALOG_ADD_COMMENT:
AlertDialog alert = (AlertDialog) dialog;
final EditText textView = (EditText) dialog.findViewById(R.id.add_comment_text);
if(null != textView) {
alert.getButton(Dialog.BUTTON_POSITIVE).setEnabled(textView.length() > 0);
}
break;
case DIALOG_SHOW_DRINK_IMAGE:
DrinkImageViewerDialog imageViewer = (DrinkImageViewerDialog) dialog;
imageViewer.load();
break;
default:
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_SETTINGS_CHANGED:
cancelGetDrinkTask();
launchGetDrinkTask(sDrink);
break;
case IntentIntegrator.REQUEST_CODE:
if (resultCode == RESULT_OK) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if (scanResult != null) {
Log.d(TAG, "contents: " + scanResult.getContents());
Log.d(TAG, "formatName: " + scanResult.getFormatName());
mBarcode = scanResult.getContents();
new SuggestBarcodeTask().execute(scanResult.getContents(), sDrink, mAuthentication);
} else {
Log.d(TAG, "NO SCAN RESULT");
}
}
break;
}
}
/**
* Create and execute a task to fetch the current drink's comments.
*/
private void launchGetCommentsTask(Drink drink) {
mGetCommentsTask = new GetCommentsTask();
mGetCommentsTask.execute(drink);
}
/**
* Cancel current GetCommentsTask if it has been created and if it is
* currently executing.
*/
private void cancelGetCommentsTask() {
if(null != mGetCommentsTask && mGetCommentsTask.getStatus() == AsyncTask.Status.RUNNING) {
mGetCommentsTask.cancel(true);
mGetCommentsTask = null;
}
}
/**
* Background task for fetching comments
*/
private class GetCommentsTask extends AsyncTask<Drink, Void, ArrayList<Comment>> {
@Override
protected ArrayList<Comment> doInBackground(Drink... params) {
publishProgress();
return mCommentsStore.getComments(params[0]);
}
@Override
public void onProgressUpdate(Void... values) {
setProgressBarIndeterminateVisibility(true);
}
@Override
protected void onPostExecute(ArrayList<Comment> result) {
setProgressBarIndeterminateVisibility(false);
updateCommentsInUi(result);
}
}
/**
* Background task for setting a user rating.
*/
private class SetUserRatingTask extends AsyncTask<Float, Void, Float> {
@Override
protected Float doInBackground(Float... params) {
publishProgress();
DrinksStore.getInstance().rateDrink(sDrink, params[0], mAuthentication);
return params[0];
}
@Override
public void onProgressUpdate(Void... values) {
Toast.makeText(DrinkDetailActivity.this, getText(R.string.adding_rating), Toast.LENGTH_SHORT).show();
}
@Override
protected void onPostExecute(Float rating) {
Toast.makeText(DrinkDetailActivity.this, getText(R.string.rating_added), Toast.LENGTH_SHORT).show();
final boolean hadUserRating = sDrink.hasUserRating();
sDrink.setUserRating(rating);
if(hadUserRating != sDrink.hasUserRating()) {
// If the drink had a rating before but not now then decrease, otherwise increase
final int offset = hadUserRating ? -1 : 1;
sDrink.setRatingCount(sDrink.getRatingCount() + offset);
}
sendBroadcast(Intents.createPublishDrinkIntent(sDrink));
}
}
/**
* @author marco
* Background task for adding a comment.
*/
private class AddCommentTask extends AsyncTask<Object, Void, Boolean> {
@Override
protected Boolean doInBackground(Object... params) {
try {
String comment = (String) params[0];
Drink drink = (Drink) params[1];
AuthStore.Authentication authentication = (Authentication) params[2];
return DrinksStore.getInstance().commentDrink(drink, comment, authentication);
} catch(IOException e) {
return false;
}
}
@Override
public void onProgressUpdate(Void... values) {
Toast.makeText(DrinkDetailActivity.this, getText(R.string.adding_comment), Toast.LENGTH_SHORT).show();
}
@Override
protected void onPostExecute(Boolean response) {
if(true == response) {
Toast.makeText(DrinkDetailActivity.this, R.string.comment_saved, Toast.LENGTH_SHORT).show();
sDrink.setCommentCount(sDrink.getCommentCount() + 1);
// TODO: We might want to inject the comment directly into the adapter,
// but just refresh all the comments for now.
launchGetCommentsTask(sDrink);
sendBroadcast(Intents.createPublishDrinkIntent(sDrink));
} else {
// TODO: Show a retry/cancel here or maybe a better text than just "failed"?
Toast.makeText(DrinkDetailActivity.this, R.string.failed, Toast.LENGTH_SHORT).show();
}
}
}
/**
* Background task for suggesting a new barcode.
*
*/
private class SuggestBarcodeTask extends AsyncTask<Object, Void, Boolean> {
@Override
protected Boolean doInBackground(Object... params) {
try {
String barcode = (String) params[0];
Drink drink = (Drink) params[1];
AuthStore.Authentication authentication = (Authentication) params[2];
return BarcodeStore.getInstance().suggest(barcode, drink, authentication);
} catch (IOException e) {
return false;
}
}
@Override
public void onProgressUpdate(Void... values) {
Toast.makeText(DrinkDetailActivity.this, "Sparar streckkod...", Toast.LENGTH_SHORT).show();
}
@Override
protected void onPostExecute(Boolean response) {
if (response == true) {
Toast.makeText(DrinkDetailActivity.this, "Streckkod sparad", Toast.LENGTH_SHORT).show();
// Remove any orphan barcodes to prevent the "add orphan code?" dialog from showing again
getApp().clearOrphanBarcode();
} else {
showDialog(DIALOG_SUGGEST_BARCODE_FAIL);
}
}
}
/**
* Create and execute a task to fetch the current drink.
*/
private void launchGetDrinkTask(Drink drink) {
mGetDrinkTask = new GetDrinkTask();
mGetDrinkTask.execute(drink.getId());
}
/**
* Cancel current GetDrinkTask if it has been created and if it is
* currently executing.
*/
private void cancelGetDrinkTask() {
if(null != mGetDrinkTask && mGetDrinkTask.getStatus() == AsyncTask.Status.RUNNING) {
mGetDrinkTask.cancel(true);
mGetDrinkTask = null;
}
}
private Intent createInventoryIntent(Volume volume) {
SharedPreferences sharedPreferences = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
String county = sharedPreferences
.getString("sb_search_county", "0");
Uri uri = Uri.parse(String.format(
"http://mobil.systembolaget.se/SokDryck/SokDryck.aspx?artnr=%s&lan=%s",
String.valueOf(volume.getArticleId()), county));
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
return intent;
}
/**
* Background task for fetching a drink.
*/
private class GetDrinkTask extends AsyncTask<Integer, Void, Drink> {
@Override
protected Drink doInBackground(Integer... params) {
publishProgress();
return DrinksStore.getInstance().getDrink(params[0], mAuthentication);
}
@Override
protected void onPostExecute(Drink drink) {
if(null != drink) {
onUpdatedDrink(drink);
} else {
showDialog(DIALOG_SEARCH_NETWORK_PROBLEM);
}
}
}
private class UserRatingAdapter extends ArrayAdapter<String> {
private float mUserRating;
public UserRatingAdapter(Context context, float userRating) {
super(context, R.layout.user_rating, new ArrayList<String>());
add("1");
this.mUserRating = userRating;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.user_rating, parent, false);
}
RatingBar ratingBar = (RatingBar) convertView.findViewById(R.id.user_drink_rating);
ratingBar.setRating(mUserRating);
return convertView;
}
public void setUserRating(float userRating) {
mUserRating = userRating;
}
public float getUserRating() {
return mUserRating;
}
}
}