package org.commcare.adapters;
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.commcare.CommCareApplication;
import org.commcare.activities.CommCareActivity;
import org.commcare.dalvik.R;
import org.commcare.logging.AndroidLogger;
import org.commcare.logging.XPathErrorLogger;
import org.commcare.models.AndroidSessionWrapper;
import org.commcare.preferences.DeveloperPreferences;
import org.commcare.suite.model.EntityDatum;
import org.commcare.suite.model.Entry;
import org.commcare.suite.model.Menu;
import org.commcare.suite.model.MenuDisplayable;
import org.commcare.suite.model.MenuLoader;
import org.commcare.suite.model.SessionDatum;
import org.commcare.util.CommCarePlatform;
import org.commcare.util.LoggerInterface;
import org.commcare.utils.MediaUtil;
import org.commcare.views.UserfacingErrorHandling;
import org.commcare.views.media.AudioPlaybackButton;
import org.commcare.views.media.ViewId;
import org.javarosa.core.reference.InvalidReferenceException;
import org.javarosa.core.reference.ReferenceManager;
import org.javarosa.core.services.Logger;
import org.javarosa.core.services.locale.Localization;
import org.javarosa.core.services.locale.Localizer;
import org.javarosa.xpath.XPathException;
import org.javarosa.xpath.parser.XPathSyntaxException;
import java.io.File;
/**
* Load module menu items
*
* @author wspride
*/
public class MenuAdapter extends BaseAdapter {
protected final AndroidSessionWrapper asw;
private Exception loadError;
private String errorMessage = "";
final Context context;
final MenuDisplayable[] displayableData;
class MenuLogger implements LoggerInterface {
@Override
public void logError(String message, Exception cause) {
if (cause instanceof XPathSyntaxException) {
errorMessage = Localization.get("app.menu.display.cond.bad.xpath", new String[]{message, cause.getMessage()});
logError(errorMessage);
} else if (cause instanceof XPathException) {
errorMessage = Localization.get("app.menu.display.cond.xpath.err", new String[]{message, cause.getMessage()});
XPathErrorLogger.INSTANCE.logErrorToCurrentApp(((XPathException)cause).getSource(), message);
Logger.log(AndroidLogger.TYPE_ERROR_CONFIG_STRUCTURE, message);
}
}
@Override
public void logError(String message) {
XPathErrorLogger.INSTANCE.logErrorToCurrentApp(message);
Logger.log(AndroidLogger.TYPE_ERROR_CONFIG_STRUCTURE, message);
}
}
public MenuAdapter(Context context, CommCarePlatform platform, String menuID) {
this.context = context;
asw = CommCareApplication.instance().getCurrentSessionWrapper();
MenuLoader menuLoader = new MenuLoader(platform, asw, menuID, new MenuLogger());
this.displayableData = menuLoader.getMenus();
this.errorMessage = menuLoader.getErrorMessage();
this.loadError = menuLoader.getLoadException();
}
public void showAnyLoadErrors(CommCareActivity activity) {
if (loadError != null) {
UserfacingErrorHandling.createErrorDialog(activity, errorMessage, true);
}
}
@Override
public boolean areAllItemsEnabled() {
return true;
}
@Override
public boolean isEnabled(int arg0) {
return true;
}
@Override
public int getCount() {
return displayableData.length;
}
@Override
public Object getItem(int i) {
return displayableData[i];
}
@Override
public long getItemId(int i) {
Object tempItem = displayableData[i];
if (tempItem instanceof Menu) {
return ((Menu)tempItem).getId().hashCode();
} else {
return ((Entry)tempItem).getCommandId().hashCode();
}
}
@Override
public int getItemViewType(int i) {
return 0;
}
enum NavIconState {
NONE, NEXT, JUMP
}
@Override
public View getView(int i, View menuListItem, ViewGroup vg) {
MenuDisplayable menuDisplayable = displayableData[i];
if (menuListItem == null) {
// inflate it and do not attach to parent, or we will get the 'addView not supported' exception
menuListItem = LayoutInflater.from(context).inflate(R.layout.menu_list_item_modern, vg, false);
}
TextView rowText = (TextView)menuListItem.findViewById(R.id.row_txt);
setupTextView(rowText, menuDisplayable);
AudioPlaybackButton audioPlaybackButton = (AudioPlaybackButton)menuListItem.findViewById(R.id.row_soundicon);
setupAudioButton(i, audioPlaybackButton, menuDisplayable);
// set up the image, if available
ImageView mIconView = (ImageView)menuListItem.findViewById(R.id.row_img);
setupImageView(mIconView, menuDisplayable);
setupBadgeView(menuListItem, menuDisplayable);
return menuListItem;
}
private void setupAudioButton(int rowId, AudioPlaybackButton audioPlaybackButton, MenuDisplayable menuDisplayable) {
final String audioURI = menuDisplayable.getAudioURI();
String audioFilename = "";
if (audioURI != null && !audioURI.equals("")) {
try {
audioFilename = ReferenceManager.instance().DeriveReference(audioURI).getLocalURI();
} catch (InvalidReferenceException e) {
Log.e("AVTLayout", "Invalid reference exception");
e.printStackTrace();
}
}
File audioFile = new File(audioFilename);
// First set up the audio button
ViewId viewId = ViewId.buildListViewId(rowId);
if (!"".equals(audioFilename) && audioFile.exists()) {
audioPlaybackButton.modifyButtonForNewView(viewId, audioURI, true);
} else {
if (audioPlaybackButton != null) {
audioPlaybackButton.modifyButtonForNewView(viewId,audioURI, false);
((LinearLayout)audioPlaybackButton.getParent()).removeView(audioPlaybackButton);
}
}
}
public void setupTextView(TextView textView, MenuDisplayable menuDisplayable) {
String mQuestionText = menuDisplayable.getDisplayText();
//Final change, remove any numeric context requests. J2ME uses these to
//help with numeric navigation.
if (mQuestionText != null) {
mQuestionText = Localizer.processArguments(mQuestionText, new String[]{""}).trim();
}
textView.setText(mQuestionText);
}
public void setupImageView(ImageView mIconView, MenuDisplayable menuDisplayable) {
setupImageView(mIconView, menuDisplayable, (int)context.getResources().getDimension(R.dimen.list_icon_bounding_dimen));
}
public void setupImageView(ImageView mIconView, MenuDisplayable menuDisplayable, int defaultBoundingBox) {
if (mIconView != null) {
int iconDimension = defaultBoundingBox;
Bitmap image = MediaUtil.inflateDisplayImage(context, menuDisplayable.getImageURI(),
iconDimension, iconDimension);
if (image != null) {
mIconView.setImageBitmap(image);
mIconView.setAdjustViewBounds(true);
} else {
setupDefaultIcon(mIconView, getIconState(menuDisplayable));
}
}
}
protected void setupBadgeView(View menuListItem, MenuDisplayable menuDisplayable) {
View badgeView = menuListItem.findViewById(R.id.badge_view);
String badgeText = menuDisplayable.getTextForBadge(
asw.getEvaluationContext(menuDisplayable.getCommandID()));
if (badgeText != null && !"".equals(badgeText) && !"0".equals(badgeText)) {
if (badgeText.length() > 2) {
// A badge can only fit up to 2 characters
badgeText = badgeText.substring(0, 2);
}
TextView badgeTextView = (TextView)menuListItem.findViewById(R.id.badge_text);
badgeTextView.setText(badgeText);
badgeView.setVisibility(View.VISIBLE);
} else {
badgeView.setVisibility(View.GONE);
}
}
private NavIconState getIconState(MenuDisplayable menuDisplayable) {
NavIconState iconChoice = NavIconState.NEXT;
//figure out some icons
if (menuDisplayable instanceof Entry) {
SessionDatum datum = asw.getSession().getNeededDatum((Entry)menuDisplayable);
if (datum == null || !(datum instanceof EntityDatum)) {
iconChoice = NavIconState.JUMP;
}
}
if (!DeveloperPreferences.isNewNavEnabled()) {
iconChoice = NavIconState.NONE;
}
return iconChoice;
}
protected void setupDefaultIcon(ImageView mIconView, NavIconState iconChoice) {
if (mIconView != null) {
switch (iconChoice) {
case NEXT:
mIconView.setImageResource(R.drawable.avatar_module);
break;
case JUMP:
mIconView.setImageResource(R.drawable.avatar_form);
break;
case NONE:
mIconView.setVisibility(View.GONE);
break;
}
}
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public void registerDataSetObserver(DataSetObserver arg0) {
}
@Override
public void unregisterDataSetObserver(DataSetObserver arg0) {
}
}