Java tutorial
/* * Twidere - Twitter client for Android * * Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com> * * This program 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. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ package org.mariotaku.twidere.fragment; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnShowListener; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.support.v7.app.AlertDialog; import android.text.Editable; import android.text.TextWatcher; import android.util.SparseBooleanArray; import android.view.ActionMode; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import org.apache.commons.lang3.StringUtils; import org.mariotaku.twidere.R; import org.mariotaku.twidere.adapter.ArrayAdapter; import org.mariotaku.twidere.util.ParseUtils; import org.mariotaku.twidere.util.SharedPreferencesWrapper; import java.util.Map; import static android.text.TextUtils.isEmpty; public class HostMappingsListFragment extends BaseListFragment implements MultiChoiceModeListener, OnSharedPreferenceChangeListener { private static final String EXTRA_EDIT_MODE = "edit_mode"; private static final String EXTRA_HOST = "host"; private static final String EXTRA_ADDRESS = "address"; private static final String EXTRA_EXCLUDED = "excluded"; private ListView mListView; private HostMappingAdapter mAdapter; private SharedPreferencesWrapper mHostMapping; @Override public void onActivityCreated(final Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); mHostMapping = SharedPreferencesWrapper.getInstance(getActivity(), HOST_MAPPING_PREFERENCES_NAME, Context.MODE_PRIVATE); mHostMapping.registerOnSharedPreferenceChangeListener(this); mAdapter = new HostMappingAdapter(getActivity()); setListAdapter(mAdapter); mListView = getListView(); mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); mListView.setMultiChoiceModeListener(this); reloadHostMappings(); } @Override public boolean onCreateActionMode(final ActionMode mode, final Menu menu) { mode.getMenuInflater().inflate(R.menu.action_multi_select_items, menu); return true; } @Override public boolean onPrepareActionMode(final ActionMode mode, final Menu menu) { updateTitle(mode); return true; } @Override public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) { switch (item.getItemId()) { case R.id.delete: { final SharedPreferences.Editor editor = mHostMapping.edit(); final SparseBooleanArray array = mListView.getCheckedItemPositions(); if (array == null) return false; for (int i = 0, size = array.size(); i < size; i++) { if (array.valueAt(i)) { editor.remove(mAdapter.getItem(i)); } } editor.apply(); reloadHostMappings(); break; } default: { return false; } } mode.finish(); return true; } @Override public void onDestroyActionMode(final ActionMode mode) { } @Override public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { inflater.inflate(R.menu.menu_host_mapping, menu); } @Override public void onListItemClick(ListView l, View v, int position, long id) { final String host = mAdapter.getItem(position); final String address = mAdapter.getAddress(host); final Bundle args = new Bundle(); args.putString(EXTRA_HOST, host); args.putString(EXTRA_ADDRESS, address); args.putBoolean(EXTRA_EXCLUDED, StringUtils.equals(host, address)); args.putBoolean(EXTRA_EDIT_MODE, true); final DialogFragment df = new AddMappingDialogFragment(); df.setArguments(args); df.show(getFragmentManager(), "add_mapping"); } @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case R.id.add: { final DialogFragment df = new AddMappingDialogFragment(); df.show(getFragmentManager(), "add_mapping"); break; } } return super.onOptionsItemSelected(item); } @Override public void onItemCheckedStateChanged(final ActionMode mode, final int position, final long id, final boolean checked) { updateTitle(mode); } @Override public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) { reloadHostMappings(); } public void reloadHostMappings() { if (mAdapter == null) return; mAdapter.reload(); } private void updateTitle(final ActionMode mode) { if (mListView == null || mode == null || getActivity() == null) return; final int count = mListView.getCheckedItemCount(); mode.setTitle(getResources().getQuantityString(R.plurals.Nitems_selected, count, count)); } public static class AddMappingDialogFragment extends BaseDialogFragment implements OnClickListener, TextWatcher, OnCheckedChangeListener { private EditText mEditHost, mEditAddress; private CheckBox mCheckExclude; @Override public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) { } @Override public void onTextChanged(final CharSequence s, final int start, final int before, final int count) { updateButton(); } @Override public void afterTextChanged(final Editable s) { } @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { updateAddressField(); updateButton(); } @Override public void onClick(final DialogInterface dialog, final int which) { switch (which) { case DialogInterface.BUTTON_POSITIVE: { final String host = ParseUtils.parseString(mEditHost.getText()); final String address = mCheckExclude.isChecked() ? host : ParseUtils.parseString(mEditAddress.getText()); if (isEmpty(host) || isEmpty(address)) return; final SharedPreferences prefs = getSharedPreferences(HOST_MAPPING_PREFERENCES_NAME, Context.MODE_PRIVATE); final SharedPreferences.Editor editor = prefs.edit(); editor.putString(host, address); editor.apply(); break; } } } @NonNull @Override public Dialog onCreateDialog(final Bundle savedInstanceState) { final Context context = getActivity(); final AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setView(R.layout.dialog_host_mapping); builder.setTitle(R.string.add_host_mapping); builder.setPositiveButton(android.R.string.ok, this); builder.setNegativeButton(android.R.string.cancel, null); final AlertDialog dialog = builder.create(); dialog.setOnShowListener(new OnShowListener() { @Override public void onShow(DialogInterface dialog) { AlertDialog alertDialog = (AlertDialog) dialog; mEditHost = (EditText) alertDialog.findViewById(R.id.host); mEditAddress = (EditText) alertDialog.findViewById(R.id.address); mCheckExclude = (CheckBox) alertDialog.findViewById(R.id.exclude); mEditHost.addTextChangedListener(AddMappingDialogFragment.this); mEditAddress.addTextChangedListener(AddMappingDialogFragment.this); mCheckExclude.setOnCheckedChangeListener(AddMappingDialogFragment.this); final Bundle args = getArguments(); if (args != null) { mEditHost.setEnabled(!args.getBoolean(EXTRA_EDIT_MODE, false)); if (savedInstanceState == null) { mEditHost.setText(args.getCharSequence(EXTRA_HOST)); mEditAddress.setText(args.getCharSequence(EXTRA_ADDRESS)); mCheckExclude.setChecked(args.getBoolean(EXTRA_EXCLUDED)); } } updateButton(); } }); return dialog; } @Override public void onSaveInstanceState(@NonNull final Bundle outState) { outState.putCharSequence(EXTRA_HOST, mEditHost.getText()); outState.putCharSequence(EXTRA_ADDRESS, mEditAddress.getText()); outState.putCharSequence(EXTRA_EXCLUDED, mEditAddress.getText()); super.onSaveInstanceState(outState); } private void updateAddressField() { mEditAddress.setVisibility(mCheckExclude.isChecked() ? View.GONE : View.VISIBLE); } private void updateButton() { final AlertDialog dialog = (AlertDialog) getDialog(); if (dialog == null) return; final boolean hostValid = !isEmpty(mEditHost.getText()); final boolean addressValid = !isEmpty(mEditAddress.getText()) || mCheckExclude.isChecked(); final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE); positiveButton.setEnabled(hostValid && addressValid); } } static class HostMappingAdapter extends ArrayAdapter<String> { private final SharedPreferences mHostMapping; public HostMappingAdapter(final Context context) { super(context, android.R.layout.simple_list_item_activated_2); mHostMapping = context.getSharedPreferences(HOST_MAPPING_PREFERENCES_NAME, Context.MODE_PRIVATE); } @Override public View getView(final int position, final View convertView, final ViewGroup parent) { final View view = super.getView(position, convertView, parent); final TextView text1 = (TextView) view.findViewById(android.R.id.text1); final TextView text2 = (TextView) view.findViewById(android.R.id.text2); final String key = getItem(position); text1.setText(key); final String value = getAddress(key); if (StringUtils.equals(key, value)) { text2.setText(R.string.excluded); } else { text2.setText(value); } return view; } public void reload() { clear(); final Map<String, ?> all = mHostMapping.getAll(); addAll(all.keySet()); } public String getAddress(String key) { return mHostMapping.getString(key, null); } } }