berict/Tapad

View on GitHub
app/src/main/java/com/bedrock/padder/activity/FeedbackActivity.java

Summary

Maintainability
F
5 days
Test Coverage
package com.bedrock.padder.activity;

import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.Toast;

import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.bedrock.padder.BuildConfig;
import com.bedrock.padder.R;
import com.bedrock.padder.helper.AnimateHelper;
import com.bedrock.padder.helper.FabHelper;
import com.bedrock.padder.helper.IntentHelper;
import com.bedrock.padder.helper.ToolbarHelper;
import com.bedrock.padder.helper.WindowHelper;

public class FeedbackActivity extends AppCompatActivity {

    final String TAG = "FeedbackActivity";
    String MODE_TAG = "";

    private FabHelper fab = new FabHelper();
    private WindowHelper w = new WindowHelper();
    private IntentHelper intent = new IntentHelper();
    private AnimateHelper anim = new AnimateHelper();
    private ToolbarHelper toolbar = new ToolbarHelper();

    Activity a = this;

    private String br = System.getProperty("line.separator");
    private String sendMessage;
    private String systemInfo;
    private int circularRevealDuration = 400;
    private boolean feedbackSent = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_feedback);

        Intent intent = getIntent();
        MODE_TAG = intent.getExtras().getString("feedbackMode");

        setFab();
        initUi();

        toolbar.setActionBar(this);
        toolbar.setActionBarDisplayHomeAsUpIcon(R.drawable.ic_close_white);
        toolbar.setStatusBarTint(this);
        toolbar.setActionBarTitle(w.getStringId("task_feedback_" + MODE_TAG));
        toolbar.setActionBarColor(R.color.colorFeedback, a);
        w.setStatusBar(R.color.colorFeedbackDark, a);

        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);

        w.setRecentColor(w.getStringId("task_feedback_" + MODE_TAG), R.color.colorFeedback, a);

        systemInfo = "Version code = " + BuildConfig.VERSION_CODE + br +
                "Version name = \"" + BuildConfig.VERSION_NAME + "\"" + br +
                "Android version = " + Build.VERSION.RELEASE + " (" + Build.VERSION.SDK_INT + ")" + br +
                "Device model (Product) = " + Build.MODEL + " (" + Build.PRODUCT + ")" + br +
                "Device screen = " +
                getWindow().getWindowManager().getDefaultDisplay().getWidth()  + " (W) X " +
                getWindow().getWindowManager().getDefaultDisplay().getHeight() + " (H)" + br +
                "Screen density = " + getResources().getDisplayMetrics().densityDpi + " dpi";
    }

    public boolean onOptionsItemSelected(MenuItem item) {
        pressBack();
        return true;
    }

    void pressBack() {
        KeyEvent kDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
        this.dispatchKeyEvent(kDown);
        KeyEvent kUp = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
        this.dispatchKeyEvent(kUp);
    }

    private TextInputLayout songNameLayout, songArtistLayout, songLinkLayout, songMessageLayout;
    private EditText songName, songArtist, songLink, songMessage;
    private Spinner songGenre;
    private boolean songGenreValidateFirstRun = true;

    private String songNameString;
    private String songArtistString;
    private String songLinkString;
    private String songMessageString;
    private String songGenreString;

    private TextInputLayout feedbackMessageLayout;
    private EditText feedbackMessage;
    private Spinner feedbackType;
    private boolean feedbackTypeValidateFirstRun = true;

    private String feedbackMessageString;
    private String feedbackTypeString;

    private TextInputLayout reportBugMessageLayout;
    private EditText reportBugMessage;
    private Spinner reportBugType;
    private boolean reportBugTypeValidateFirstRun = true;

    private String reportBugMessageString;
    private String reportBugTypeString;

    private void initUi() {
        switch (MODE_TAG) {
            case "song":
                // layout
                RelativeLayout songLayout = findViewById(R.id.feedback_song);
                // input layout
                songNameLayout = findViewById(R.id.feedback_song_name_input_layout);
                songArtistLayout = findViewById(R.id.feedback_song_artist_input_layout);
                songLinkLayout = findViewById(R.id.feedback_song_link_input_layout);
                songMessageLayout = findViewById(R.id.feedback_song_message_input_layout);
                // editText
                songName = findViewById(R.id.feedback_song_name_input);
                songArtist = findViewById(R.id.feedback_song_artist_input);
                songLink = findViewById(R.id.feedback_song_link_input);
                songMessage = findViewById(R.id.feedback_song_message_input);
                // spinner
                songGenre = findViewById(R.id.feedback_song_genre_spinner);

                songLayout.setVisibility(View.VISIBLE);
                songName   .addTextChangedListener(new mTextWatcher(songName   ));
                songArtist .addTextChangedListener(new mTextWatcher(songArtist ));
                songLink   .addTextChangedListener(new mTextWatcher(songLink   ));
                songMessage.addTextChangedListener(new mTextWatcher(songMessage));
                songGenre  .setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                        if (position != 0) {
                            // not the first item (placeholder)
                            songGenreString = getResources().getStringArray(R.array.feedback_song_genre_array)[position];
                            Log.d(TAG, songGenreString);
                        } else {
                            // first item
                            songGenreString = "";
                        }
                        validateSpinner(songGenreValidateFirstRun, R.id.feedback_song_genre_spinner_error, songGenreString);
                    } // to close the onItemSelected
                    public void onNothingSelected(AdapterView<?> parent) {}
                });
                break;
            case "feedback":
                // layout
                RelativeLayout feedbackLayout = findViewById(R.id.feedback_feedback);
                // input layout
                feedbackMessageLayout = findViewById(R.id.feedback_feedback_message_input_layout);
                // editText
                feedbackMessage = findViewById(R.id.feedback_feedback_message_input);
                // spinner
                feedbackType = findViewById(R.id.feedback_feedback_type_spinner);

                feedbackLayout.setVisibility(View.VISIBLE);
                feedbackMessage.addTextChangedListener(new mTextWatcher(feedbackMessage));
                feedbackType   .setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                        if (position != 0) {
                            // not the first item (placeholder)
                            feedbackTypeString = getResources().getStringArray(R.array.feedback_feedback_type_array)[position];
                            Log.d(TAG, feedbackTypeString);
                        } else {
                            // first item
                            feedbackTypeString = "";
                            Log.d(TAG, "null");
                        }
                        validateSpinner(feedbackTypeValidateFirstRun, R.id.feedback_feedback_type_spinner_error, feedbackTypeString);
                    } // to close the onItemSelected
                    public void onNothingSelected(AdapterView<?> parent) {}
                });
                break;
            case "report_bug":
                // layout
                RelativeLayout reportBugLayout = findViewById(R.id.feedback_report_bug);
                // input layout
                reportBugMessageLayout = findViewById(R.id.feedback_report_bug_message_input_layout);
                // editText
                reportBugMessage = findViewById(R.id.feedback_report_bug_message_input);
                // spinner
                reportBugType = findViewById(R.id.feedback_report_bug_type_spinner);

                reportBugLayout.setVisibility(View.VISIBLE);
                reportBugMessage.addTextChangedListener(new mTextWatcher(reportBugMessage));
                reportBugType   .setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                        View quickFix  = findViewById(R.id.feedback_report_bug_type_quickfix);
                        if (position == 2) {
                            // custom quickfix
                            reportBugTypeString = getResources().getStringArray(R.array.feedback_report_bug_type_array)[position];
                            if (quickFix.getVisibility() == View.INVISIBLE) {
                                anim.fadeIn(R.id.feedback_report_bug_type_quickfix, 0, 100, "errorQuickFix", a);
                            }
                        } else if (position != 0) {
                            // not the first item (placeholder)
                            reportBugTypeString = getResources().getStringArray(R.array.feedback_report_bug_type_array)[position];
                            Log.d(TAG, reportBugTypeString);
                            if (quickFix.getVisibility() == View.VISIBLE) {
                                anim.fadeOutInvisible(R.id.feedback_report_bug_type_quickfix, 0, 100, a);
                            }
                        } else {
                            // first item
                            reportBugTypeString = "";
                            Log.d(TAG, "null");
                            if (quickFix.getVisibility() == View.VISIBLE) {
                                anim.fadeOutInvisible(R.id.feedback_report_bug_type_quickfix, 0, 100, a);
                            }
                        }
                        validateSpinner(reportBugTypeValidateFirstRun, R.id.feedback_report_bug_type_spinner_error, reportBugTypeString);
                    } // to close the onItemSelected
                    public void onNothingSelected(AdapterView<?> parent) {}
                });

                w.setOnClick(R.id.feedback_report_bug_type_quickfix_action, new Runnable() {
                    @Override
                    public void run() {
                        new MaterialDialog.Builder(a)
                                .content(R.string.feedback_report_bug_type_quickfix_content)
                                .contentColorRes(R.color.dark_secondary)
                                .positiveText(R.string.feedback_report_bug_type_quickfix_neutral)
                                .positiveColorRes(R.color.colorAccent)
                                .show();
                    }
                }, a);
                break;
        }

        View learnMore = findViewById(R.id.feedback_disclaimer_action);
        learnMore.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new MaterialDialog.Builder(a)
                        .title(R.string.feedback_disclaimer_dialog_title)
                        .content(systemInfo)
                        .contentColorRes(R.color.dark_primary)
                        .positiveText(R.string.feedback_disclaimer_dialog_action)
                        .positiveColorRes(R.color.colorAccent)
                        .show();
            }
        });
    }

    private boolean validateSpinner(boolean firstRun, int errorViewId, String spinnerCurrentItemString) {
        if (firstRun) {
            switch (MODE_TAG) {
                case "song":
                    songGenreValidateFirstRun = false;
                    break;
                case "feedback":
                    feedbackTypeValidateFirstRun = false;
                    break;
                case "report_bug":
                    reportBugTypeValidateFirstRun = false;
                    break;
            }
            return false;
        } else {
            View errorView = findViewById(errorViewId);
            if (spinnerCurrentItemString.isEmpty()) {
                // empty, first item
                anim.fadeIn(errorViewId, 0, 100, "errorFadeIn", a);
                return false;
            } else {
                if (errorView.getVisibility() == View.VISIBLE) {
                    anim.fadeOutInvisible(errorViewId, 0, 100, a);
                }
                return true;
            }
        }
    }

    private boolean validateEditText(EditText editText) {
        Log.d(TAG, "validateEditText");
        switch (MODE_TAG) {
            case "song":
                if (editText == songName) {
                    if (songName.getText().toString().trim().isEmpty()) {
                        // string empty
                        songNameLayout.setError(getResources().getString(R.string.feedback_song_name_input_error));
                        songName.requestFocus();
                        return false;
                    } else {
                        songNameLayout.setErrorEnabled(false);
                        songNameString = songName.getText().toString();
                    }
                    return true;
                }
                if (editText == songArtist) {
                    if (songArtist.getText().toString().trim().isEmpty()) {
                        // string empty
                        songArtistLayout.setError(getResources().getString(R.string.feedback_song_artist_input_error));
                        songArtist.requestFocus();
                        return false;
                    } else {
                        songArtistLayout.setErrorEnabled(false);
                        songArtistString = songArtist.getText().toString();
                    }
                    return true;
                }
                if (editText == songLink) {
                    if (songLink.getText().toString().trim().isEmpty()) {
                        // string empty
                        songLinkLayout.setError(getResources().getString(R.string.feedback_song_link_input_error));
                        songLink.requestFocus();
                        return false;
                    } else if (validateMusicUrl(songLink.getText().toString()) == false) {
                        songLinkLayout.setError(getResources().getString(R.string.feedback_song_link_input_url_error));
                        songLink.requestFocus();
                        return false;
                    } else {
                        songLinkLayout.setErrorEnabled(false);
                        songLinkString = songLink.getText().toString();
                    }
                    return true;
                }
                if (editText == songMessage) {
                    songMessageLayout.setErrorEnabled(false);
                    songMessageString = songMessage.getText().toString();
                    return true;
                }
                break;
            case "feedback":
                if (editText == feedbackMessage) {
                    if (feedbackMessage.getText().toString().trim().isEmpty()) {
                        // string empty
                        feedbackMessageLayout.setErrorTextAppearance(R.style.editTextErrorDefault);
                        feedbackMessageLayout.setError(getResources().getString(R.string.feedback_feedback_message_input_error_empty));
                        feedbackMessage.requestFocus();
                        return false;
                    } else if (feedbackMessage.getText().toString().length() < 15) {
                        // too short
                        feedbackMessageLayout.setErrorTextAppearance(R.style.editTextErrorGrey);
                        feedbackMessageLayout.setError(
                                (15 - feedbackMessage.getText().toString().length()) + " " +
                                getResources().getString(R.string.feedback_feedback_message_input_error_too_short)
                        );
                        feedbackMessage.requestFocus();
                        return false;
                    } else {
                        feedbackMessageLayout.setErrorEnabled(false);
                        feedbackMessageString = feedbackMessage.getText().toString();
                    }
                    return true;
                }
                break;
            case "report_bug":
                if (editText == reportBugMessage) {
                    if (reportBugMessage.getText().toString().trim().isEmpty()) {
                        // string empty
                        reportBugMessageLayout.setErrorTextAppearance(R.style.editTextErrorDefault);
                        reportBugMessageLayout.setError(getResources().getString(R.string.feedback_report_bug_message_input_error_empty));
                        reportBugMessage.requestFocus();
                        return false;
                    } else if (reportBugMessage.getText().toString().length() < 15) {
                        // too short
                        reportBugMessageLayout.setErrorTextAppearance(R.style.editTextErrorGrey);
                        reportBugMessageLayout.setError(
                                (15 - reportBugMessage.getText().toString().length()) + " " +
                                        getResources().getString(R.string.feedback_report_bug_message_input_error_too_short)
                        );
                        reportBugMessage.requestFocus();
                        return false;
                    } else {
                        reportBugMessageLayout.setErrorEnabled(false);
                        reportBugMessageString = reportBugMessage.getText().toString();
                    }
                    return true;
                }
                break;
        }
        return false;
    }

    private boolean validateMusicUrl(String url) {
        return (validateUrlWithLength(url, "youtube.com/watch?v=", 31) ||
                validateUrlWithLength(url, "youtu.be/", 20) ||
                validateUrlWithLength(url, "soundcloud.com/", 16));
    }

    private boolean validateUrlWithLength(String url, String validateUrl, int validateUrlLength) {
        if (url.contains(validateUrl) && url.length() >= validateUrlLength) {
            return true;
        } else {
            return false;
        }
    }

    private boolean validateAll() {
        switch (MODE_TAG) {
            case "song":
                if (validateEditText(songName) &
                        validateEditText(songArtist) &
                        validateEditText(songLink) &
                        validateEditText(songMessage) &
                        validateSpinner(songGenreValidateFirstRun, R.id.feedback_song_genre_spinner_error, songGenreString)) {
                    return true;
                }
                break;
            case "feedback":
                if (validateEditText(feedbackMessage) &
                        validateSpinner(feedbackTypeValidateFirstRun, R.id.feedback_feedback_type_spinner_error, feedbackTypeString)) {
                    return true;
                }
                break;
            case "report_bug":
                if (validateEditText(reportBugMessage) &
                        validateSpinner(reportBugTypeValidateFirstRun, R.id.feedback_report_bug_type_spinner_error, reportBugTypeString)) {
                    return true;
                }
                break;
        }
        return false;
    }

    private boolean send() {
        if (validateAll() == true) {
            switch (MODE_TAG) {
                case "song":
                    sendMessage =   "Song title   = \"" + songNameString    + "\"" + br +
                                    "Artist name  = \"" + songArtistString  + "\"" + br +
                                    "Song genre   = \"" + songGenreString   + "\"" + br +
                                    "Song link    = \"" + songLinkString    + "\"" + br +
                                    "User message = \"" + songMessageString + "\"" + br + br +
                                    systemInfo + br + "FeedbackId0" + br + br +
                                    "### Do not edit the subject and the message to receive a reply ###";
                    intent.intentEmail(a, R.string.feedback_email,
                            "Tapad Feedback - Song Request", sendMessage,
                            R.string.feedback_email_client_feedback, circularRevealDuration);
                    break;
                case "feedback":
                    sendMessage =   "Feedback type    = \"" + feedbackTypeString    + "\"" + br +
                                    "Feedback message = \"" + feedbackMessageString + "\"" + br + br +
                                    systemInfo + br + "FeedbackId1" + br + br +
                            "### Do not edit the subject and the message to receive a reply ###";
                    intent.intentEmail(a, R.string.feedback_email,
                            "Tapad Feedback - Feedback [" + feedbackTypeString + "]", sendMessage,
                            R.string.feedback_email_client_feedback, circularRevealDuration);
                    break;
                case "report_bug":
                    sendMessage =
                            "Bug type   = \"" + reportBugTypeString    + "\"" + br +
                            "Bug detail = \"" + reportBugMessageString + "\"" + br + br +
                            systemInfo + br + "FeedbackId2" + br + br +
                            "### Do not edit the subject and the message to receive a reply ###";
                    intent.intentEmail(a, R.string.feedback_email,
                            "Tapad Feedback - Bug Report [" + reportBugTypeString + "]", sendMessage,
                            R.string.feedback_email_client_bug_report, circularRevealDuration);
                    break;
            }
            feedbackSent = true;
            return true;
        } else {
            Toast.makeText(a, w.getStringId("feedback_" + MODE_TAG + "_send_error"), Toast.LENGTH_SHORT).show();
            return false;
        }
    }

    private MaterialDialog onBackPressedDialog;

    @Override
    public void onBackPressed() {
        if (feedbackSent == false) {
            String currentContentTitle = w.getStringFromId("feedback_" + MODE_TAG + "_discard", a);

            onBackPressedDialog = new MaterialDialog.Builder(a)
                    .content(currentContentTitle)
                    .positiveText(R.string.feedback_quit_dialog_negative)
                    .positiveColorRes(R.color.red)
                    .onPositive(new MaterialDialog.SingleButtonCallback() {
                        @Override
                        public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                            FeedbackActivity.super.onBackPressed();
                        }
                    })
                    .negativeText(R.string.feedback_quit_dialog_positive)
                    .negativeColorRes(R.color.colorAccent)
                    .onNegative(new MaterialDialog.SingleButtonCallback() {
                        @Override
                        public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                            onBackPressedDialog.dismiss();
                        }
                    })
                    .show();
        } else {
            super.onBackPressed();
        }
    }

    private int focusCount = 0;
    // count 2 for sent / canceled email

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        focusCount++;
        Log.d("FocusCount", String.valueOf(focusCount));
        if (focusCount == 2) {
            if (feedbackSent == true) {
                (a.findViewById(R.id.layout_placeholder)).setVisibility(View.GONE);
                w.setRecentColor(w.getStringId("task_feedback_" + MODE_TAG), R.color.colorFeedback, a);
            }
            focusCount = 0;
        }
        super.onWindowFocusChanged(hasFocus);
    }

    void setFab() {
        fab.set(a);
        fab.show();
        fab.setIcon(R.drawable.ic_send_white, a);
        fab.setOnClickListener(new Runnable() {
            @Override
            public void run() {
                focusCount = 0;
                if (send() == true) {
                    w.setRecentColor(w.getStringId("task_feedback_" + MODE_TAG), 0, R.color.colorAccent, a);
                }
            }
        });
    }

    private class mTextWatcher implements TextWatcher {

        private View view;

        private mTextWatcher(View view) {
            this.view = view;
        }

        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}

        public void afterTextChanged(Editable editable) {
            validateEditText((EditText)view);
        }
    }
}