Java tutorial
/* * Tweetings - Twitter client for Android * * Copyright (C) 2012-2013 RBD Solutions Limited <apps@tweetings.net> * Copyright (C) 2012 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 com.dwdesign.tweetings.fragment; import static com.dwdesign.tweetings.util.Utils.buildDirectMessageConversationUri; import static com.dwdesign.tweetings.util.Utils.isNullOrEmpty; import static com.dwdesign.tweetings.util.Utils.openUserProfile; import static com.dwdesign.tweetings.util.Utils.parseString; import com.dwdesign.popupmenu.PopupMenu; import com.dwdesign.popupmenu.PopupMenu.OnMenuItemClickListener; import com.dwdesign.tweetings.R; import com.dwdesign.tweetings.adapter.DirectMessagesConversationAdapter; import com.dwdesign.tweetings.adapter.UserAutoCompleteAdapter; import com.dwdesign.tweetings.app.TweetingsApplication; import com.dwdesign.tweetings.model.Account; import com.dwdesign.tweetings.model.DirectMessageConversationViewHolder; import com.dwdesign.tweetings.model.Panes; import com.dwdesign.tweetings.model.ParcelableDirectMessage; import com.dwdesign.tweetings.provider.TweetStore; import com.dwdesign.tweetings.provider.TweetStore.DirectMessages; import com.dwdesign.tweetings.util.ImageLoaderWrapper; import com.dwdesign.tweetings.util.ClipboardUtils; import com.dwdesign.tweetings.util.ServiceInterface; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.database.Cursor; import android.graphics.Color; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.text.Editable; import android.text.Html; import android.text.TextWatcher; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.Button; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ListView; import android.widget.Spinner; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; import android.widget.Toast; import com.twitter.Validator; public class DMConversationFragment extends BaseFragment implements LoaderCallbacks<Cursor>, OnItemClickListener, OnItemLongClickListener, OnMenuItemClickListener, TextWatcher, OnClickListener, Panes.Right, OnItemSelectedListener, OnEditorActionListener { private final Validator mValidator = new Validator(); private ServiceInterface mService; private SharedPreferences mPreferences; private ListView mListView; private EditText mEditText; private TextView mTextCount; private AutoCompleteTextView mEditScreenName; private ImageButton mSendButton; private Button mScreenNameConfirmButton; private View mConversationContainer, mScreenNameContainer; private Spinner mAccountSelector; private PopupMenu mPopupMenu; private ParcelableDirectMessage mSelectedDirectMessage; private final Bundle mArguments = new Bundle(); private Account mSelectedAccount; private DirectMessagesConversationAdapter mAdapter; private UserAutoCompleteAdapter mUserAutoCompleteAdapter; private AccountsAdapter mAccountsAdapter; private boolean isVisibleToUser = false; // Begin Sync Code private final BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { final String action = intent.getAction(); if (BROADCAST_VOLUME_UP.equals(action)) { //if (isVisible()) { int currentPosition = mListView.getFirstVisiblePosition(); if (currentPosition == 0) return; mListView.setSelection(currentPosition - 1); mListView.clearFocus(); //} } else if (BROADCAST_VOLUME_DOWN.equals(action)) { //if (isVisible()) { int currentPosition = mListView.getFirstVisiblePosition(); if (currentPosition == mListView.getCount() - 1) return; mListView.setSelection(currentPosition + 1); mListView.clearFocus(); //} } } }; @Override public void setMenuVisibility(final boolean visible) { super.setMenuVisibility(visible); isVisibleToUser = visible; } @Override public void onResume() { super.onResume(); IntentFilter filter = new IntentFilter(); filter.addAction(BROADCAST_VOLUME_UP); filter.addAction(BROADCAST_VOLUME_DOWN); registerReceiver(receiver, filter); } @Override public void onPause() { super.onPause(); unregisterReceiver(receiver); } private final BroadcastReceiver mStatusReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { final String action = intent.getAction(); if (BROADCAST_RECEIVED_DIRECT_MESSAGES_DATABASE_UPDATED.equals(action) || BROADCAST_SENT_DIRECT_MESSAGES_DATABASE_UPDATED.equals(action)) { getLoaderManager().restartLoader(0, mArguments, DMConversationFragment.this); } else if (BROADCAST_RECEIVED_DIRECT_MESSAGES_REFRESHED.equals(action) || BROADCAST_SENT_DIRECT_MESSAGES_REFRESHED.equals(action)) { getLoaderManager().restartLoader(0, mArguments, DMConversationFragment.this); } else if (BROADCAST_REFRESHSTATE_CHANGED.equals(action)) { setProgressBarIndeterminateVisibility( mService.isReceivedDirectMessagesRefreshing() || mService.isSentDirectMessagesRefreshing()); } } }; private final TextWatcher mScreenNameTextWatcher = new TextWatcher() { @Override public void afterTextChanged(final Editable s) { } @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) { if (mScreenNameConfirmButton == null) return; mScreenNameConfirmButton.setEnabled(s.length() > 0 && s.length() < 20); } }; private TweetingsApplication mApplication; @Override public void afterTextChanged(final Editable s) { } @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) { if (mSendButton == null || s == null) return; mSendButton.setEnabled(mValidator.isValidTweet(s.toString())); if (mTextCount != null) { final int acount = mValidator.getTweetLength(s.toString()); final float hue = acount < 140 ? acount >= 130 ? 5 * (140 - acount) : 50 : 0; final float[] hsv = new float[] { hue, 1.0f, 1.0f }; mTextCount.setTextColor(acount >= 130 ? Color.HSVToColor(0x80, hsv) : 0x80808080); mTextCount.setText(parseString(140 - acount)); } } @Override public void onActivityCreated(final Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mApplication = getApplication(); mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); mService = getServiceInterface(); mAdapter = new DirectMessagesConversationAdapter(getActivity()); mListView.setAdapter(mAdapter); mListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL); mListView.setStackFromBottom(true); mListView.setOnItemClickListener(this); mListView.setOnItemLongClickListener(this); final Bundle args = savedInstanceState == null ? getArguments() : savedInstanceState.getBundle(INTENT_KEY_DATA); if (args != null) { mArguments.putAll(args); } getLoaderManager().initLoader(0, mArguments, this); if (mPreferences.getBoolean(PREFERENCE_KEY_QUICK_SEND, false)) { mEditText.setOnEditorActionListener(this); } mEditText.addTextChangedListener(this); final String text = savedInstanceState != null ? savedInstanceState.getString(INTENT_KEY_TEXT) : null; if (text != null) { mEditText.setText(text); } mAccountsAdapter = new AccountsAdapter(getActivity()); mAccountSelector.setAdapter(mAccountsAdapter); mAccountSelector.setOnItemSelectedListener(this); mUserAutoCompleteAdapter = new UserAutoCompleteAdapter(getActivity()); mEditScreenName.addTextChangedListener(mScreenNameTextWatcher); mEditScreenName.setAdapter(mUserAutoCompleteAdapter); mSendButton.setOnClickListener(this); mSendButton.setEnabled(false); mScreenNameConfirmButton.setOnClickListener(this); mScreenNameConfirmButton.setEnabled(false); mTextCount = (TextView) getActivity().findViewById(R.id.text_count); } @Override public void onClick(final View view) { switch (view.getId()) { case R.id.send: { send(); break; } case R.id.screen_name_confirm: { final CharSequence text = mEditScreenName.getText(); if (text == null || mSelectedAccount == null) return; final String screen_name = text.toString(); mArguments.putString(INTENT_KEY_SCREEN_NAME, screen_name); mArguments.putLong(INTENT_KEY_ACCOUNT_ID, mSelectedAccount.account_id); getLoaderManager().restartLoader(0, mArguments, this); break; } } } @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Tell the framework to try to keep this fragment around // during a configuration change. setRetainInstance(true); } @Override public Loader<Cursor> onCreateLoader(final int id, final Bundle args) { if (args == null || !args.containsKey(INTENT_KEY_ACCOUNT_ID)) return new CursorLoader(getActivity(), TweetStore.NULL_CONTENT_URI, null, null, null, null); final String[] cols = DirectMessages.COLUMNS; final long account_id = args != null ? args.getLong(INTENT_KEY_ACCOUNT_ID, -1) : -1; final long conversation_id = args != null ? args.getLong(INTENT_KEY_CONVERSATION_ID, -1) : -1; final String screen_name = args != null ? args.getString(INTENT_KEY_SCREEN_NAME) : null; final Uri uri = buildDirectMessageConversationUri(account_id, conversation_id, screen_name); mConversationContainer.setVisibility( account_id <= 0 || conversation_id <= 0 && screen_name == null ? View.GONE : View.VISIBLE); mScreenNameContainer.setVisibility( account_id <= 0 || conversation_id <= 0 && screen_name == null ? View.VISIBLE : View.GONE); return new CursorLoader(getActivity(), uri, cols, null, null, DirectMessages.Conversation.DEFAULT_SORT_ORDER); } @Override public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.direct_messages_conversation, null); mListView = (ListView) view.findViewById(android.R.id.list); mEditText = (EditText) view.findViewById(R.id.edit_text); mSendButton = (ImageButton) view.findViewById(R.id.send); mConversationContainer = view.findViewById(R.id.conversation_container); mScreenNameContainer = view.findViewById(R.id.screen_name_container); mEditScreenName = (AutoCompleteTextView) view.findViewById(R.id.screen_name); mAccountSelector = (Spinner) view.findViewById(R.id.account_selector); mScreenNameConfirmButton = (Button) view.findViewById(R.id.screen_name_confirm); return view; } @Override public void onDestroy() { super.onDestroy(); } @Override public boolean onEditorAction(final TextView view, final int actionId, final KeyEvent event) { switch (event.getKeyCode()) { case KeyEvent.KEYCODE_ENTER: { send(); return true; } } return false; } @Override public void onItemClick(final AdapterView<?> adapter, final View view, final int position, final long id) { final Object tag = view.getTag(); if (tag instanceof DirectMessageConversationViewHolder) { } } @Override public boolean onItemLongClick(final AdapterView<?> adapter, final View view, final int position, final long id) { final Object tag = view.getTag(); if (tag instanceof DirectMessageConversationViewHolder) { final ParcelableDirectMessage dm = mSelectedDirectMessage = mAdapter.findItem(id); mPopupMenu = PopupMenu.getInstance(getActivity(), view); mPopupMenu.inflate(R.menu.action_direct_message); final Menu menu = mPopupMenu.getMenu(); final MenuItem view_profile_item = menu.findItem(MENU_VIEW_PROFILE); if (view_profile_item != null && dm != null) { view_profile_item.setVisible(dm.account_id != dm.sender_id); } mPopupMenu.setOnMenuItemClickListener(this); mPopupMenu.show(); return true; } return false; } @Override public void onItemSelected(final AdapterView<?> parent, final View view, final int pos, final long id) { mSelectedAccount = null; if (mAccountsAdapter == null) return; mSelectedAccount = mAccountsAdapter.getItem(pos); } @Override public void onLoaderReset(final Loader<Cursor> loader) { mAdapter.swapCursor(null); } @Override public void onLoadFinished(final Loader<Cursor> loader, final Cursor cursor) { mAdapter.swapCursor(cursor); } @Override public boolean onMenuItemClick(final MenuItem item) { if (mSelectedDirectMessage != null) { final long message_id = mSelectedDirectMessage.message_id; final long account_id = mSelectedDirectMessage.account_id; switch (item.getItemId()) { case MENU_REPLY: { break; } case MENU_DELETE: { mService.destroyDirectMessage(account_id, message_id); break; } case MENU_COPY: { if (ClipboardUtils.setText(getActivity(), mSelectedDirectMessage.text)) { Toast.makeText(getActivity(), R.string.text_copied, Toast.LENGTH_SHORT).show(); } break; } case MENU_VIEW_PROFILE: { if (mSelectedDirectMessage == null) return false; openUserProfile(getActivity(), account_id, mSelectedDirectMessage.sender_id, mSelectedDirectMessage.sender_screen_name); break; } default: return false; } } return true; } @Override public void onNothingSelected(final AdapterView<?> view) { } @Override public void onSaveInstanceState(final Bundle outState) { if (mEditText != null) { outState.putString(INTENT_KEY_TEXT, parseString(mEditText.getText())); } outState.putBundle(INTENT_KEY_DATA, mArguments); super.onSaveInstanceState(outState); } @Override public void onStart() { super.onStart(); final IntentFilter filter = new IntentFilter(BROADCAST_REFRESHSTATE_CHANGED); filter.addAction(BROADCAST_RECEIVED_DIRECT_MESSAGES_DATABASE_UPDATED); filter.addAction(BROADCAST_SENT_DIRECT_MESSAGES_DATABASE_UPDATED); filter.addAction(BROADCAST_RECEIVED_DIRECT_MESSAGES_REFRESHED); filter.addAction(BROADCAST_SENT_DIRECT_MESSAGES_REFRESHED); registerReceiver(mStatusReceiver, filter); final float text_size = mPreferences.getFloat(PREFERENCE_KEY_TEXT_SIZE, PREFERENCE_DEFAULT_TEXT_SIZE); final boolean display_profile_image = mPreferences.getBoolean(PREFERENCE_KEY_DISPLAY_PROFILE_IMAGE, true); final boolean display_name = mPreferences.getBoolean(PREFERENCE_KEY_DISPLAY_NAME, false); mAdapter.setDisplayProfileImage(display_profile_image); mAdapter.setDisplayName(display_name); mAdapter.setTextSize(text_size); } @Override public void onStop() { unregisterReceiver(mStatusReceiver); if (mPopupMenu != null) { mPopupMenu.dismiss(); } super.onStop(); } public void showConversation(final long account_id, final long conversation_id) { final Bundle args = new Bundle(); args.putLong(INTENT_KEY_ACCOUNT_ID, account_id); args.putLong(INTENT_KEY_CONVERSATION_ID, conversation_id); getLoaderManager().restartLoader(0, args, this); } private void send() { final Editable text = mEditText.getText(); if (isNullOrEmpty(text)) return; final String message = text.toString(); if (mValidator.isValidTweet(message)) { final long account_id = mArguments.getLong(INTENT_KEY_ACCOUNT_ID, -1); final long conversation_id = mArguments.getLong(INTENT_KEY_CONVERSATION_ID, -1); final String screen_name = mArguments.getString(INTENT_KEY_SCREEN_NAME); mService.sendDirectMessage(account_id, screen_name, conversation_id, message); text.clear(); } } private static class AccountsAdapter extends ArrayAdapter<Account> { public AccountsAdapter(final Context context) { super(context, R.layout.spinner_item, Account.getAccounts(context, true)); setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); } } }