/* * Copyright (C) 2010-2016 Stichting Akvo (Akvo Foundation) * * This file is part of Akvo Flow. * * Akvo Flow is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Akvo Flow is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Akvo Flow. If not, see <http://www.gnu.org/licenses/>. */ package org.akvo.flow.ui.view; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnFocusChangeListener; import android.widget.Button; import android.widget.EditText; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; import org.akvo.flow.R; import org.akvo.flow.domain.Question; import org.akvo.flow.domain.QuestionResponse; import org.akvo.flow.event.QuestionInteractionEvent; import org.akvo.flow.event.SurveyListener; import org.akvo.flow.util.ConstantUtil; import org.akvo.flow.util.ViewUtil; /** * Question to handle scanning of a barcode. This question relies on the zxing * library being installed on the device. * * @author Christopher Fagiani */ public class BarcodeQuestionView extends QuestionView implements OnClickListener, OnFocusChangeListener { private EditText mInputText; private LinearLayout mInputContainer; private boolean mMultiple; public BarcodeQuestionView(Context context, Question q, SurveyListener surveyListener) { super(context, q, surveyListener); init(); } private void init() { setQuestionView(R.layout.barcode_question_view); mMultiple = getQuestion().isAllowMultiple(); mInputContainer = (LinearLayout) findViewById(R.id.input_ll); mInputText = (EditText) findViewById(R.id.input_text); Button mScanBtn = (Button) findViewById(R.id.scan_btn); mScanBtn.setEnabled(!isReadOnly()); boolean isQuestionLocked = mQuestion.isLocked(); if (!isQuestionLocked) { View manualInputContainer = findViewById(R.id.manual_input_container); View manualInputSeparator = findViewById(R.id.manual_input_separator); manualInputSeparator.setVisibility(VISIBLE); manualInputContainer.setVisibility(VISIBLE); setInputText(); setUpAddButton(); } mScanBtn.setOnClickListener(this); } private void setUpAddButton() { ImageButton mAddBtn = (ImageButton) findViewById(R.id.add_btn); if (isReadOnly() || !mMultiple) { mAddBtn.setVisibility(View.GONE); } mAddBtn.setOnClickListener(this); } private void setInputText() { boolean isReadOnly = isReadOnly(); if (mMultiple) { mInputText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // EMPTY } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // EMPTY } @Override public void afterTextChanged(Editable s) { String[] tokens = s.toString().split("\\s+", -1); if (tokens.length > 1) { for (int i = 0; i < tokens.length - 1; i++) { addValue(tokens[i]); } mInputText.setText(tokens[tokens.length - 1]); } } }); if (isReadOnly) { mInputText.setVisibility(View.GONE); } } mInputText.setEnabled(!mQuestion.isLocked()); mInputText.setFocusable(!isReadOnly); mInputText.setOnFocusChangeListener(this); } private void addValue(final String text) { LayoutInflater inflater = LayoutInflater.from(getContext()); final View view = inflater.inflate(R.layout.barcode_item, mInputContainer, false); ((EditText) view.findViewById(R.id.input)).setText(text); ImageButton btn = (ImageButton) view.findViewById(R.id.delete); if (isReadOnly()) { btn.setVisibility(View.GONE); } else { btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { ViewUtil.showConfirmDialog(R.string.deleteresponse, R.string.clear_value_msg, getContext(), true, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mInputContainer.removeView(view); displayOrder(); captureResponse(); } }); } }); } mInputContainer.addView(view); displayOrder(); captureResponse(); } private void displayOrder() { if (!mQuestion.isAllowMultiple()) { return; } for (int i = 0; i < mInputContainer.getChildCount(); i++) { View view = mInputContainer.getChildAt(i); TextView orderView = (TextView) view.findViewById(R.id.order); String text = i + 1 + ":"; orderView.setText(text); orderView.setVisibility(VISIBLE); } } /** * handle the action button click */ public void onClick(View v) { switch (v.getId()) { case R.id.scan_btn: notifyQuestionListeners(QuestionInteractionEvent.SCAN_BARCODE_EVENT); break; case R.id.add_btn: final String value = mInputText.getText().toString(); if (!TextUtils.isEmpty(value)) { addValue(value); mInputText.setText(""); } break; } } @Override public void questionComplete(Bundle barcodeData) { if (barcodeData != null) { String value = barcodeData.getString(ConstantUtil.BARCODE_CONTENT); if (mMultiple) { addValue(value); } else { mInputText.setText(value); } captureResponse(); } } /** * restores the data and turns on the complete icon if the content is * non-null */ @Override public void rehydrate(QuestionResponse resp) { super.rehydrate(resp); mInputContainer.removeAllViews(); mInputText.setText(""); String answer = resp != null ? resp.getValue() : null; if (!TextUtils.isEmpty(answer)) { if (mMultiple) { String[] values = answer.split("\\|", -1); for (String value : values) { addValue(value); } } else { mInputText.setText(answer); } } } /** * clears the file path and the complete icon */ @Override public void resetQuestion(boolean fireEvent) { super.resetQuestion(fireEvent); mInputContainer.removeAllViews(); mInputText.setText(""); } /** * captures the response and runs validation on loss of focus */ @Override public void onFocusChange(View view, boolean hasFocus) { // we need to listen to loss of focus // and make sure input is valid if (!hasFocus) { captureResponse(false); } } /** * pulls the data out of the fields and saves it as a response object, * possibly suppressing listeners */ public void captureResponse(boolean suppressListeners) { StringBuilder builder = new StringBuilder(); if (mMultiple) { for (int i = 0; i < mInputContainer.getChildCount(); i++) { View v = mInputContainer.getChildAt(i); String value = ((EditText) v.findViewById(R.id.input)).getText().toString(); if (!TextUtils.isEmpty(value)) { builder.append(value); if (i < mInputContainer.getChildCount() - 1) { builder.append("|"); } } } } String value = mInputText.getText().toString(); if (!TextUtils.isEmpty(value)) { builder.append(value); } setResponse(new QuestionResponse(builder.toString(), ConstantUtil.VALUE_RESPONSE_TYPE, getQuestion().getId()), suppressListeners); } }