package com.boardgamegeek.ui; import android.annotation.SuppressLint; import android.content.AsyncQueryHandler; import android.content.ContentResolver; import android.content.DialogInterface; import android.content.Intent; import android.content.res.ColorStateList; import android.content.res.Resources; import android.database.Cursor; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.v4.content.ContextCompat; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SwitchCompat; import android.text.Editable; import android.text.InputType; import android.text.TextUtils; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.ScrollView; import android.widget.TextView; import com.boardgamegeek.R; import com.boardgamegeek.model.Player; import com.boardgamegeek.provider.BggContract; import com.boardgamegeek.provider.BggContract.GameColors; import com.boardgamegeek.provider.BggContract.Games; import com.boardgamegeek.ui.adapter.BuddyNameAdapter; import com.boardgamegeek.ui.adapter.GameColorAdapter; import com.boardgamegeek.ui.adapter.PlayerNameAdapter; import com.boardgamegeek.ui.dialog.ColorPickerDialogFragment; import com.boardgamegeek.util.ColorUtils; import com.boardgamegeek.util.DialogUtils; import com.boardgamegeek.util.HelpUtils; import com.boardgamegeek.util.ImageUtils; import com.boardgamegeek.util.PreferencesUtils; import com.boardgamegeek.util.ShowcaseViewWizard; import com.boardgamegeek.util.StringUtils; import com.boardgamegeek.util.ToolbarUtils; import com.boardgamegeek.util.fabric.AddFieldEvent; import com.github.amlcurran.showcaseview.targets.Target; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.OnTextChanged; import hugo.weaving.DebugLog; import icepick.Icepick; import icepick.State; public class LogPlayerActivity extends AppCompatActivity { public static final String KEY_GAME_ID = "GAME_ID"; public static final String KEY_GAME_NAME = "GAME_NAME"; public static final String KEY_IMAGE_URL = "IMAGE_URL"; public static final String KEY_AUTO_POSITION = "AUTO_POSITION"; public static final String KEY_USED_COLORS = "USED_COLORS"; public static final String KEY_END_PLAY = "SCORE_SHOWN"; public static final String KEY_PLAYER = "PLAYER"; public static final String KEY_FAB_COLOR = "FAB_COLOR"; public static final String KEY_POSITION = "POSITION"; public static final int INVALID_POSITION = -1; private static final int HELP_VERSION = 2; private static final int TOKEN_COLORS = 1; private String gameName; private int position; @State Player player; private Player originalPlayer; @BindView(R.id.scroll_container) ScrollView scrollContainer; @BindView(R.id.header) TextView headerView; @BindView(R.id.two_line_container) View twoLineContainer; @BindView(R.id.header2) TextView titleView; @BindView(R.id.subheader) TextView subtitleView; @BindView(R.id.log_player_username) AutoCompleteTextView usernameView; @BindView(R.id.log_player_name) AutoCompleteTextView nameView; @BindView(R.id.log_player_team_color) AutoCompleteTextView teamColorView; @BindView(R.id.color_view) ImageView colorView; @BindView(R.id.log_player_position) EditText positionView; @BindView(R.id.log_player_position_button) Button positionButton; @BindView(R.id.log_player_score) EditText scoreView; @BindView(R.id.log_player_score_button) Button scoreButton; @BindView(R.id.log_player_rating) EditText ratingView; @BindView(R.id.log_player_new) SwitchCompat newView; @BindView(R.id.log_player_win) SwitchCompat winView; @BindView(R.id.fab) FloatingActionButton fab; @BindView(R.id.fab_buffer) View fabBuffer; private ShowcaseViewWizard showcaseWizard; private boolean preferToShowTeamColor; private boolean preferToShowPosition; private boolean preferToShowScore; private boolean preferToShowRating; private boolean preferToShowNew; private boolean preferToShowWin; @State boolean userHasShownTeamColor; @State boolean userHasShownPosition; @State boolean userHasShownScore; @State boolean userHasShownRating; @State boolean userHasShownNew; @State boolean userHasShownWin; private int autoPosition; private ArrayList<String> usedColors; private ArrayList<String> colors; private final View.OnClickListener actionBarListener = new View.OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { case R.id.menu_done: save(); break; case R.id.menu_cancel: cancel(); break; } } }; @SuppressLint("HandlerLeak") private class QueryHandler extends AsyncQueryHandler { public QueryHandler(ContentResolver cr) { super(cr); } @DebugLog @Override protected void onQueryComplete(int token, Object cookie, Cursor cursor) { if (cursor == null) { return; } if (isFinishing()) { cursor.close(); return; } switch (token) { case TOKEN_COLORS: if (cursor.getCount() == 0) { cursor.close(); return; } try { if (cursor.moveToFirst()) { colors = new ArrayList<>(); do { colors.add(cursor.getString(0)); } while (cursor.moveToNext()); } } finally { cursor.close(); } break; default: cursor.close(); break; } } } @DebugLog @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_logplayer); ButterKnife.bind(this); nameView.setOnItemClickListener(nameClickListener()); ToolbarUtils.setDoneCancelActionBarView(this, actionBarListener); final Intent intent = getIntent(); int gameId = intent.getIntExtra(KEY_GAME_ID, BggContract.INVALID_ID); position = intent.getIntExtra(KEY_POSITION, INVALID_POSITION); gameName = intent.getStringExtra(KEY_GAME_NAME); String imageUrl = intent.getStringExtra(KEY_IMAGE_URL); autoPosition = intent.getIntExtra(KEY_AUTO_POSITION, Player.SEAT_UNKNOWN); String[] usedColors = intent.getStringArrayExtra(KEY_USED_COLORS); if (intent.getBooleanExtra(KEY_END_PLAY, false)) { userHasShownScore = true; scoreView.requestFocus(); } fab.setBackgroundTintList(ColorStateList.valueOf(intent.getIntExtra(KEY_FAB_COLOR, ContextCompat.getColor(this, R.color.accent)))); if (savedInstanceState == null) { player = intent.getParcelableExtra(KEY_PLAYER); if (player == null) { player = new Player(); } if (hasAutoPosition()) { player.setSeat(autoPosition); } originalPlayer = new Player(player); } else { Icepick.restoreInstanceState(this, savedInstanceState); } this.usedColors = (usedColors == null) ? new ArrayList<String>() : new ArrayList<>(Arrays.asList(usedColors)); this.usedColors.remove(player.color); ImageUtils.safelyLoadImage((ImageView) findViewById(R.id.thumbnail), imageUrl); bindUi(); new QueryHandler(getContentResolver()).startQuery(TOKEN_COLORS, null, Games.buildColorsUri(gameId), new String[] { GameColors.COLOR }, null, null, null); nameView.setAdapter(new PlayerNameAdapter(this)); usernameView.setAdapter(new BuddyNameAdapter(this)); teamColorView.setAdapter(new GameColorAdapter(this, gameId, R.layout.autocomplete_color)); setUpShowcaseViewWizard(); showcaseWizard.maybeShowHelp(); } @DebugLog @Override protected void onResume() { super.onResume(); preferToShowTeamColor = PreferencesUtils.showLogPlayerTeamColor(this); preferToShowPosition = PreferencesUtils.showLogPlayerPosition(this); preferToShowScore = PreferencesUtils.showLogPlayerScore(this); preferToShowRating = PreferencesUtils.showLogPlayerRating(this); preferToShowNew = PreferencesUtils.showLogPlayerNew(this); preferToShowWin = PreferencesUtils.showLogPlayerWin(this); setViewVisibility(); } @DebugLog @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Icepick.saveInstanceState(this, outState); } @DebugLog @Override public void onBackPressed() { cancel(); } @DebugLog private OnItemClickListener nameClickListener() { return new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { usernameView.setText((String) view.getTag()); } }; } @DebugLog @OnClick(R.id.color_view) public void onColorClick() { ColorPickerDialogFragment fragment = ColorPickerDialogFragment.newInstance(0, ColorUtils.getColorList(), colors, teamColorView.getText().toString(), usedColors, null, 4); fragment.setOnColorSelectedListener(new ColorPickerDialogFragment.OnColorSelectedListener() { @Override public void onColorSelected(String description, int color) { teamColorView.setText(description); } }); fragment.show(getSupportFragmentManager(), "color_picker"); } @DebugLog @OnTextChanged(R.id.log_player_team_color) public void afterTextChanged(Editable text) { int color = ColorUtils.parseColor(text.toString()); ColorUtils.setColorViewValue(colorView, color); } @DebugLog @OnClick({ R.id.log_player_position_button, R.id.log_player_score_button }) public void onNumberToTextClick(Button button) { EditText editText = null; if (button == positionButton) { editText = positionView; } else if (button == scoreButton) { editText = scoreView; } if (editText == null) { return; } int type = editText.getInputType(); if ((type & InputType.TYPE_CLASS_NUMBER) == InputType.TYPE_CLASS_NUMBER) { editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_WORDS | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); button.setText(R.string.text_to_number); } else { editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL | InputType.TYPE_NUMBER_FLAG_SIGNED); button.setText(R.string.number_to_text); } editText.requestFocus(); } @DebugLog private void setUpShowcaseViewWizard() { showcaseWizard = new ShowcaseViewWizard(this, HelpUtils.HELP_LOGPLAYER_KEY, HELP_VERSION); showcaseWizard.addTarget(R.string.help_logplayer, Target.NONE); } @DebugLog private void bindUi() { if (hasAutoPosition()) { titleView.setText(gameName); subtitleView.setText(getString(R.string.title_player) + " #" + autoPosition); headerView.setVisibility(View.GONE); twoLineContainer.setVisibility(View.VISIBLE); } else { headerView.setText(gameName); headerView.setVisibility(View.VISIBLE); twoLineContainer.setVisibility(View.GONE); } nameView.setTextKeepState(player.name); usernameView.setTextKeepState(player.username); teamColorView.setTextKeepState(player.color); if (player.getStartingPosition() != null) { positionView.setTextKeepState(player.getStartingPosition()); } scoreView.setTextKeepState(player.score); ratingView.setTextKeepState((player.rating == Player.DEFAULT_RATING) ? "" : String.valueOf(player.rating)); newView.setChecked(player.New()); winView.setChecked(player.Win()); } @DebugLog private void setViewVisibility() { boolean enableButton = hideRow(shouldHideTeamColor(), findViewById(R.id.log_player_team_color_container)); enableButton |= hideRow(shouldHidePosition(), findViewById(R.id.log_player_position_container)); if (hasAutoPosition()) { hideRow(true, findViewById(R.id.log_player_position_container)); } enableButton |= hideRow(shouldHideScore(), findViewById(R.id.log_player_score_container)); enableButton |= hideRow(shouldHideRating(), findViewById(R.id.log_player_rating_container)); enableButton |= hideRow(shouldHideNew(), newView); enableButton |= hideRow(shouldHideWin(), winView); fabBuffer.setVisibility(enableButton ? View.VISIBLE : View.GONE); if (enableButton) { fab.show(); } else { fab.hide(); } } @DebugLog private boolean hideRow(boolean shouldHide, View view) { if (shouldHide) { view.setVisibility(View.GONE); return true; } view.setVisibility(View.VISIBLE); return false; } @DebugLog private boolean shouldHideTeamColor() { return !preferToShowTeamColor && !userHasShownTeamColor && TextUtils.isEmpty(player.color); } @DebugLog private boolean shouldHidePosition() { return !preferToShowPosition && !userHasShownPosition && TextUtils.isEmpty(player.getStartingPosition()); } @DebugLog private boolean hasAutoPosition() { return autoPosition != Player.SEAT_UNKNOWN; } @DebugLog private boolean shouldHideScore() { return !preferToShowScore && !userHasShownScore && TextUtils.isEmpty(player.score); } @DebugLog private boolean shouldHideRating() { return !preferToShowRating && !userHasShownRating && !(player.rating > 0); } @DebugLog private boolean shouldHideNew() { return !preferToShowNew && !userHasShownNew && !player.New(); } @DebugLog private boolean shouldHideWin() { return !preferToShowWin && !userHasShownWin && !player.Win(); } @DebugLog @OnClick(R.id.fab) public void addField() { final CharSequence[] array = createAddFieldArray(); if (array == null || array.length == 0) { return; } new AlertDialog.Builder(this).setTitle(R.string.add_field) .setItems(array, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Resources r = getResources(); View viewToFocus = null; View viewToScroll = null; String selection = array[which].toString(); if (selection.equals(r.getString(R.string.team_color))) { userHasShownTeamColor = true; viewToFocus = teamColorView; viewToScroll = findViewById(R.id.log_player_team_color_container); } else if (selection.equals(r.getString(R.string.starting_position))) { userHasShownPosition = true; viewToFocus = positionView; viewToScroll = findViewById(R.id.log_player_position_container); } else if (selection.equals(r.getString(R.string.score))) { userHasShownScore = true; viewToFocus = scoreView; viewToScroll = findViewById(R.id.log_player_score_container); } else if (selection.equals(r.getString(R.string.rating))) { userHasShownRating = true; viewToFocus = ratingView; viewToScroll = findViewById(R.id.log_player_rating); } else if (selection.equals(r.getString(R.string.new_label))) { userHasShownNew = true; newView.setChecked(true); viewToScroll = newView; viewToFocus = newView; } else if (selection.equals(r.getString(R.string.win))) { userHasShownWin = true; winView.setChecked(true); viewToScroll = winView; viewToFocus = winView; } AddFieldEvent.log("Player", selection); setViewVisibility(); if (viewToFocus != null) { viewToFocus.requestFocus(); } if (viewToScroll != null) { final View finalView = viewToScroll; scrollContainer.post(new Runnable() { @Override public void run() { scrollContainer.smoothScrollTo(0, finalView.getBottom()); } }); } } }).show(); } @DebugLog private CharSequence[] createAddFieldArray() { Resources r = getResources(); List<CharSequence> list = new ArrayList<>(); if (shouldHideTeamColor()) { list.add(r.getString(R.string.team_color)); } if (!hasAutoPosition() && shouldHidePosition()) { list.add(r.getString(R.string.starting_position)); } if (shouldHideScore()) { list.add(r.getString(R.string.score)); } if (shouldHideRating()) { list.add(r.getString(R.string.rating)); } if (shouldHideNew()) { list.add(r.getString(R.string.new_label)); } if (shouldHideWin()) { list.add(r.getString(R.string.win)); } CharSequence[] csa = {}; csa = list.toArray(csa); return csa; } @DebugLog private void save() { captureForm(); Intent intent = new Intent(); intent.putExtra(KEY_PLAYER, player); intent.putExtra(KEY_POSITION, position); setResult(RESULT_OK, intent); finish(); } @DebugLog private void cancel() { captureForm(); if (player.equals(originalPlayer)) { setResult(RESULT_CANCELED); finish(); } else { DialogUtils.createCancelDialog(this).show(); } } @DebugLog private void captureForm() { player.name = nameView.getText().toString().trim(); player.username = usernameView.getText().toString().trim(); player.color = teamColorView.getText().toString().trim(); player.setStartingPosition(positionView.getText().toString().trim()); player.score = scoreView.getText().toString().trim(); player.rating = StringUtils.parseDouble(ratingView.getText().toString().trim()); player.New(newView.isChecked()); player.Win(winView.isChecked()); } }