diff options
author | laco0416 <laco0416@gmail.com> | 2015-04-26 19:03:29 +0900 |
---|---|---|
committer | laco0416 <laco0416@gmail.com> | 2015-04-26 19:03:31 +0900 |
commit | d2cda779b3dcaad81ad68018270b84636a576c37 (patch) | |
tree | cf6b2e2019f0778ef96bb5b2ee7849b6722bee8d /app/src/main/java/net/lacolaco/smileessence/view | |
parent | ae56571e6e1358ce2ae7afb24959d97af0917022 (diff) | |
download | SmileEssence-d2cda779b3dcaad81ad68018270b84636a576c37.tar.gz |
Reconstruct the project
Diffstat (limited to 'app/src/main/java/net/lacolaco/smileessence/view')
41 files changed, 5962 insertions, 0 deletions
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/CustomListFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/CustomListFragment.java new file mode 100644 index 00000000..f6a683fe --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/CustomListFragment.java @@ -0,0 +1,167 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.ListAdapter; +import android.widget.ListView; + +import com.handmark.pulltorefresh.library.PullToRefreshBase; +import com.handmark.pulltorefresh.library.PullToRefreshListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.notification.Notificator; +import net.lacolaco.smileessence.view.adapter.CustomListAdapter; + +public class CustomListFragment extends Fragment implements AbsListView.OnScrollListener, + PullToRefreshBase.OnRefreshListener2<ListView> { + + // ------------------------------ FIELDS ------------------------------ + + public static final String ADAPTER_INDEX = "fragmentIndex"; + public static final int SCROLL_DURATION = 1500; + + private int fragmentIndex; + + // --------------------- GETTER / SETTER METHODS --------------------- + + protected PullToRefreshBase.Mode getRefreshMode() { + return PullToRefreshBase.Mode.DISABLED; + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnRefreshListener2 --------------------- + + @Override + public void onPullDownToRefresh(PullToRefreshBase<ListView> refreshView) { + + } + + @Override + public void onPullUpToRefresh(PullToRefreshBase<ListView> refreshView) { + + } + + // --------------------- Interface OnScrollListener --------------------- + + @Override + public void onScrollStateChanged(AbsListView absListView, int scrollState) { + Bundle args = getArguments(); + fragmentIndex = args.getInt(ADAPTER_INDEX); + CustomListAdapter<?> adapter = getListAdapter(fragmentIndex); + adapter.setNotifiable(false); + + if (absListView.getFirstVisiblePosition() == 0 && absListView.getChildAt(0) != null && absListView.getChildAt(0).getTop() == 0) { + if (scrollState == SCROLL_STATE_IDLE) { + updateListViewWithNotice(absListView, adapter, true); + } + } + } + + @Override + public void onScroll(AbsListView absListView, int i, int i2, int i3) { + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Bundle args = getArguments(); + fragmentIndex = args.getInt(ADAPTER_INDEX); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View page = inflater.inflate(R.layout.fragment_list, container, false); + Bundle args = getArguments(); + int fragmentIndex = args.getInt(ADAPTER_INDEX); + PullToRefreshListView listView = getListView(page); + ListAdapter adapter = getListAdapter(fragmentIndex); + listView.setAdapter(adapter); + listView.setOnScrollListener(this); + listView.setOnRefreshListener(this); + listView.setMode(getRefreshMode()); + return page; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(ADAPTER_INDEX, fragmentIndex); + } + + @Override + public void onViewStateRestored(Bundle savedInstanceState) { + super.onViewStateRestored(savedInstanceState); + if (savedInstanceState != null) { + fragmentIndex = savedInstanceState.getInt(ADAPTER_INDEX); + } + } + + protected CustomListAdapter<?> getListAdapter(int fragmentIndex) { + return ((MainActivity) getActivity()).getListAdapter(fragmentIndex); + } + + protected PullToRefreshListView getListView(View page) { + return (PullToRefreshListView) page.findViewById(R.id.fragment_list_listview); + } + + protected void notifyListUpdated(int increments) { + Notificator.publish(getActivity(), getString(R.string.notice_timeline_new, increments)); + } + + protected void updateListViewWithNotice(AbsListView absListView, CustomListAdapter<?> adapter, boolean addedToTop) { + int before = adapter.getCount(); + adapter.notifyDataSetChanged(); // synchronized call (not adapter#updateForce()) + int after = adapter.getCount(); + int increments = after - before; + if (increments > 0) { + adapter.setNotifiable(false); + notifyListUpdated(increments); + if (addedToTop) { + absListView.setSelection(increments + 1); + absListView.smoothScrollToPositionFromTop(increments, 0); + absListView.setSelection(increments); + } else { + absListView.smoothScrollToPositionFromTop(before, 0); + } + + if (increments == 1) { + adapter.setNotifiable(true); + } + } else { + adapter.setNotifiable(true); + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/HistoryFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/HistoryFragment.java new file mode 100644 index 00000000..3bdb001d --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/HistoryFragment.java @@ -0,0 +1,55 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view; + +import android.widget.ListView; + +import com.handmark.pulltorefresh.library.PullToRefreshBase; + +/** + * Fragment for notice history + */ +public class HistoryFragment extends CustomListFragment { + + // --------------------- GETTER / SETTER METHODS --------------------- + + @Override + protected PullToRefreshBase.Mode getRefreshMode() { + return PullToRefreshBase.Mode.DISABLED; + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnRefreshListener2 --------------------- + + @Override + public void onPullDownToRefresh(PullToRefreshBase<ListView> refreshView) { + } + + @Override + public void onPullUpToRefresh(PullToRefreshBase<ListView> refreshView) { + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/HomeFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/HomeFragment.java new file mode 100644 index 00000000..0cc3b77f --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/HomeFragment.java @@ -0,0 +1,123 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view; + +import android.widget.ListView; + +import com.handmark.pulltorefresh.library.PullToRefreshBase; + +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.twitter.StatusFilter; +import net.lacolaco.smileessence.twitter.TwitterApi; +import net.lacolaco.smileessence.twitter.task.HomeTimelineTask; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.util.UIHandler; +import net.lacolaco.smileessence.view.adapter.StatusListAdapter; +import net.lacolaco.smileessence.viewmodel.StatusViewModel; + +import twitter4j.Paging; +import twitter4j.Twitter; + +public class HomeFragment extends CustomListFragment { + + // --------------------- GETTER / SETTER METHODS --------------------- + + @Override + protected PullToRefreshBase.Mode getRefreshMode() { + return PullToRefreshBase.Mode.BOTH; + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnRefreshListener2 --------------------- + + @Override + public void onPullDownToRefresh(final PullToRefreshBase<ListView> refreshView) { + final MainActivity activity = (MainActivity) getActivity(); + if (activity.isStreaming()) { + new UIHandler() { + @Override + public void run() { + StatusListAdapter adapter = getListAdapter(activity); + updateListViewWithNotice(refreshView.getRefreshableView(), adapter, true); + refreshView.onRefreshComplete(); + } + }.post(); + return; + } + final Account currentAccount = activity.getCurrentAccount(); + Twitter twitter = TwitterApi.getTwitter(currentAccount); + final StatusListAdapter adapter = getListAdapter(activity); + Paging paging = TwitterUtils.getPaging(TwitterUtils.getPagingCount(activity)); + if (adapter.getCount() > 0) { + paging.setSinceId(adapter.getTopID()); + } + new HomeTimelineTask(twitter, activity, paging) { + @Override + protected void onPostExecute(twitter4j.Status[] statuses) { + super.onPostExecute(statuses); + for (int i = statuses.length - 1; i >= 0; i--) { + twitter4j.Status status = statuses[i]; + StatusViewModel viewModel = new StatusViewModel(status, currentAccount); + adapter.addToTop(viewModel); + StatusFilter.filter(activity, viewModel); + } + updateListViewWithNotice(refreshView.getRefreshableView(), adapter, true); + refreshView.onRefreshComplete(); + } + }.execute(); + } + + @Override + public void onPullUpToRefresh(final PullToRefreshBase<ListView> refreshView) { + final MainActivity activity = (MainActivity) getActivity(); + final Account currentAccount = activity.getCurrentAccount(); + Twitter twitter = TwitterApi.getTwitter(currentAccount); + final StatusListAdapter adapter = getListAdapter(activity); + Paging paging = TwitterUtils.getPaging(TwitterUtils.getPagingCount(activity)); + if (adapter.getCount() > 0) { + paging.setMaxId(adapter.getLastID() - 1); + } + new HomeTimelineTask(twitter, activity, paging) { + @Override + protected void onPostExecute(twitter4j.Status[] statuses) { + super.onPostExecute(statuses); + for (twitter4j.Status status : statuses) { + StatusViewModel viewModel = new StatusViewModel(status, currentAccount); + adapter.addToBottom(viewModel); + StatusFilter.filter(activity, viewModel); + } + updateListViewWithNotice(refreshView.getRefreshableView(), adapter, false); + refreshView.onRefreshComplete(); + } + }.execute(); + } + + private StatusListAdapter getListAdapter(MainActivity activity) { + return (StatusListAdapter) activity.getListAdapter(MainActivity.ADAPTER_HOME); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/MentionsFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/MentionsFragment.java new file mode 100644 index 00000000..d47d9552 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/MentionsFragment.java @@ -0,0 +1,106 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view; + +import android.widget.ListView; + +import com.handmark.pulltorefresh.library.PullToRefreshBase; + +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.twitter.TwitterApi; +import net.lacolaco.smileessence.twitter.task.MentionsTimelineTask; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.view.adapter.StatusListAdapter; +import net.lacolaco.smileessence.viewmodel.StatusViewModel; + +import twitter4j.Paging; +import twitter4j.Twitter; + +public class MentionsFragment extends CustomListFragment { + + // --------------------- GETTER / SETTER METHODS --------------------- + + @Override + protected PullToRefreshBase.Mode getRefreshMode() { + return PullToRefreshBase.Mode.BOTH; + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnRefreshListener2 --------------------- + + @Override + public void onPullDownToRefresh(final PullToRefreshBase<ListView> refreshView) { + final MainActivity activity = (MainActivity) getActivity(); + final Account currentAccount = activity.getCurrentAccount(); + Twitter twitter = TwitterApi.getTwitter(currentAccount); + final StatusListAdapter adapter = getListAdapter(activity); + Paging paging = TwitterUtils.getPaging(TwitterUtils.getPagingCount(activity)); + if (adapter.getCount() > 0) { + paging.setSinceId(adapter.getTopID()); + } + new MentionsTimelineTask(twitter, activity, paging) { + @Override + protected void onPostExecute(twitter4j.Status[] statuses) { + super.onPostExecute(statuses); + for (int i = statuses.length - 1; i >= 0; i--) { + twitter4j.Status status = statuses[i]; + adapter.addToTop(new StatusViewModel(status, currentAccount)); + } + updateListViewWithNotice(refreshView.getRefreshableView(), adapter, true); + refreshView.onRefreshComplete(); + } + }.execute(); + } + + @Override + public void onPullUpToRefresh(final PullToRefreshBase<ListView> refreshView) { + final MainActivity activity = (MainActivity) getActivity(); + final Account currentAccount = activity.getCurrentAccount(); + Twitter twitter = TwitterApi.getTwitter(currentAccount); + final StatusListAdapter adapter = getListAdapter(activity); + Paging paging = TwitterUtils.getPaging(TwitterUtils.getPagingCount(activity)); + if (adapter.getCount() > 0) { + paging.setMaxId(adapter.getLastID() - 1); + } + new MentionsTimelineTask(twitter, activity, paging) { + @Override + protected void onPostExecute(twitter4j.Status[] statuses) { + super.onPostExecute(statuses); + for (twitter4j.Status status : statuses) { + adapter.addToBottom(new StatusViewModel(status, currentAccount)); + } + updateListViewWithNotice(refreshView.getRefreshableView(), adapter, false); + refreshView.onRefreshComplete(); + } + }.execute(); + } + + private StatusListAdapter getListAdapter(MainActivity activity) { + return (StatusListAdapter) activity.getListAdapter(MainActivity.ADAPTER_MENTIONS); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/MessagesFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/MessagesFragment.java new file mode 100644 index 00000000..eccea631 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/MessagesFragment.java @@ -0,0 +1,109 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view; + +import android.widget.ListView; + +import com.handmark.pulltorefresh.library.PullToRefreshBase; + +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.twitter.TwitterApi; +import net.lacolaco.smileessence.twitter.task.DirectMessagesTask; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.view.adapter.MessageListAdapter; +import net.lacolaco.smileessence.viewmodel.MessageViewModel; + +import twitter4j.DirectMessage; +import twitter4j.Paging; +import twitter4j.Twitter; + +/** + * Fragment of messages list + */ +public class MessagesFragment extends CustomListFragment { + + // --------------------- GETTER / SETTER METHODS --------------------- + + @Override + protected PullToRefreshBase.Mode getRefreshMode() { + return PullToRefreshBase.Mode.BOTH; + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnRefreshListener2 --------------------- + + @Override + public void onPullDownToRefresh(final PullToRefreshBase<ListView> refreshView) { + final MainActivity activity = (MainActivity) getActivity(); + final Account currentAccount = activity.getCurrentAccount(); + Twitter twitter = TwitterApi.getTwitter(currentAccount); + final MessageListAdapter adapter = getListAdapter(activity); + Paging paging = TwitterUtils.getPaging(TwitterUtils.getPagingCount(activity)); + if (adapter.getCount() > 0) { + paging.setSinceId(adapter.getTopID()); + } + new DirectMessagesTask(twitter, activity, paging) { + @Override + protected void onPostExecute(DirectMessage[] directMessages) { + super.onPostExecute(directMessages); + for (int i = directMessages.length - 1; i >= 0; i--) { + adapter.addToTop(new MessageViewModel(directMessages[i], currentAccount)); + } + updateListViewWithNotice(refreshView.getRefreshableView(), adapter, true); + refreshView.onRefreshComplete(); + } + }.execute(); + } + + @Override + public void onPullUpToRefresh(final PullToRefreshBase<ListView> refreshView) { + final MainActivity activity = (MainActivity) getActivity(); + final Account currentAccount = activity.getCurrentAccount(); + Twitter twitter = TwitterApi.getTwitter(currentAccount); + final MessageListAdapter adapter = getListAdapter(activity); + Paging paging = TwitterUtils.getPaging(TwitterUtils.getPagingCount(activity)); + if (adapter.getCount() > 0) { + paging.setMaxId(adapter.getLastID() - 1); + } + new DirectMessagesTask(twitter, activity, paging) { + @Override + protected void onPostExecute(DirectMessage[] directMessages) { + super.onPostExecute(directMessages); + for (DirectMessage directMessage : directMessages) { + adapter.addToBottom(new MessageViewModel(directMessage, currentAccount)); + } + updateListViewWithNotice(refreshView.getRefreshableView(), adapter, false); + refreshView.onRefreshComplete(); + } + }.execute(); + } + + private MessageListAdapter getListAdapter(MainActivity activity) { + return (MessageListAdapter) activity.getListAdapter(MainActivity.ADAPTER_MESSAGES); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/PostFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/PostFragment.java new file mode 100644 index 00000000..9c8a255b --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/PostFragment.java @@ -0,0 +1,388 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view; + +import android.app.Fragment; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.text.Editable; +import android.text.Spannable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.text.method.ArrowKeyMovementMethod; +import android.view.*; +import android.view.inputmethod.InputMethodManager; +import android.widget.*; + +import com.twitter.Validator; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.logging.Logger; +import net.lacolaco.smileessence.preference.UserPreferenceHelper; +import net.lacolaco.smileessence.twitter.TwitterApi; +import net.lacolaco.smileessence.twitter.task.TweetTask; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.util.BitmapThumbnailTask; +import net.lacolaco.smileessence.util.IntentUtils; +import net.lacolaco.smileessence.util.UIHandler; +import net.lacolaco.smileessence.view.adapter.PostState; +import net.lacolaco.smileessence.view.dialog.DialogHelper; +import net.lacolaco.smileessence.view.dialog.PostMenuDialogFragment; +import net.lacolaco.smileessence.view.dialog.SelectImageDialogFragment; +import net.lacolaco.smileessence.viewmodel.StatusViewModel; + +import twitter4j.Status; +import twitter4j.StatusUpdate; + +import java.io.File; + +public class PostFragment extends Fragment implements TextWatcher, View.OnFocusChangeListener, View.OnClickListener, + PostState.OnPostStateChangeListener { + + // ------------------------------ FIELDS ------------------------------ + + private EditText editText; + private TextView textViewCount; + private Button buttonTweet; + private ViewGroup viewGroupReply; + private ViewGroup viewGroupMedia; + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnClickListener --------------------- + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.button_post_delete: { + deletePost(); + break; + } + case R.id.button_post_media: { + setImage(); + break; + } + case R.id.button_post_menu: { + openPostMenu(); + break; + } + case R.id.button_post_tweet: { + submitPost(); + break; + } + case R.id.button_post_reply_delete: { + deleteReply(); + break; + } + case R.id.button_post_media_delete: { + removeImage(); + break; + } + case R.id.image_post_media: { + displayImage(); + break; + } + } + } + + // --------------------- Interface OnFocusChangeListener --------------------- + + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (hasFocus) { + showIME(); + } else { + hideIME(); + } + } + + // --------------------- Interface OnPostStateChangeListener --------------------- + + + @Override + public void onPostStateChange(final PostState postState) { + Logger.debug("PostFragment PostStateChange"); + final MainActivity activity = (MainActivity) getActivity(); + if (editText != null) { + final int start = postState.getSelectionStart(); + final int end = postState.getSelectionEnd(); + editText.removeTextChangedListener(this); + editText.setTextKeepState(postState.getText()); + editText.addTextChangedListener(this); + updateTextCount(editText.getText()); + new UIHandler() { + @Override + public void run() { + editText.setSelection(start, end); + } + }.postAtFrontOfQueue(); + } + if (viewGroupReply != null) { + if (postState.getInReplyToStatusID() >= 0) { + viewGroupReply.setVisibility(View.VISIBLE); + final Account account = activity.getCurrentAccount(); + TwitterUtils.tryGetStatus(account, postState.getInReplyToStatusID(), new TwitterUtils.StatusCallback() { + @Override + public void success(Status status) { + View header = viewGroupReply.findViewById(R.id.layout_post_reply_status); + header = new StatusViewModel(status, account).getView(activity, activity.getLayoutInflater(), header); + header.setBackgroundColor(getResources().getColor(R.color.transparent)); + header.setClickable(false); + } + + @Override + public void error() { + viewGroupReply.setVisibility(View.GONE); + } + }); + ImageButton imageButtonDeleteReply = (ImageButton) viewGroupReply.findViewById(R.id.button_post_reply_delete); + imageButtonDeleteReply.setOnClickListener(this); + } else { + viewGroupReply.setVisibility(View.GONE); + } + } + if (viewGroupMedia != null) { + ImageView imageViewMedia = (ImageView) viewGroupMedia.findViewById(R.id.image_post_media); + if (TextUtils.isEmpty(postState.getMediaFilePath())) { + viewGroupMedia.setVisibility(View.GONE); + } else { + viewGroupMedia.setVisibility(View.VISIBLE); + + } + new BitmapThumbnailTask(activity, postState.getMediaFilePath(), imageViewMedia).execute(); + } + } + + // --------------------- Interface TextWatcher --------------------- + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + updateTextCount(s); + } + + public void updateTextCount(CharSequence s) { + int remainingCount = 140 - TwitterUtils.getFixedTextLength(s.toString()); + if (!TextUtils.isEmpty(PostState.getState().getMediaFilePath())) { + remainingCount -= new Validator().getShortUrlLength(); + } + textViewCount.setText(String.valueOf(remainingCount)); + if (remainingCount == 140) { + textViewCount.setTextColor(getResources().getColor(R.color.red)); + buttonTweet.setEnabled(false); + } else if (remainingCount < 0) { + textViewCount.setTextColor(getResources().getColor(R.color.red)); + buttonTweet.setEnabled(false); + } else { + textViewCount.setTextAppearance(getActivity(), android.R.style.TextAppearance_Widget_TextView); + buttonTweet.setEnabled(true); + } + setStateFromView(); + } + + @Override + public void afterTextChanged(Editable s) { + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public void onCreate(Bundle savedInstanceState) { + Logger.debug("PostFragment Create"); + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + menu.removeItem(R.id.actionbar_post); + showIME(); + } + + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + Logger.debug("PostFragment CreateView"); + MainActivity activity = (MainActivity) getActivity(); + PostState.getState().setListener(this); + UserPreferenceHelper preferenceHelper = new UserPreferenceHelper(activity); + View v = inflater.inflate(R.layout.fragment_post, null); + buttonTweet = getTweetButton(v); + buttonTweet.setOnClickListener(this); + editText = getEditText(v); + textViewCount = getCountTextView(v); + int textSize = preferenceHelper.getValue(R.string.key_setting_text_size, 10); + editText.addTextChangedListener(this); + editText.setOnFocusChangeListener(this); + editText.setTextSize(textSize + 4); + editText.setMovementMethod(new ArrowKeyMovementMethod() { + @Override + protected boolean right(TextView widget, Spannable buffer) { + //Don't back to Home + return widget.getSelectionEnd() == widget.length() || super.right(widget, buffer); + } + }); + ImageButton imageButtonDeleteText = (ImageButton) v.findViewById(R.id.button_post_delete); + imageButtonDeleteText.setOnClickListener(this); + ImageButton imageButtonMedia = (ImageButton) v.findViewById(R.id.button_post_media); + imageButtonMedia.setOnClickListener(this); + ImageButton imageButtonMenu = (ImageButton) v.findViewById(R.id.button_post_menu); + imageButtonMenu.setOnClickListener(this); + //Reply view + viewGroupReply = getReplyViewGroup(v); + ImageButton imageButtonDeleteReply = (ImageButton) viewGroupReply.findViewById(R.id.button_post_reply_delete); + imageButtonDeleteReply.setOnClickListener(this); + //Media view + viewGroupMedia = getMediaViewGroup(v); + ImageView imageViewMedia = (ImageView) viewGroupMedia.findViewById(R.id.image_post_media); + ImageButton imageButtonDeleteMedia = (ImageButton) viewGroupMedia.findViewById(R.id.button_post_media_delete); + imageViewMedia.setOnClickListener(this); + imageButtonDeleteMedia.setOnClickListener(this); + editText.requestFocus(); + return v; + } + + @Override + public void onDestroyView() { + Logger.debug("PostFragment DestroyView"); + super.onDestroyView(); + setStateFromView(); + PostState.getState().removeListener(); + } + + @Override + public void onViewStateRestored(Bundle savedInstanceState) { + Logger.debug("PostFragment ViewStateRestored"); + super.onViewStateRestored(savedInstanceState); + PostState state = PostState.getState(); + onPostStateChange(state); + } + + private void deletePost() { + editText.setText(""); + PostState.getState().beginTransaction().setText("").setCursor(0).commit(); + deleteReply(); + } + + private void deleteReply() { + viewGroupReply.setVisibility(View.GONE); + PostState.getState().beginTransaction().setInReplyToStatusID(-1).commit(); + } + + private void displayImage() { + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_VIEW); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setDataAndType(Uri.fromFile(new File(PostState.getState().getMediaFilePath())), "image/*"); + IntentUtils.startActivityIfFound(getActivity(), intent); + } + + private TextView getCountTextView(View v) { + return (TextView) v.findViewById(R.id.post_text_count); + } + + private EditText getEditText(View v) { + return (EditText) v.findViewById(R.id.post_edit_text); + } + + private ViewGroup getMediaViewGroup(View v) { + return (ViewGroup) v.findViewById(R.id.post_media_parent); + } + + private ViewGroup getReplyViewGroup(View v) { + return (ViewGroup) v.findViewById(R.id.post_inreplyto_parent); + } + + private Button getTweetButton(View v) { + return (Button) v.findViewById(R.id.button_post_tweet); + } + + private void hideIME() { + InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + + private void openPostMenu() { + setStateFromView(); + hideIME(); + PostMenuDialogFragment menuDialogFragment = new PostMenuDialogFragment(); + DialogHelper.showDialog(getActivity(), menuDialogFragment, PostMenuDialogFragment.TAG); + } + + private void removeImage() { + hideIME(); + viewGroupMedia.setVisibility(View.GONE); + ((ImageView) viewGroupMedia.findViewById(R.id.image_post_media)).setImageBitmap(null); + PostState.getState().beginTransaction().setMediaFilePath("").commit(); + } + + private void setImage() { + setStateFromView(); + hideIME(); + SelectImageDialogFragment selectImageDialogFragment = new SelectImageDialogFragment(); + DialogHelper.showDialog(getActivity(), selectImageDialogFragment); + } + + private void setStateFromView() { + PostState state = PostState.getState(); + state.removeListener(); + state.beginTransaction() + .setText(editText.getText().toString()) + .setSelection(editText.getSelectionStart(), editText.getSelectionEnd()) + .commit(); + state.setListener(this); + } + + private void showIME() { + if (editText != null) { + new UIHandler() { + @Override + public void run() { + InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(editText, 0); + } + }.postDelayed(100); + } + } + + private void submitPost() { + hideIME(); + setStateFromView(); + PostState state = PostState.getState(); + StatusUpdate statusUpdate = state.toStatusUpdate(); + MainActivity mainActivity = (MainActivity) getActivity(); + TweetTask tweetTask = new TweetTask(TwitterApi.getTwitter(mainActivity.getCurrentAccount()), statusUpdate, state.getMediaFilePath(), mainActivity); + tweetTask.execute(); + PostState.newState().beginTransaction().commit(); + mainActivity.setSelectedPageIndex(MainActivity.ADAPTER_HOME); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/SearchFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/SearchFragment.java new file mode 100644 index 00000000..4da3fd46 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/SearchFragment.java @@ -0,0 +1,346 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view; + +import android.content.Context; +import android.os.Bundle; +import android.text.Spannable; +import android.text.TextUtils; +import android.text.method.ArrowKeyMovementMethod; +import android.view.*; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.ListView; +import android.widget.TextView; + +import com.handmark.pulltorefresh.library.PullToRefreshBase; +import com.handmark.pulltorefresh.library.PullToRefreshListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.command.Command; +import net.lacolaco.smileessence.command.CommandOpenSearch; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.entity.SearchQuery; +import net.lacolaco.smileessence.notification.NotificationType; +import net.lacolaco.smileessence.notification.Notificator; +import net.lacolaco.smileessence.twitter.StatusFilter; +import net.lacolaco.smileessence.twitter.TwitterApi; +import net.lacolaco.smileessence.twitter.task.SearchTask; +import net.lacolaco.smileessence.util.UIHandler; +import net.lacolaco.smileessence.view.adapter.SearchListAdapter; +import net.lacolaco.smileessence.view.dialog.DialogHelper; +import net.lacolaco.smileessence.view.dialog.SelectSearchQueryDialogFragment; +import net.lacolaco.smileessence.viewmodel.StatusViewModel; + +import twitter4j.Query; +import twitter4j.QueryResult; +import twitter4j.Twitter; + +import java.util.List; + +public class SearchFragment extends CustomListFragment implements View.OnClickListener, View.OnFocusChangeListener, + SearchListAdapter.OnQueryChangeListener { + + // ------------------------------ FIELDS ------------------------------ + + public static final String SEARCH_QUERY_DIALOG = "searchQueryDialog"; + private EditText editText; + + // --------------------- GETTER / SETTER METHODS --------------------- + + private int getAdapterIndex() { + return getArguments().getInt(ADAPTER_INDEX); + } + + private MainActivity getMainActivity() { + return (MainActivity) getActivity(); + } + + @Override + protected PullToRefreshBase.Mode getRefreshMode() { + return PullToRefreshBase.Mode.BOTH; + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnClickListener --------------------- + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.button_search_queries: { + openSearchQueryDialog(getMainActivity()); + break; + } + case R.id.button_search_execute: { + search(); + break; + } + case R.id.button_search_save: { + saveQuery(); + } + } + } + + // --------------------- Interface OnFocusChangeListener --------------------- + + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (!hasFocus) { + hideIME(); + } + } + + // --------------------- Interface OnQueryChangeListener --------------------- + + @Override + public void onQueryChange(String newQuery) { + if (editText != null) { + editText.setText(newQuery); + } + } + + // --------------------- Interface OnRefreshListener2 --------------------- + + @Override + public void onPullDownToRefresh(final PullToRefreshBase<ListView> refreshView) { + final MainActivity activity = getMainActivity(); + final Account currentAccount = activity.getCurrentAccount(); + Twitter twitter = TwitterApi.getTwitter(currentAccount); + final SearchListAdapter adapter = getListAdapter(activity); + String queryString = adapter.getQuery(); + if (TextUtils.isEmpty(queryString)) { + new UIHandler() { + @Override + public void run() { + notifyTextEmpty(activity); + refreshView.onRefreshComplete(); + } + }.post(); + return; + } + final Query query = SearchTask.getBaseQuery(activity, queryString); + if (adapter.getCount() > 0) { + query.setSinceId(adapter.getTopID()); + } + new SearchTask(twitter, query, activity) { + @Override + protected void onPostExecute(QueryResult queryResult) { + super.onPostExecute(queryResult); + if (queryResult != null) { + List<twitter4j.Status> tweets = queryResult.getTweets(); + for (int i = tweets.size() - 1; i >= 0; i--) { + twitter4j.Status status = tweets.get(i); + if (!status.isRetweet()) { + StatusViewModel viewModel = new StatusViewModel(status, currentAccount); + adapter.addToTop(viewModel); + StatusFilter.filter(activity, viewModel); + } + } + updateListViewWithNotice(refreshView.getRefreshableView(), adapter, true); + adapter.setTopID(queryResult.getMaxId()); + refreshView.onRefreshComplete(); + } + } + }.execute(); + } + + @Override + public void onPullUpToRefresh(final PullToRefreshBase<ListView> refreshView) { + final MainActivity activity = getMainActivity(); + final Account currentAccount = activity.getCurrentAccount(); + Twitter twitter = TwitterApi.getTwitter(currentAccount); + final SearchListAdapter adapter = getListAdapter(activity); + String queryString = adapter.getQuery(); + if (TextUtils.isEmpty(queryString)) { + new UIHandler() { + @Override + public void run() { + notifyTextEmpty(activity); + refreshView.onRefreshComplete(); + } + }.post(); + return; + } + final Query query = SearchTask.getBaseQuery(activity, queryString); + if (adapter.getCount() > 0) { + query.setMaxId(adapter.getLastID() - 1); + } + new SearchTask(twitter, query, activity) { + @Override + protected void onPostExecute(QueryResult queryResult) { + super.onPostExecute(queryResult); + if (queryResult != null) { + List<twitter4j.Status> tweets = queryResult.getTweets(); + for (twitter4j.Status status : tweets) { + if (!status.isRetweet()) { + StatusViewModel viewModel = new StatusViewModel(status, currentAccount); + adapter.addToBottom(viewModel); + StatusFilter.filter(activity, viewModel); + } + } + updateListViewWithNotice(refreshView.getRefreshableView(), adapter, false); + refreshView.onRefreshComplete(); + } + } + }.execute(); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + protected PullToRefreshListView getListView(View page) { + return (PullToRefreshListView) page.findViewById(R.id.listview_search); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + menu.removeItem(R.id.actionbar_search); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View page = inflater.inflate(R.layout.fragment_search, container, false); + int fragmentIndex = getAdapterIndex(); + PullToRefreshListView listView = getListView(page); + SearchListAdapter adapter = (SearchListAdapter) getListAdapter(fragmentIndex); + listView.setAdapter(adapter); + listView.setOnScrollListener(this); + listView.setOnRefreshListener(this); + listView.setMode(getRefreshMode()); + ImageButton buttonQueries = getQueriesButton(page); + buttonQueries.setOnClickListener(this); + ImageButton buttonExecute = getExecuteButton(page); + buttonExecute.setOnClickListener(this); + ImageButton buttonSave = getSaveButton(page); + buttonSave.setOnClickListener(this); + editText = getEditText(page); + editText.setOnFocusChangeListener(this); + editText.setText(adapter.getQuery()); + editText.setMovementMethod(new ArrowKeyMovementMethod() { + @Override + protected boolean right(TextView widget, Spannable buffer) { + //Don't move page + return widget.getSelectionEnd() == widget.length() || super.right(widget, buffer); + } + + @Override + protected boolean left(TextView widget, Spannable buffer) { + //Don't move page + return widget.getSelectionStart() == 0 || super.left(widget, buffer); + } + }); + adapter.setOnQueryChangeListener(this); + return page; + } + + private EditText getEditText(View page) { + return (EditText) page.findViewById(R.id.edittext_search); + } + + private ImageButton getExecuteButton(View page) { + return (ImageButton) page.findViewById(R.id.button_search_execute); + } + + private SearchListAdapter getListAdapter(MainActivity activity) { + return (SearchListAdapter) activity.getListAdapter(MainActivity.ADAPTER_SEARCH); + } + + private ImageButton getQueriesButton(View page) { + return (ImageButton) page.findViewById(R.id.button_search_queries); + } + + private ImageButton getSaveButton(View page) { + return (ImageButton) page.findViewById(R.id.button_search_save); + } + + private void hideIME() { + InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + + private void notifyTextEmpty(MainActivity activity) { + Notificator.publish(activity, R.string.notice_search_text_empty); + } + + private void openSearchQueryDialog(final MainActivity mainActivity) { + if (SearchQuery.getAll().size() == 0) { + Notificator.publish(mainActivity, R.string.notice_no_query_exists); + return; + } + DialogHelper.showDialog(mainActivity, new SelectSearchQueryDialogFragment() { + @Override + protected void deleteQuery(CommandOpenSearch command) { + super.deleteQuery(command); + if (editText.getText().toString().contentEquals(command.getQuery().query)) { + editText.setText(""); + mainActivity.setLastSearch(""); + } else { + mainActivity.setLastSearch(editText.getText().toString()); + } + } + + @Override + protected void executeCommand(Command command) { + super.executeCommand(command); + SearchQuery query = ((CommandOpenSearch) command).getQuery(); + editText.setText(query.query); + hideIME(); + } + }, SEARCH_QUERY_DIALOG); + } + + private void saveQuery() { + String text = editText.getText().toString(); + if (TextUtils.isEmpty(text)) { + Notificator.publish(getMainActivity(), R.string.notice_query_is_empty, NotificationType.ALERT); + } else { + SearchQuery.saveIfNotFound(text); + Notificator.publish(getMainActivity(), R.string.notice_query_saved); + } + } + + private void search() { + if (editText != null) { + String text = editText.getText().toString(); + if (TextUtils.isEmpty(text)) { + Notificator.publish(getMainActivity(), R.string.notice_query_is_empty, NotificationType.ALERT); + } else { + getMainActivity().openSearchPage(text); + hideIME(); + } + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.java new file mode 100644 index 00000000..006a43ba --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.java @@ -0,0 +1,182 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.EditTextPreference; +import android.preference.ListPreference; +import android.preference.Preference; +import android.preference.PreferenceFragment; +import android.text.TextUtils; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.LicenseActivity; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.notification.Notificator; +import net.lacolaco.smileessence.preference.UserPreferenceHelper; +import net.lacolaco.smileessence.view.dialog.ConfirmDialogFragment; +import net.lacolaco.smileessence.view.dialog.DialogHelper; +import net.lacolaco.smileessence.view.dialog.SimpleDialogFragment; + +import static android.content.SharedPreferences.OnSharedPreferenceChangeListener; + +public class SettingFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener, + Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener { + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnPreferenceChangeListener --------------------- + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + String newValueStr = String.valueOf(newValue); + if (preference.getKey().contentEquals(getString(R.string.key_setting_text_size))) { + if (TextUtils.isDigitsOnly(newValueStr)) { + int newTextSize = Integer.parseInt(newValueStr); + if (UserPreferenceHelper.TEXT_SIZE_MIN <= newTextSize && newTextSize <= UserPreferenceHelper.TEXT_SIZE_MAX) { + return true; + } + Notificator.publish(getActivity(), R.string.error_setting_text_size_range); + } else { + Notificator.publish(getActivity(), R.string.error_setting_text_size_not_number); + } + return false; + } else if (preference.getKey().contentEquals(getString(R.string.key_setting_timelines))) { + if (TextUtils.isDigitsOnly(newValueStr)) { + int newTextSize = Integer.parseInt(newValueStr); + if (UserPreferenceHelper.TIMELINES_MIN <= newTextSize && newTextSize <= UserPreferenceHelper.TIMELINES_MAX) { + return true; + } + Notificator.publish(getActivity(), R.string.error_setting_timelines_range); + } else { + Notificator.publish(getActivity(), R.string.error_setting_timelines_not_number); + } + return false; + } else if (preference.getKey().contentEquals(getString(R.string.key_setting_theme))) { + Notificator.publish(getActivity(), R.string.notice_theme_changed); + } + return true; + } + + // --------------------- Interface OnPreferenceClickListener --------------------- + + @Override + public boolean onPreferenceClick(Preference preference) { + String key = preference.getKey(); + if (key.contentEquals(getString(R.string.key_setting_application_information))) { + SimpleDialogFragment informationDialog = SimpleDialogFragment.newInstance( + R.layout.dialog_app_info, + getString(R.string.dialog_title_about)); + DialogHelper.showDialog(getActivity(), informationDialog); + } else if (key.contentEquals(getString(R.string.key_setting_clear_account))) { + ConfirmDialogFragment.show(getActivity(), getString(R.string.dialog_confirm_clear_account), new Runnable() { + @Override + public void run() { + Notificator.publish(getActivity(), R.string.notice_cleared_account); + Account.deleteAll(); + finishActivity(); + } + }, false); + } else if (key.contentEquals(getString(R.string.key_setting_licenses))) { + openLicenseActivity(); + } + return true; + } + + // --------------------- Interface OnSharedPreferenceChangeListener --------------------- + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + setSummaryCurrentValue(); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.setting); + EditTextPreference textSizePreference = (EditTextPreference) findPreference(R.string.key_setting_text_size); + textSizePreference.setSummary(textSizePreference.getText()); + textSizePreference.setOnPreferenceChangeListener(this); + ListPreference themePreference = (ListPreference) findPreference(R.string.key_setting_theme); + themePreference.setSummary(themePreference.getEntry()); + themePreference.setOnPreferenceChangeListener(this); + ListPreference namestylePreference = (ListPreference) findPreference(R.string.key_setting_namestyle); + namestylePreference.setSummary(namestylePreference.getEntry()); + EditTextPreference timelinesPreference = (EditTextPreference) findPreference(R.string.key_setting_timelines); + timelinesPreference.setSummary(String.format(getString(R.string.setting_timelines_summary_format), timelinesPreference.getText())); + timelinesPreference.setOnPreferenceChangeListener(this); + Preference appInfoPreference = findPreference(R.string.key_setting_application_information); + appInfoPreference.setOnPreferenceClickListener(this); + Preference clearAccount = findPreference(R.string.key_setting_clear_account); + clearAccount.setOnPreferenceClickListener(this); + Preference license = findPreference(R.string.key_setting_licenses); + license.setOnPreferenceClickListener(this); + } + + @Override + public void onPause() { + super.onPause(); + SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences(); + sharedPreferences.unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onResume() { + super.onResume(); + SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences(); + sharedPreferences.registerOnSharedPreferenceChangeListener(this); + } + + // -------------------------- OTHER METHODS -------------------------- + + public Preference findPreference(int preferenceResID) { + return findPreference(getString(preferenceResID)); + } + + private void finishActivity() { + getActivity().finish(); + } + + private void openLicenseActivity() { + Intent intent = new Intent(getActivity(), LicenseActivity.class); + getActivity().startActivity(intent); + } + + private void setSummaryCurrentValue() { + EditTextPreference textSizePreference = (EditTextPreference) findPreference(R.string.key_setting_text_size); + textSizePreference.setSummary(textSizePreference.getText()); + ListPreference themePreference = (ListPreference) findPreference(R.string.key_setting_theme); + themePreference.setSummary(themePreference.getEntry()); + ListPreference namestylePreference = (ListPreference) findPreference(R.string.key_setting_namestyle); + namestylePreference.setSummary(namestylePreference.getEntry()); + EditTextPreference timelinesPreference = (EditTextPreference) findPreference(R.string.key_setting_timelines); + timelinesPreference.setSummary(String.format(getString(R.string.setting_timelines_summary_format), timelinesPreference.getText())); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/TextFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/TextFragment.java new file mode 100644 index 00000000..1293da28 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/TextFragment.java @@ -0,0 +1,55 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view; + +import android.app.Fragment; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +public class TextFragment extends Fragment { + + // ------------------------------ FIELDS ------------------------------ + + public static final String ARG_TEXT = "text"; + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + TextView textView = new TextView(getActivity()); + Bundle args = getArguments(); + if (args != null) { + String text = args.getString(ARG_TEXT); + if (!TextUtils.isEmpty(text)) { + textView.setText(text); + } + } + return textView; + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/UserListFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/UserListFragment.java new file mode 100644 index 00000000..6f8f1420 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/UserListFragment.java @@ -0,0 +1,214 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view; + +import android.content.DialogInterface; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; +import android.widget.ListView; +import android.widget.TextView; + +import com.handmark.pulltorefresh.library.PullToRefreshBase; +import com.handmark.pulltorefresh.library.PullToRefreshListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.notification.Notificator; +import net.lacolaco.smileessence.twitter.StatusFilter; +import net.lacolaco.smileessence.twitter.TwitterApi; +import net.lacolaco.smileessence.twitter.task.UserListStatusesTask; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.util.UIHandler; +import net.lacolaco.smileessence.view.dialog.DialogHelper; +import net.lacolaco.smileessence.view.dialog.SelectUserListDialogFragment; +import net.lacolaco.smileessence.viewmodel.StatusViewModel; +import net.lacolaco.smileessence.viewmodel.UserListListAdapter; + +import twitter4j.Paging; +import twitter4j.Twitter; + +public class UserListFragment extends CustomListFragment implements View.OnClickListener { + + // ------------------------------ FIELDS ------------------------------ + + private TextView textListName; + + // --------------------- GETTER / SETTER METHODS --------------------- + + private MainActivity getMainActivity() { + return (MainActivity) getActivity(); + } + + @Override + protected PullToRefreshBase.Mode getRefreshMode() { + return PullToRefreshBase.Mode.BOTH; + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnClickListener --------------------- + + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.button_userlist_lists: { + openUserListsDialog(getMainActivity()); + break; + } + } + } + + // --------------------- Interface OnRefreshListener2 --------------------- + + @Override + public void onPullDownToRefresh(final PullToRefreshBase<ListView> refreshView) { + final MainActivity activity = getMainActivity(); + final Account currentAccount = activity.getCurrentAccount(); + Twitter twitter = TwitterApi.getTwitter(currentAccount); + final UserListListAdapter adapter = getListAdapter(activity); + String listFullName = adapter.getListFullName(); + if (TextUtils.isEmpty(listFullName)) { + new UIHandler() { + @Override + public void run() { + notifyTextEmpty(activity); + refreshView.onRefreshComplete(); + } + }.post(); + return; + } + Paging paging = TwitterUtils.getPaging(TwitterUtils.getPagingCount(activity)); + if (adapter.getCount() > 0) { + paging.setSinceId(adapter.getTopID()); + } + new UserListStatusesTask(twitter, listFullName, activity, paging) { + @Override + protected void onPostExecute(twitter4j.Status[] statuses) { + super.onPostExecute(statuses); + for (int i = statuses.length - 1; i >= 0; i--) { + twitter4j.Status status = statuses[i]; + StatusViewModel statusViewModel = new StatusViewModel(status, activity.getCurrentAccount()); + adapter.addToTop(statusViewModel); + StatusFilter.filter(activity, statusViewModel); + } + updateListViewWithNotice(refreshView.getRefreshableView(), adapter, true); + refreshView.onRefreshComplete(); + } + }.execute(); + } + + @Override + public void onPullUpToRefresh(final PullToRefreshBase<ListView> refreshView) { + final MainActivity activity = getMainActivity(); + final Account currentAccount = activity.getCurrentAccount(); + Twitter twitter = TwitterApi.getTwitter(currentAccount); + final UserListListAdapter adapter = getListAdapter(activity); + String listFullName = adapter.getListFullName(); + if (TextUtils.isEmpty(listFullName)) { + new UIHandler() { + @Override + public void run() { + notifyTextEmpty(activity); + refreshView.onRefreshComplete(); + } + }.post(); + return; + } + Paging paging = TwitterUtils.getPaging(TwitterUtils.getPagingCount(activity)); + if (adapter.getCount() > 0) { + paging.setMaxId(adapter.getLastID() - 1); + } + new UserListStatusesTask(twitter, listFullName, activity, paging) { + @Override + protected void onPostExecute(twitter4j.Status[] statuses) { + super.onPostExecute(statuses); + for (int i = 0; i < statuses.length; i++) { + twitter4j.Status status = statuses[i]; + StatusViewModel statusViewModel = new StatusViewModel(status, activity.getCurrentAccount()); + adapter.addToBottom(statusViewModel); + StatusFilter.filter(activity, statusViewModel); + } + updateListViewWithNotice(refreshView.getRefreshableView(), adapter, false); + refreshView.onRefreshComplete(); + } + }.execute(); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + protected PullToRefreshListView getListView(View page) { + return (PullToRefreshListView) page.findViewById(R.id.listview_userlist); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View page = inflater.inflate(R.layout.fragment_userlist, container, false); + PullToRefreshListView listView = getListView(page); + UserListListAdapter adapter = getListAdapter((MainActivity) getActivity()); + listView.setAdapter(adapter); + listView.setOnScrollListener(this); + listView.setOnRefreshListener(this); + listView.setMode(getRefreshMode()); + ImageButton buttonUserLists = getUserListsButton(page); + buttonUserLists.setOnClickListener(this); + textListName = getTextListName(page); + textListName.setText(adapter.getListFullName()); + return page; + } + + private UserListListAdapter getListAdapter(MainActivity activity) { + return (UserListListAdapter) getListAdapter(MainActivity.ADAPTER_USERLIST); + } + + private TextView getTextListName(View page) { + return (TextView) page.findViewById(R.id.textview_userlist_name); + } + + private ImageButton getUserListsButton(View page) { + return (ImageButton) page.findViewById(R.id.button_userlist_lists); + } + + private void notifyTextEmpty(MainActivity activity) { + Notificator.publish(activity, R.string.notice_userlist_not_selected); + } + + private void openUserListsDialog(final MainActivity mainActivity) { + DialogHelper.showDialog(mainActivity, new SelectUserListDialogFragment() { + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + textListName.setText(getListAdapter(mainActivity).getListFullName()); + } + }); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.java b/app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.java new file mode 100644 index 00000000..69c893e5 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.java @@ -0,0 +1,178 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.adapter; + +import android.app.Activity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import com.google.common.collect.Iterables; + +import net.lacolaco.smileessence.util.UIHandler; +import net.lacolaco.smileessence.viewmodel.IViewModel; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class CustomListAdapter<T extends IViewModel> extends BaseAdapter { + + // ------------------------------ FIELDS ------------------------------ + + protected final Object LOCK = new Object(); + protected Class<T> clss; + protected ArrayList<T> list = new ArrayList<>(); + protected T[] array; + protected int count; + protected boolean isNotifiable = true; + protected Activity activity; + + // --------------------------- CONSTRUCTORS --------------------------- + + public CustomListAdapter(Activity activity, Class<T> clss) { + this.activity = activity; + this.clss = clss; + } + + // --------------------- GETTER / SETTER METHODS --------------------- + + public Activity getActivity() { + return activity; + } + + @Override + public int getCount() { + return count; + } + + public boolean isNotifiable() { + synchronized (LOCK) { + return isNotifiable; + } + } + + public void setNotifiable(boolean notifiable) { + synchronized (LOCK) { + isNotifiable = notifiable; + } + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface Adapter --------------------- + + @Override + public Object getItem(int position) { + return array[position]; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + return ((T) getItem(position)).getView(activity, activity.getLayoutInflater(), convertView); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public void notifyDataSetChanged() { + sort(); + array = Iterables.toArray(list, clss); + count = array.length; + super.notifyDataSetChanged(); + } + + // -------------------------- OTHER METHODS -------------------------- + + public void addToBottom(T... items) { + synchronized (LOCK) { + List<T> buffer = Arrays.asList(items); + for (T item : buffer) { + if (list.contains(item)) { + list.remove(item); + } + list.add(item); + } + } + } + + public void addToTop(T... items) { + synchronized (LOCK) { + List<T> buffer = Arrays.asList(items); + Collections.reverse(buffer); + for (T item : buffer) { + if (list.contains(item)) { + list.remove(item); + } + list.add(0, item); + } + } + } + + public void clear() { + synchronized (LOCK) { + list.clear(); + } + } + + public T removeItem(int position) { + synchronized (LOCK) { + return list.remove(position); + } + } + + public boolean removeItem(T item) { + synchronized (LOCK) { + return list.remove(item); + } + } + + public void sort() { + } + + public void update() { + if (isNotifiable) { + updateForce(); + } + } + + public void updateForce() { + synchronized (LOCK) { + new UIHandler() { + @Override + public void run() { + notifyDataSetChanged(); + } + }.post(); + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/EventListAdapter.java b/app/src/main/java/net/lacolaco/smileessence/view/adapter/EventListAdapter.java new file mode 100644 index 00000000..94762845 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/adapter/EventListAdapter.java @@ -0,0 +1,38 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.adapter; + +import android.app.Activity; + +import net.lacolaco.smileessence.viewmodel.EventViewModel; + +public class EventListAdapter extends CustomListAdapter<EventViewModel> { + + // --------------------------- CONSTRUCTORS --------------------------- + + public EventListAdapter(Activity activity) { + super(activity, EventViewModel.class); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/MessageListAdapter.java b/app/src/main/java/net/lacolaco/smileessence/view/adapter/MessageListAdapter.java new file mode 100644 index 00000000..7c6b992d --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/adapter/MessageListAdapter.java @@ -0,0 +1,107 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.adapter; + +import android.app.Activity; + +import net.lacolaco.smileessence.viewmodel.MessageViewModel; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; + +public class MessageListAdapter extends CustomListAdapter<MessageViewModel> { + + // --------------------------- CONSTRUCTORS --------------------------- + + public MessageListAdapter(Activity activity) { + super(activity, MessageViewModel.class); + } + + // --------------------- GETTER / SETTER METHODS --------------------- + + public long getLastID() { + return ((MessageViewModel) getItem(getCount() - 1)).getID(); + } + + public long getTopID() { + return ((MessageViewModel) getItem(0)).getID(); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public void addToBottom(MessageViewModel... items) { + for (MessageViewModel item : items) { + if (!preAdd(item)) { + continue; + } + super.addToBottom(items); + } + } + + @Override + public void addToTop(MessageViewModel... items) { + for (MessageViewModel item : items) { + if (!preAdd(item)) { + continue; + } + super.addToTop(items); + } + } + + @Override + public void sort() { + synchronized (LOCK) { + Collections.sort(list, new Comparator<MessageViewModel>() { + @Override + public int compare(MessageViewModel lhs, MessageViewModel rhs) { + return rhs.getCreatedAt().compareTo(lhs.getCreatedAt()); + } + }); + } + } + + // -------------------------- OTHER METHODS -------------------------- + + public MessageViewModel removeByMessageID(long messageID) { + synchronized (this.LOCK) { + Iterator<MessageViewModel> iterator = this.list.iterator(); + while (iterator.hasNext()) { + MessageViewModel message = iterator.next(); + if (message.getID() == messageID) { + iterator.remove(); + return message; + } + } + return null; + } + } + + private boolean preAdd(MessageViewModel item) { + removeByMessageID(item.getID()); + return true; + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.java b/app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.java new file mode 100644 index 00000000..7c6cab9a --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.java @@ -0,0 +1,186 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.adapter; + +import android.app.ActionBar; +import android.app.Fragment; +import android.os.Bundle; +import android.support.v13.app.FragmentStatePagerAdapter; +import android.support.v4.view.ViewPager; +import android.widget.ArrayAdapter; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.logging.Logger; + +import java.util.ArrayList; + +public class PageListAdapter extends FragmentStatePagerAdapter implements ViewPager.OnPageChangeListener, + ActionBar.OnNavigationListener { + + // ------------------------------ FIELDS ------------------------------ + + private final MainActivity context; + private final ActionBar actionBar; + private final ViewPager viewPager; + private final ArrayList<PageInfo> pages = new ArrayList<>(); + + // --------------------------- CONSTRUCTORS --------------------------- + + public PageListAdapter(MainActivity activity, ViewPager viewPager) { + super(activity.getFragmentManager()); + this.context = activity; + this.actionBar = activity.getActionBar(); + this.viewPager = viewPager; + viewPager.setAdapter(this); + viewPager.setOnPageChangeListener(this); + } + + // --------------------- GETTER / SETTER METHODS --------------------- + + @Override + public synchronized int getCount() { + return pages.size(); + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnNavigationListener --------------------- + + @Override + public synchronized boolean onNavigationItemSelected(int itemPosition, long itemId) { + viewPager.setCurrentItem(itemPosition, true); + return true; + } + + // --------------------- Interface OnPageChangeListener --------------------- + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + } + + @Override + public synchronized void onPageSelected(int position) { + //Synchronize pager and navigation. + Logger.debug(String.format("Page selected:%d", position)); + actionBar.setSelectedNavigationItem(position); + } + + @Override + public void onPageScrollStateChanged(int state) { + } + + // -------------------------- OTHER METHODS -------------------------- + + /** + * Add new tab and new page + * + * @param name Page name + * @param clss Fragment class + * @param args Bundle for Fragment instantiate + * @return True if adding is complete successfully + */ + public synchronized boolean addPage(String name, Class<? extends Fragment> clss, Bundle args) { + if (addPageWithoutNotify(name, clss, args)) { + refreshListNavigation(); + return true; + } + return false; + } + + /** + * Add new tab and new page without notify. + * You must call notifyDataSetChanged after adding tab. + * + * @param name Page name + * @param clss Fragment class + * @param args Bundle for Fragment instantiate + * @return True if adding is complete successfully + */ + public synchronized boolean addPageWithoutNotify(String name, Class<? extends Fragment> clss, Bundle args) { + PageInfo info = new PageInfo(name, clss, args); + return pages.add(info); + } + + @Override + public synchronized Fragment getItem(int position) { + PageInfo info = pages.get(position); + return Fragment.instantiate(context, info.fragmentClass.getName(), info.args); + } + + public synchronized PageInfo getPage(int position) { + return pages.get(position); + } + + public synchronized void refreshListNavigation() { + ArrayList<String> itemList = new ArrayList<>(); + for (PageInfo page : pages) { + itemList.add(page.name); + } + ArrayAdapter<String> adapter = new ArrayAdapter<>(context, R.layout.navigation_list_item, R.id.navigation_list_item_text, itemList); + actionBar.setListNavigationCallbacks(adapter, this); + notifyDataSetChanged(); + } + + public synchronized boolean removePage(int position) { + if (removePageWithoutNotify(position)) { + refreshListNavigation(); + return true; + } + return false; + } + + private synchronized boolean removePageWithoutNotify(int position) { + return pages.remove(position) != null; + } + + // -------------------------- INNER CLASSES -------------------------- + + public static final class PageInfo { + + private final String name; + private final Class<? extends Fragment> fragmentClass; + private final Bundle args; + + PageInfo(String name, Class<? extends Fragment> clss, Bundle args) { + this.name = name; + this.fragmentClass = clss; + this.args = args; + } + + public String getName() { + return name; + } + + public Class<? extends Fragment> getFragmentClass() { + return fragmentClass; + } + + public Bundle getArgs() { + return args; + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/PostState.java b/app/src/main/java/net/lacolaco/smileessence/view/adapter/PostState.java new file mode 100644 index 00000000..c3810408 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/adapter/PostState.java @@ -0,0 +1,202 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.adapter; + +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.view.dialog.DialogHelper; + +import twitter4j.StatusUpdate; + +public class PostState { + + // ------------------------------ FIELDS ------------------------------ + + private static PostState instance = new PostState(); + private String text = ""; + private long inReplyToStatusID = -1L; + private String inReplyToScreenName = ""; + private String inReplyToText = ""; + private String mediaFilePath = ""; + private boolean directMessage = false; + private OnPostStateChangeListener listener; + private int selectionStart = 0; + private int selectionEnd = 0; + + // -------------------------- STATIC METHODS -------------------------- + + private PostState() { + } + + public static PostState getState() { + return instance; + } + + // --------------------------- CONSTRUCTORS --------------------------- + + public static PostState newState() { + return instance = new PostState().setListener(instance.listener); + } + + // --------------------- GETTER / SETTER METHODS --------------------- + + public long getInReplyToStatusID() { + return inReplyToStatusID; + } + + public String getMediaFilePath() { + return mediaFilePath; + } + + public int getSelectionEnd() { + if (selectionEnd < 0) { + return text.length(); + } + return selectionEnd; + } + + public int getSelectionStart() { + if (selectionStart < 0) { + return text.length(); + } + return selectionStart; + } + + public String getText() { + return text; + } + + public PostState setListener(OnPostStateChangeListener listener) { + this.listener = listener; + return this; + } + + // -------------------------- OTHER METHODS -------------------------- + + public PostStateTransaction beginTransaction() { + return new PostStateTransaction(this); + } + + public void removeListener() { + this.listener = null; + } + + /** + * Convert to StatusUpdate for tweet. + * + * @return StatusUpdate + */ + public StatusUpdate toStatusUpdate() { + return new StatusUpdate(getText()) + .inReplyToStatusId(getInReplyToStatusID()); + } + + private PostState copy(PostState another) { + this.text = another.text; + this.inReplyToStatusID = another.inReplyToStatusID; + this.inReplyToScreenName = another.inReplyToScreenName; + this.inReplyToText = another.inReplyToText; + this.mediaFilePath = another.mediaFilePath; + this.directMessage = another.directMessage; + this.selectionStart = another.selectionStart; + this.selectionEnd = another.selectionEnd; + this.listener = another.listener; + return this; + } + + private void postStateChange() { + if (listener != null) { + listener.onPostStateChange(this); + } + } + + // -------------------------- INNER CLASSES -------------------------- + + public static interface OnPostStateChangeListener { + + void onPostStateChange(PostState postState); + } + + public static class PostStateTransaction { + + private PostState state; + + private PostStateTransaction(PostState state) { + this.state = new PostState().copy(state); + } + + public PostStateTransaction setText(String text) { + state.text = text; + return this; + } + + public PostStateTransaction appendText(String text) { + state.text = state.text + text; + return this; + } + + public PostStateTransaction insertText(int index, String text) { + StringBuilder builder = new StringBuilder(state.text); + builder.insert(index, text); + state.text = builder.toString(); + return this; + } + + public PostStateTransaction setInReplyToStatusID(long inReplyToStatusID) { + state.inReplyToStatusID = inReplyToStatusID; + return this; + } + + public PostStateTransaction setMediaFilePath(String mediaFilePath) { + state.mediaFilePath = mediaFilePath; + return this; + } + + public PostStateTransaction setCursor(int cursor) { + state.selectionStart = state.selectionEnd = cursor; + return this; + } + + public PostStateTransaction setSelection(int start, int end) { + state.selectionStart = start; + state.selectionEnd = end; + return this; + } + + public void commit() { + PostState.getState().copy(state).postStateChange(); + } + + public void commitWithOpen(MainActivity activity) { + DialogHelper.closeAll(activity); + PostState.getState().copy(state).postStateChange(); + activity.openPostPage(); + } + + public PostStateTransaction moveCursor(int length) { + int cursor = state.selectionEnd + length; + return setCursor(cursor); + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/SearchListAdapter.java b/app/src/main/java/net/lacolaco/smileessence/view/adapter/SearchListAdapter.java new file mode 100644 index 00000000..20a5971a --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/adapter/SearchListAdapter.java @@ -0,0 +1,83 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.adapter; + +import android.app.Activity; + +public class SearchListAdapter extends StatusListAdapter { + + // ------------------------------ FIELDS ------------------------------ + + private long topID; + private String query; + private OnQueryChangeListener listener; + + // --------------------------- CONSTRUCTORS --------------------------- + + public SearchListAdapter(Activity activity) { + super(activity); + } + + // --------------------- GETTER / SETTER METHODS --------------------- + + public OnQueryChangeListener getListener() { + return listener; + } + + public String getQuery() { + return query; + } + + @Override + public long getTopID() { + return topID; + } + + public void setTopID(long topID) { + this.topID = topID; + } + + public void setOnQueryChangeListener(OnQueryChangeListener listener) { + this.listener = listener; + } + + // -------------------------- OTHER METHODS -------------------------- + + public void initSearch(String query) { + this.query = query; + topID = 0; + if (listener != null) { + listener.onQueryChange(query); + } + } + + // -------------------------- INNER CLASSES -------------------------- + + public static interface OnQueryChangeListener { + + void onQueryChange(String newQuery); + } + +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/StatusListAdapter.java b/app/src/main/java/net/lacolaco/smileessence/view/adapter/StatusListAdapter.java new file mode 100644 index 00000000..80c60b94 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/adapter/StatusListAdapter.java @@ -0,0 +1,113 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.adapter; + +import android.app.Activity; + +import net.lacolaco.smileessence.data.UserCache; +import net.lacolaco.smileessence.viewmodel.StatusViewModel; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; + +public class StatusListAdapter extends CustomListAdapter<StatusViewModel> { + + // --------------------------- CONSTRUCTORS --------------------------- + + public StatusListAdapter(Activity activity) { + super(activity, StatusViewModel.class); + } + + // --------------------- GETTER / SETTER METHODS --------------------- + + public long getLastID() { + return ((StatusViewModel) getItem(getCount() - 1)).getID(); + } + + public long getTopID() { + return ((StatusViewModel) getItem(0)).getID(); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public void addToBottom(StatusViewModel... items) { + for (StatusViewModel item : items) { + if (!preAdd(item)) { + continue; + } + super.addToBottom(item); + } + } + + @Override + public void addToTop(StatusViewModel... items) { + for (StatusViewModel item : items) { + if (!preAdd(item)) { + continue; + } + super.addToTop(item); + } + } + + /** + * Sort list by Status#createdAt + */ + @Override + public void sort() { + synchronized (LOCK) { + Collections.sort(list, new Comparator<StatusViewModel>() { + @Override + public int compare(StatusViewModel lhs, StatusViewModel rhs) { + return Long.valueOf(rhs.getID()).compareTo(lhs.getID()); + } + }); + } + } + + // -------------------------- OTHER METHODS -------------------------- + + public void removeByStatusID(long statusID) { + synchronized (this.LOCK) { + Iterator<StatusViewModel> iterator = this.list.iterator(); + while (iterator.hasNext()) { + StatusViewModel statusViewModel = iterator.next(); + if (statusViewModel.getID() == statusID || statusViewModel.getOriginal().getID() == statusID) { + iterator.remove(); + } + } + } + } + + private boolean isBlockUser(StatusViewModel item) { + return UserCache.getInstance().isInvisibleUserID(item.getOriginalUserID()); + } + + private boolean preAdd(StatusViewModel item) { + removeByStatusID(item.getID()); + return !isBlockUser(item); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/ChooseTemplateDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/ChooseTemplateDialogFragment.java new file mode 100644 index 00000000..425e95c7 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/ChooseTemplateDialogFragment.java @@ -0,0 +1,80 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.os.Bundle; +import android.view.View; +import android.widget.ListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.command.Command; +import net.lacolaco.smileessence.command.post.PostCommandUseTemplate; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.entity.Template; +import net.lacolaco.smileessence.view.adapter.CustomListAdapter; + +import java.util.ArrayList; +import java.util.List; + +public class ChooseTemplateDialogFragment extends MenuDialogFragment { + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + MainActivity activity = (MainActivity) getActivity(); + Account account = activity.getCurrentAccount(); + List<Command> commands = getCommands(activity); + View body = activity.getLayoutInflater().inflate(R.layout.dialog_menu_list, null); + ListView listView = (ListView) body.findViewById(R.id.listview_dialog_menu_list); + CustomListAdapter<Command> adapter = new CustomListAdapter<>(activity, Command.class); + listView.setAdapter(adapter); + for (Command command : commands) { + adapter.addToBottom(command); + } + adapter.update(); + listView.setOnItemClickListener(onItemClickListener); + + return new AlertDialog.Builder(activity) + .setView(body) + .setCancelable(true) + .create(); + } + + // -------------------------- OTHER METHODS -------------------------- + + public List<Command> getCommands(Activity activity) { + ArrayList<Command> list = new ArrayList<>(); + List<Template> templates = Template.getAll(); + for (Template template : templates) { + list.add(new PostCommandUseTemplate(activity, template)); + } + return list; + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/ConfirmDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/ConfirmDialogFragment.java new file mode 100644 index 00000000..ec9c512a --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/ConfirmDialogFragment.java @@ -0,0 +1,125 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.preference.UserPreferenceHelper; + +public abstract class ConfirmDialogFragment extends DialogFragment { + + // ------------------------------ FIELDS ------------------------------ + + public static final String ARG_TEXT = "text"; + public static final String TAG = "confirmDialog"; + private final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + onButtonClick(which); + dialog.dismiss(); + } + }; + private int layoutResourceID; + private String text; + + // -------------------------- STATIC METHODS -------------------------- + + public static void show(Activity activity, String text, final Runnable onYes) { + show(activity, text, onYes, null, true); + } + + public static void show(Activity activity, String text, final Runnable onYes, boolean ignorable) { + show(activity, text, onYes, null, ignorable); + } + + public static void show(Activity activity, String text, final Runnable onOK, final Runnable onCancel, boolean ignorable) { + boolean confirm = new UserPreferenceHelper(activity).getValue(R.string.key_setting_show_confirm_dialog, true); + if (!confirm && ignorable) { + onOK.run(); + return; + } + final ConfirmDialogFragment fragment = new ConfirmDialogFragment() { + @Override + public void onButtonClick(int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: { + if (onOK != null) { + this.dismiss(); + onOK.run(); + } + break; + } + case DialogInterface.BUTTON_NEGATIVE: { + if (onCancel != null) { + this.dismiss(); + onCancel.run(); + } + break; + } + } + } + }; + fragment.setText(text); + DialogHelper.showDialog(activity, fragment, TAG); + } + + // --------------------- GETTER / SETTER METHODS --------------------- + + public void setText(String text) { + Bundle args = new Bundle(); + args.putString(ARG_TEXT, text); + setArguments(args); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Bundle args = getArguments(); + if (args != null) { + text = args.getString(ARG_TEXT); + } + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new AlertDialog.Builder(getActivity()).setTitle(text) + .setCancelable(false) + .setPositiveButton(R.string.alert_dialog_ok, listener) + .setNegativeButton(R.string.alert_dialog_cancel, listener) + .create(); + } + + // -------------------------- OTHER METHODS -------------------------- + + public abstract void onButtonClick(int which); +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/DialogHelper.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/DialogHelper.java new file mode 100644 index 00000000..20e229e2 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/DialogHelper.java @@ -0,0 +1,97 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.Activity; +import android.app.DialogFragment; +import android.app.FragmentTransaction; + +import java.util.Stack; + +public class DialogHelper { + + // ------------------------------ FIELDS ------------------------------ + + private static final String TAG_DIALOG = "dialog"; + + private static Stack<String> dialogStack = new Stack<>(); + private final Activity activity; + private final DialogFragment dialogFragment; + + // -------------------------- STATIC METHODS -------------------------- + + public DialogHelper(Activity activity, DialogFragment dialogFragment) { + this.activity = activity; + this.dialogFragment = dialogFragment; + } + + public static void closeDialog(Activity activity) { + close(activity, TAG_DIALOG); + } + + /** + * Close all stacked dialog + */ + public static void closeAll(Activity activity) { + while (dialogStack.size() > 0) { + String tag = dialogStack.pop(); + close(activity, tag); + } + } + + public static void showDialog(Activity activity, DialogFragment dialogFragment) { + showDialog(activity, dialogFragment, TAG_DIALOG); + } + + /** + * Please expressly closing + */ + public static void showDialog(Activity activity, DialogFragment dialogFragment, String tag) { + close(activity, tag); + dialogStack.push(tag); + dialogFragment.show(activity.getFragmentManager().beginTransaction(), tag); + } + + // --------------------------- CONSTRUCTORS --------------------------- + + public static void close(Activity activity, String tag) { + if (activity != null) { + FragmentTransaction transaction = activity.getFragmentManager().beginTransaction(); + DialogFragment oldDialog = (DialogFragment) activity.getFragmentManager().findFragmentByTag(tag); + if (oldDialog != null) { + transaction.remove(oldDialog); + // oldDialog.dismiss(); + } + // transaction.addToBackStack(null); + transaction.commit(); + } + } + + // -------------------------- OTHER METHODS -------------------------- + + public void show() { + showDialog(activity, dialogFragment); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/DisposeDialog.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/DisposeDialog.java new file mode 100644 index 00000000..1dbbf057 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/DisposeDialog.java @@ -0,0 +1,51 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.Dialog; +import android.content.Context; + +/** + * Dialog for dispose soon. + */ +public final class DisposeDialog extends Dialog { + + public DisposeDialog(Context context) { + super(context); + } + + public DisposeDialog(Context context, int theme) { + super(context, theme); + } + + protected DisposeDialog(Context context, boolean cancelable, OnCancelListener cancelListener) { + super(context, cancelable, cancelListener); + } + + @Override + public void show() { + dismiss(); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTextDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTextDialogFragment.java new file mode 100644 index 00000000..23211a8d --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTextDialogFragment.java @@ -0,0 +1,91 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; +import android.view.View; +import android.widget.EditText; + +import net.lacolaco.smileessence.R; + +public abstract class EditTextDialogFragment extends DialogFragment { + + // ------------------------------ FIELDS ------------------------------ + + private static String titleKey = "title"; + private static String textKey = "text"; + private String title; + private String text; + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Bundle args = getArguments(); + text = args.getString(textKey); + title = args.getString(titleKey); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + View view = getActivity().getLayoutInflater().inflate(R.layout.part_edittext, null); + final EditText editText = (EditText) view.findViewById(R.id.part_edittext); + editText.setText(text); + return new AlertDialog.Builder(getActivity()) + .setTitle(title) + .setView(view) + .setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + onTextInput(editText.getText().toString()); + dialog.dismiss(); + } + }) + .setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }) + .create(); + } + + // -------------------------- OTHER METHODS -------------------------- + + public abstract void onTextInput(String text); + + public void setParams(String title, String text) { + Bundle args = new Bundle(); + args.putString(titleKey, title); + args.putString(textKey, text); + setArguments(args); + } + +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/HashtagDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/HashtagDialogFragment.java new file mode 100644 index 00000000..3ba8ee5e --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/HashtagDialogFragment.java @@ -0,0 +1,95 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.os.Bundle; +import android.view.View; +import android.widget.ListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.command.Command; +import net.lacolaco.smileessence.command.CommandPasteToPost; +import net.lacolaco.smileessence.command.CommandSaveAsTemplate; +import net.lacolaco.smileessence.command.CommandSearchOnTwitter; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.view.adapter.CustomListAdapter; + +import java.util.ArrayList; +import java.util.List; + +public class HashtagDialogFragment extends MenuDialogFragment { + + // ------------------------------ FIELDS ------------------------------ + + public static final String KEY_TEXT = "text"; + + // --------------------- GETTER / SETTER METHODS --------------------- + + private String getHashtagText() { + return "#" + (String) getArguments().get(KEY_TEXT); + } + + public void setText(String text) { + Bundle bundle = new Bundle(); + bundle.putString(KEY_TEXT, text); + setArguments(bundle); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + MainActivity activity = (MainActivity) getActivity(); + Account account = activity.getCurrentAccount(); + String text = getHashtagText(); + List<Command> commands = getCommands(activity, text); + Command.filter(commands); + View body = activity.getLayoutInflater().inflate(R.layout.dialog_menu_list, null); + ListView listView = (ListView) body.findViewById(R.id.listview_dialog_menu_list); + CustomListAdapter<Command> adapter = new CustomListAdapter<>(activity, Command.class); + listView.setAdapter(adapter); + for (Command command : commands) { + adapter.addToBottom(command); + } + adapter.update(); + listView.setOnItemClickListener(onItemClickListener); + + return new AlertDialog.Builder(activity).setView(body).setTitle(text).setCancelable(true).create(); + } + + // -------------------------- OTHER METHODS -------------------------- + + public List<Command> getCommands(Activity activity, String text) { + ArrayList<Command> commands = new ArrayList<>(); + commands.add(new CommandSaveAsTemplate(activity, text)); + commands.add(new CommandPasteToPost(activity, text)); + commands.add(new CommandSearchOnTwitter(activity, text)); + return commands; + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/MenuDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/MenuDialogFragment.java new file mode 100644 index 00000000..63d06bb1 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/MenuDialogFragment.java @@ -0,0 +1,68 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.DialogFragment; +import android.view.View; +import android.widget.AdapterView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.command.Command; +import net.lacolaco.smileessence.command.IConfirmable; + +public abstract class MenuDialogFragment extends DialogFragment { + + // ------------------------------ FIELDS ------------------------------ + + protected final AdapterView.OnItemClickListener onItemClickListener = new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { + MenuDialogFragment.this.onItemClick(adapterView, i); + } + }; + + protected void executeCommand(Command command) { + if (command.execute()) { + dismiss(); + DialogHelper.closeAll(getActivity()); + } + } + + protected void onItemClick(AdapterView<?> adapterView, int i) { + final Command command = (Command) adapterView.getItemAtPosition(i); + if (command != null) { + if (command instanceof IConfirmable) { + ConfirmDialogFragment.show(getActivity(), getString(R.string.dialog_confirm_commands), new Runnable() { + @Override + public void run() { + executeCommand(command); + } + }); + } else { + executeCommand(command); + } + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageDetailDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageDetailDialogFragment.java new file mode 100644 index 00000000..eb846196 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageDetailDialogFragment.java @@ -0,0 +1,264 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2015 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.view.View; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.ListView; + +import com.google.common.collect.Lists; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.command.Command; +import net.lacolaco.smileessence.command.CommandOpenURL; +import net.lacolaco.smileessence.data.DirectMessageCache; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.notification.Notificator; +import net.lacolaco.smileessence.twitter.TwitterApi; +import net.lacolaco.smileessence.twitter.task.DeleteMessageTask; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.view.adapter.MessageListAdapter; +import net.lacolaco.smileessence.view.listener.ListItemClickListener; +import net.lacolaco.smileessence.viewmodel.MessageViewModel; + +import twitter4j.DirectMessage; +import twitter4j.MediaEntity; +import twitter4j.URLEntity; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +public class MessageDetailDialogFragment extends DialogFragment implements View.OnClickListener { + + // ------------------------------ FIELDS ------------------------------ + + private static final String KEY_MESSAGE_ID = "messageID"; + + // --------------------- GETTER / SETTER METHODS --------------------- + + public long getMessageID() { + return getArguments().getLong(KEY_MESSAGE_ID); + } + + public void setMessageID(long messageID) { + Bundle args = new Bundle(); + args.putLong(KEY_MESSAGE_ID, messageID); + setArguments(args); + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnClickListener --------------------- + + @Override + public void onClick(final View v) { + final MainActivity activity = (MainActivity) getActivity(); + final Account account = activity.getCurrentAccount(); + TwitterUtils.tryGetMessage(account, getMessageID(), new TwitterUtils.MessageCallback() { + @Override + public void success(DirectMessage message) { + switch (v.getId()) { + case R.id.button_status_detail_reply: { + openSendMessageDialog(message); + break; + } + case R.id.button_status_detail_delete: { + deleteMessage(account, message); + break; + } + case R.id.button_status_detail_menu: { + openMenu(activity); + break; + } + default: { + dismiss(); + } + } + } + + @Override + public void error() { + + } + }); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + MainActivity activity = (MainActivity) getActivity(); + final Account account = activity.getCurrentAccount(); + + DirectMessage selectedMessage = DirectMessageCache.getInstance().get(getMessageID()); + if (selectedMessage == null) { + Notificator.publish(getActivity(), R.string.notice_error_get_messages); + return new DisposeDialog(getActivity()); + } + View header = getTitleView(activity, account, selectedMessage); + ListView listView = (ListView) header.findViewById(R.id.listview_status_detail_reply_to); + final MessageListAdapter adapter = new MessageListAdapter(getActivity()); + listView.setAdapter(adapter); + long replyToMessageId = -1; + ArrayList<DirectMessage> allMessages = Lists.newArrayList(DirectMessageCache.getInstance().all()); + Collections.sort(allMessages, new Comparator<DirectMessage>() { + @Override + public int compare(DirectMessage lhs, DirectMessage rhs) { + return rhs.getCreatedAt().compareTo(lhs.getCreatedAt()); + } + }); + for (DirectMessage directMessage : allMessages) { + if (selectedMessage.getId() == directMessage.getId()) { + continue; + } + if (directMessage.getCreatedAt().getTime() > selectedMessage.getCreatedAt().getTime()) { + continue; + } + if (directMessage.getSenderId() == selectedMessage.getRecipientId() && directMessage.getRecipientId() == selectedMessage.getSenderId()) { + replyToMessageId = directMessage.getId(); + break; + } + } + + if (replyToMessageId == -1) { + listView.setVisibility(View.GONE); + } else { + TwitterUtils.tryGetMessage(account, replyToMessageId, new TwitterUtils.MessageCallback() { + @Override + public void success(DirectMessage message) { + adapter.addToTop(new MessageViewModel(message, account)); + adapter.updateForce(); + } + + @Override + public void error() { + + } + }); + } + return new AlertDialog.Builder(getActivity()).setView(header).create(); + } + + // -------------------------- OTHER METHODS -------------------------- + + public void deleteMessage(final Account account, final DirectMessage message) { + ConfirmDialogFragment.show(getActivity(), getString(R.string.dialog_confirm_commands), new Runnable() { + @Override + public void run() { + new DeleteMessageTask(new TwitterApi(account).getTwitter(), message.getId(), getActivity()).execute(); + dismiss(); + } + }); + } + + public void openSendMessageDialog(DirectMessage message) { + SendMessageDialogFragment dialogFragment = new SendMessageDialogFragment(); + dialogFragment.setScreenName(message.getSenderScreenName()); + DialogHelper.showDialog(getActivity(), dialogFragment); + } + + private ArrayList<Command> getCommands(Activity activity, DirectMessage message, Account account) { + ArrayList<Command> commands = new ArrayList<>(); + // URL + if (message.getURLEntities() != null) { + for (URLEntity urlEntity : message.getURLEntities()) { + commands.add(new CommandOpenURL(activity, urlEntity.getExpandedURL())); + } + } + for (MediaEntity mediaEntity : getMediaEntities(message)) { + commands.add(new CommandOpenURL(activity, mediaEntity.getMediaURL())); + } + return commands; + } + + private MediaEntity[] getMediaEntities(DirectMessage message) { + if (message.getExtendedMediaEntities().length == 0) { + // direct message's media is contained also in url entities. + return new MediaEntity[0]; + } else { + return message.getExtendedMediaEntities(); + } + } + + private View getTitleView(MainActivity activity, Account account, DirectMessage message) { + View view = activity.getLayoutInflater().inflate(R.layout.dialog_status_detail, null); + View messageHeader = view.findViewById(R.id.layout_status_header); + MessageViewModel statusViewModel = new MessageViewModel(message, account); + messageHeader = statusViewModel.getView(activity, activity.getLayoutInflater(), messageHeader); + messageHeader.setClickable(false); + int background = ((ColorDrawable) messageHeader.getBackground()).getColor(); + view.setBackgroundColor(background); + ImageButton reply = (ImageButton) view.findViewById(R.id.button_status_detail_reply); + reply.setOnClickListener(this); + ImageButton delete = (ImageButton) view.findViewById(R.id.button_status_detail_delete); + delete.setVisibility(isDeletable(account, message) ? View.VISIBLE : View.GONE); + delete.setOnClickListener(this); + ImageButton menuButton = (ImageButton) view.findViewById(R.id.button_status_detail_menu); + menuButton.setOnClickListener(this); + LinearLayout commandsLayout = (LinearLayout) view.findViewById(R.id.linearlayout_status_detail_menu); + commandsLayout.setClickable(true); + // commands + ArrayList<Command> commands = getCommands(activity, message, account); + Command.filter(commands); + for (final Command command : commands) { + View commandView = command.getView(activity, activity.getLayoutInflater(), null); + commandView.setBackgroundColor(getResources().getColor(R.color.transparent)); + commandView.setOnClickListener(new ListItemClickListener(activity, new Runnable() { + @Override + public void run() { + command.execute(); + dismiss(); + } + })); + commandsLayout.addView(commandView); + } + // status only parts + view.findViewById(R.id.button_status_detail_retweet).setVisibility(View.GONE); + view.findViewById(R.id.button_status_detail_favorite).setVisibility(View.GONE); + view.findViewById(R.id.image_status_detail_fav_count).setVisibility(View.GONE); + view.findViewById(R.id.image_status_detail_rt_count).setVisibility(View.GONE); + return view; + } + + private boolean isDeletable(Account account, DirectMessage message) { + return message.getSenderId() == account.userID; + } + + private void openMenu(MainActivity activity) { + MessageMenuDialogFragment fragment = new MessageMenuDialogFragment(); + fragment.setMessageID(getMessageID()); + DialogHelper.showDialog(activity, fragment, "messageMenuDialog"); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageMenuDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageMenuDialogFragment.java new file mode 100644 index 00000000..51282b35 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageMenuDialogFragment.java @@ -0,0 +1,151 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.os.Bundle; +import android.view.View; +import android.widget.ListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.command.*; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.view.adapter.CustomListAdapter; +import net.lacolaco.smileessence.viewmodel.MessageViewModel; + +import twitter4j.DirectMessage; +import twitter4j.HashtagEntity; +import twitter4j.MediaEntity; +import twitter4j.URLEntity; + +import java.util.ArrayList; +import java.util.List; + +public class MessageMenuDialogFragment extends MenuDialogFragment { + + // ------------------------------ FIELDS ------------------------------ + + private static final String KEY_MESSAGE_ID = "messageID"; + + // --------------------- GETTER / SETTER METHODS --------------------- + + public long getMessageID() { + return getArguments().getLong(KEY_MESSAGE_ID); + } + + public void setMessageID(long messageID) { + Bundle args = new Bundle(); + args.putLong(KEY_MESSAGE_ID, messageID); + setArguments(args); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + protected void executeCommand(Command command) { + if (command.execute()) { + dismiss(); + DialogHelper.close(getActivity(), MessageViewModel.DETAIL_DIALOG); + } + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final MainActivity activity = (MainActivity) getActivity(); + final Account account = activity.getCurrentAccount(); + + View body = activity.getLayoutInflater().inflate(R.layout.dialog_menu_list, null); + ListView listView = (ListView) body.findViewById(R.id.listview_dialog_menu_list); + final CustomListAdapter<Command> adapter = new CustomListAdapter<>(activity, Command.class); + listView.setAdapter(adapter); + listView.setOnItemClickListener(onItemClickListener); + + final AlertDialog alertDialog = new AlertDialog.Builder(activity).setView(body).create(); + TwitterUtils.tryGetMessage(account, getMessageID(), new TwitterUtils.MessageCallback() { + @Override + public void success(DirectMessage message) { + List<Command> commands = getCommands(activity, message, account); + Command.filter(commands); + for (Command command : commands) { + adapter.addToBottom(command); + } + adapter.update(); + } + + @Override + public void error() { + dismiss(); + } + }); + return alertDialog; + } + + // -------------------------- OTHER METHODS -------------------------- + + public void addBottomCommands(Activity activity, DirectMessage message, Account account, ArrayList<Command> commands) { + commands.add(new CommandSaveAsTemplate(activity, message.getText())); + //User + for (String screenName : TwitterUtils.getScreenNames(message, null)) { + commands.add(new CommandOpenUserDetail(activity, screenName, account)); + } + for (Command command : getHashtagCommands(activity, message)) { + commands.add(command); + } + // Media + if (message.getURLEntities() != null) { + for (URLEntity urlEntity : message.getURLEntities()) { + commands.add(new CommandOpenURL(activity, urlEntity.getExpandedURL())); + } + } + for (MediaEntity mediaEntity : message.getExtendedMediaEntities().length == 0 ? message.getMediaEntities() : message.getExtendedMediaEntities()) { + commands.add(new CommandOpenURL(activity, mediaEntity.getMediaURL())); + } + } + + public boolean addMainCommands(Activity activity, DirectMessage message, Account account, ArrayList<Command> commands) { + return commands.addAll(Command.getMessageCommands(activity, message, account)); + } + + public List<Command> getCommands(Activity activity, DirectMessage message, Account account) { + ArrayList<Command> commands = new ArrayList<>(); + addMainCommands(activity, message, account, commands); + addBottomCommands(activity, message, account, commands); + return commands; + } + + private ArrayList<Command> getHashtagCommands(Activity activity, DirectMessage status) { + ArrayList<Command> commands = new ArrayList<>(); + if (status.getHashtagEntities() != null) { + for (HashtagEntity hashtagEntity : status.getHashtagEntities()) { + commands.add(new CommandOpenHashtagDialog(activity, hashtagEntity)); + } + } + return commands; + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/PostMenuDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/PostMenuDialogFragment.java new file mode 100644 index 00000000..aca73f33 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/PostMenuDialogFragment.java @@ -0,0 +1,98 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.os.Bundle; +import android.view.View; +import android.widget.ListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.command.Command; +import net.lacolaco.smileessence.command.CommandOpenTemplateList; +import net.lacolaco.smileessence.command.post.PostCommandMakeAnonymous; +import net.lacolaco.smileessence.command.post.PostCommandMorse; +import net.lacolaco.smileessence.command.post.PostCommandZekamashi; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.notification.Notificator; +import net.lacolaco.smileessence.view.adapter.CustomListAdapter; + +import java.util.ArrayList; +import java.util.List; + +public class PostMenuDialogFragment extends MenuDialogFragment { + + public static final String TAG = "postMenu"; + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + MainActivity activity = (MainActivity) getActivity(); + Account account = activity.getCurrentAccount(); + List<Command> commands = getCommands(activity); + Command.filter(commands); + if (commands.isEmpty()) { + Notificator.publish(getActivity(), R.string.notice_no_command_exists); + return new DisposeDialog(getActivity()); + } + View body = activity.getLayoutInflater().inflate(R.layout.dialog_menu_list, null); + ListView listView = (ListView) body.findViewById(R.id.listview_dialog_menu_list); + CustomListAdapter<Command> adapter = new CustomListAdapter<>(activity, Command.class); + listView.setAdapter(adapter); + for (Command command : commands) { + adapter.addToBottom(command); + } + adapter.update(); + listView.setOnItemClickListener(onItemClickListener); + + return new AlertDialog.Builder(activity) + .setView(body) + .setCancelable(true) + .create(); + } + + @Override + protected void executeCommand(Command command) { + if (command.execute()) { + dismiss(); + DialogHelper.close(getActivity(), TAG); + } + } + + // -------------------------- OTHER METHODS -------------------------- + + public List<Command> getCommands(Activity activity) { + ArrayList<Command> commands = new ArrayList<>(); + commands.add(new CommandOpenTemplateList(activity)); + commands.add(new PostCommandMorse(activity)); + commands.add(new PostCommandMakeAnonymous(activity)); + commands.add(new PostCommandZekamashi(activity)); + return commands; + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/QuoteDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/QuoteDialogFragment.java new file mode 100644 index 00000000..ba8240b6 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/QuoteDialogFragment.java @@ -0,0 +1,106 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.os.Bundle; +import android.view.View; +import android.widget.ListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.command.Command; +import net.lacolaco.smileessence.command.status.StatusCommandTextQuote; +import net.lacolaco.smileessence.command.status.StatusCommandURLQuote; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.view.adapter.CustomListAdapter; + +import twitter4j.Status; + +import java.util.ArrayList; +import java.util.List; + +public class QuoteDialogFragment extends MenuDialogFragment { + + // ------------------------------ FIELDS ------------------------------ + + public static final String KEY_STATUS_ID = "statusID"; + + // --------------------- GETTER / SETTER METHODS --------------------- + + private long getStatusID() { + return getArguments().getLong(KEY_STATUS_ID); + } + + public void setStatusID(long id) { + Bundle bundle = new Bundle(); + bundle.putLong(KEY_STATUS_ID, id); + setArguments(bundle); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final MainActivity activity = (MainActivity) getActivity(); + + View body = activity.getLayoutInflater().inflate(R.layout.dialog_menu_list, null); + ListView listView = (ListView) body.findViewById(R.id.listview_dialog_menu_list); + final CustomListAdapter<Command> adapter = new CustomListAdapter<>(activity, Command.class); + listView.setAdapter(adapter); + listView.setOnItemClickListener(onItemClickListener); + Account account = activity.getCurrentAccount(); + long statusID = getStatusID(); + TwitterUtils.tryGetStatus(account, statusID, new TwitterUtils.StatusCallback() { + @Override + public void success(Status status) { + List<Command> commands = getCommands(activity, status); + Command.filter(commands); + for (Command command : commands) { + adapter.addToBottom(command); + } + adapter.update(); + } + + @Override + public void error() { + dismiss(); + } + }); + return new AlertDialog.Builder(activity).setView(body).setCancelable(true).create(); + } + + // -------------------------- OTHER METHODS -------------------------- + + public List<Command> getCommands(Activity activity, Status status) { + ArrayList<Command> commands = new ArrayList<>(); + commands.add(new StatusCommandTextQuote(activity, status)); + commands.add(new StatusCommandURLQuote(activity, status)); + return commands; + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/ReviewDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/ReviewDialogFragment.java new file mode 100644 index 00000000..8b4e8cee --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/ReviewDialogFragment.java @@ -0,0 +1,129 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.Context; +import android.os.Bundle; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.RatingBar; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.data.StatusCache; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.view.adapter.PostState; + +import twitter4j.Status; + +public class ReviewDialogFragment extends DialogFragment implements View.OnClickListener { + + // ------------------------------ FIELDS ------------------------------ + + private static String statusIDKey = "key"; + private long statusID; + private RatingBar ratingBar; + + // --------------------- GETTER / SETTER METHODS --------------------- + + public void setStatusID(long statusID) { + Bundle args = new Bundle(); + args.putLong(statusIDKey, statusID); + setArguments(args); + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnClickListener --------------------- + + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.button_submit: { + execute(); + break; + } + } + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Bundle args = getArguments(); + statusID = args.getLong(statusIDKey); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_review, null); + ratingBar = (RatingBar) view.findViewById(R.id.rating_review); + Button button = (Button) view.findViewById(R.id.button_submit); + button.setOnClickListener(this); + return new AlertDialog.Builder(getActivity()) + .setView(view) + .create(); + } + + private void hideIME() { + InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(ratingBar.getWindowToken(), 0); + } + + private void execute() { + hideIME(); + Status status = StatusCache.getInstance().get(statusID); + int star = (int) ratingBar.getRating(); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < 5; i++) { + if (i < star) { + builder.append("★"); + } else { + builder.append("☆"); + } + } + String formatString = getFormatString(); + String str = String.format(formatString, + builder.toString(), + TwitterUtils.getOriginalStatus(status).getUser().getScreenName(), + TwitterUtils.getStatusURL(status)); + PostState.newState().beginTransaction() + .setText(str) + .setInReplyToStatusID(statusID) + .setCursor(str.indexOf(":") + 2) + .commitWithOpen((MainActivity) getActivity()); + } + + private String getFormatString() { + return getString(R.string.format_status_review); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/SearchOnGoogleDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SearchOnGoogleDialogFragment.java new file mode 100644 index 00000000..ca8655be --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SearchOnGoogleDialogFragment.java @@ -0,0 +1,132 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.app.SearchManager; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.EditText; + +import net.lacolaco.smileessence.R; + +public class SearchOnGoogleDialogFragment extends DialogFragment implements TextWatcher, View.OnClickListener { + + // ------------------------------ FIELDS ------------------------------ + + private static String textKey = "key"; + private String text; + private EditText editText; + private Button button; + + // --------------------- GETTER / SETTER METHODS --------------------- + + public void setText(String text) { + Bundle args = new Bundle(); + args.putString(textKey, text); + setArguments(args); + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnClickListener --------------------- + + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.button_submit: { + execute(); + break; + } + } + } + + // --------------------- Interface TextWatcher --------------------- + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (TextUtils.isEmpty(text)) { + button.setEnabled(false); + } else { + button.setEnabled(true); + } + } + + @Override + public void afterTextChanged(Editable s) { + + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Bundle args = getArguments(); + text = args.getString(textKey); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_search_on_google, null); + editText = (EditText) view.findViewById(R.id.edittext_search_on_google); + editText.addTextChangedListener(this); + button = (Button) view.findViewById(R.id.button_submit); + button.setOnClickListener(this); + editText.setText(text); + return new AlertDialog.Builder(getActivity()) + .setView(view) + .create(); + } + + private void hideIME() { + InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + + private void execute() { + hideIME(); + Intent intent = new Intent(Intent.ACTION_WEB_SEARCH); + intent.putExtra(SearchManager.QUERY, editText.getText().toString()); + getActivity().startActivity(intent); + DialogHelper.closeAll(getActivity()); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/SelectImageDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SelectImageDialogFragment.java new file mode 100644 index 00000000..9d01f6ca --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SelectImageDialogFragment.java @@ -0,0 +1,130 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.ContentValues; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.provider.MediaStore; +import android.view.View; +import android.widget.ListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.command.Command; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.util.IntentUtils; +import net.lacolaco.smileessence.view.adapter.CustomListAdapter; + +import java.util.ArrayList; +import java.util.List; + +public class SelectImageDialogFragment extends MenuDialogFragment { + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + MainActivity activity = (MainActivity) getActivity(); + Account account = activity.getCurrentAccount(); + List<Command> commands = getCommands(activity); + View body = activity.getLayoutInflater().inflate(R.layout.dialog_menu_list, null); + ListView listView = (ListView) body.findViewById(R.id.listview_dialog_menu_list); + CustomListAdapter<Command> adapter = new CustomListAdapter<>(activity, Command.class); + listView.setAdapter(adapter); + for (Command command : commands) { + adapter.addToBottom(command); + } + adapter.update(); + listView.setOnItemClickListener(onItemClickListener); + + return new AlertDialog.Builder(activity).setView(body).setTitle(R.string.dialog_title_select_image).setCancelable(true).create(); + } + + // -------------------------- OTHER METHODS -------------------------- + + public List<Command> getCommands(final MainActivity activity) { + ArrayList<Command> commands = new ArrayList<>(); + commands.add(new Command(-1, activity) { + @Override + public boolean execute() { + startGallery(activity); + return true; + } + + @Override + public String getText() { + return activity.getString(R.string.command_select_image_from_gallery); + } + + @Override + public boolean isEnabled() { + return true; + } + }); + commands.add(new Command(-1, activity) { + @Override + public boolean execute() { + startCamera(activity); + return true; + } + + @Override + public String getText() { + return activity.getString(R.string.command_select_image_from_camera); + } + + @Override + public boolean isEnabled() { + return true; + } + }); + return commands; + } + + private void startCamera(MainActivity activity) { + ContentValues values = new ContentValues(); + String filename = System.currentTimeMillis() + ".jpg"; + values.put(MediaStore.MediaColumns.TITLE, filename); + values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg"); + + // Uriを取得して覚えておく、Intentにも保存先として渡す + Uri tempFilePath = activity.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); + activity.setCameraTempFilePath(tempFilePath); + Intent intent = new Intent(); + intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); + intent.putExtra(MediaStore.EXTRA_OUTPUT, tempFilePath); + IntentUtils.startActivityForResultIfFound(activity, intent, MainActivity.REQUEST_GET_PICTURE_FROM_CAMERA); + } + + private void startGallery(MainActivity activity) { + Intent intent = new Intent(Intent.ACTION_PICK); + intent.setType("image/*"); + IntentUtils.startActivityForResultIfFound(activity, intent, MainActivity.REQUEST_GET_PICTURE_FROM_GALLERY); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/SelectSearchQueryDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SelectSearchQueryDialogFragment.java new file mode 100644 index 00000000..637a0d37 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SelectSearchQueryDialogFragment.java @@ -0,0 +1,106 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.os.Bundle; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.command.Command; +import net.lacolaco.smileessence.command.CommandOpenSearch; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.entity.SearchQuery; +import net.lacolaco.smileessence.notification.Notificator; +import net.lacolaco.smileessence.view.adapter.CustomListAdapter; + +import java.util.ArrayList; +import java.util.List; + +public class SelectSearchQueryDialogFragment extends MenuDialogFragment implements AdapterView.OnItemLongClickListener { + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnItemLongClickListener --------------------- + + @Override + public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { + final CommandOpenSearch command = (CommandOpenSearch) parent.getItemAtPosition(position); + ConfirmDialogFragment.show(getActivity(), getString(R.string.dialog_confirm_delete_query), new Runnable() { + @Override + public void run() { + deleteQuery(command); + } + }, false); + return true; + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + MainActivity activity = (MainActivity) getActivity(); + Account account = activity.getCurrentAccount(); + List<Command> commands = getCommands(activity); + Command.filter(commands); + View body = activity.getLayoutInflater().inflate(R.layout.dialog_menu_list, null); + ListView listView = (ListView) body.findViewById(R.id.listview_dialog_menu_list); + CustomListAdapter<Command> adapter = new CustomListAdapter<>(activity, Command.class); + listView.setAdapter(adapter); + for (Command command : commands) { + adapter.addToBottom(command); + } + adapter.update(); + listView.setOnItemClickListener(onItemClickListener); + listView.setOnItemLongClickListener(this); + + return new AlertDialog.Builder(activity).setView(body).setTitle(R.string.dialog_title_select_search_query).setCancelable(true).create(); + } + + // -------------------------- OTHER METHODS -------------------------- + + public List<Command> getCommands(final MainActivity activity) { + ArrayList<Command> commands = new ArrayList<>(); + final List<SearchQuery> queries = SearchQuery.getAll(); + if (queries != null) { + for (final SearchQuery query : queries) { + commands.add(new CommandOpenSearch(activity, query)); + } + } + return commands; + } + + protected void deleteQuery(CommandOpenSearch command) { + command.getQuery().delete(); + Notificator.publish(getActivity(), R.string.notice_search_query_deleted); + ((MainActivity) getActivity()).openSearchPage(""); + dismiss(); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/SelectUserListDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SelectUserListDialogFragment.java new file mode 100644 index 00000000..b38f941b --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SelectUserListDialogFragment.java @@ -0,0 +1,79 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.os.Bundle; +import android.view.View; +import android.widget.ListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.command.Command; +import net.lacolaco.smileessence.command.CommandOpenUserList; +import net.lacolaco.smileessence.data.UserListCache; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.view.adapter.CustomListAdapter; + +import java.util.ArrayList; +import java.util.List; + +public class SelectUserListDialogFragment extends MenuDialogFragment { + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + MainActivity activity = (MainActivity) getActivity(); + Account account = activity.getCurrentAccount(); + List<Command> commands = getCommands(activity); + Command.filter(commands); + View body = activity.getLayoutInflater().inflate(R.layout.dialog_menu_list, null); + ListView listView = (ListView) body.findViewById(R.id.listview_dialog_menu_list); + CustomListAdapter<Command> adapter = new CustomListAdapter<>(activity, Command.class); + listView.setAdapter(adapter); + for (Command command : commands) { + adapter.addToBottom(command); + } + adapter.update(); + listView.setOnItemClickListener(onItemClickListener); + + return new AlertDialog.Builder(activity).setView(body).setTitle(R.string.dialog_title_select_userlist).setCancelable(true).create(); + } + + // -------------------------- OTHER METHODS -------------------------- + + public List<Command> getCommands(final MainActivity activity) { + ArrayList<Command> commands = new ArrayList<>(); + final String[] lists = UserListCache.getInstance().getAll(); + if (lists != null) { + for (final String list : lists) { + commands.add(new CommandOpenUserList(activity, list)); + } + } + return commands; + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/SendMessageDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SendMessageDialogFragment.java new file mode 100644 index 00000000..def91eb1 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SendMessageDialogFragment.java @@ -0,0 +1,165 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.Context; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.TextView; + +import com.twitter.Validator; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.twitter.TwitterApi; +import net.lacolaco.smileessence.twitter.task.SendMessageTask; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.view.adapter.PostState; + +import twitter4j.Twitter; + +public class SendMessageDialogFragment extends DialogFragment implements TextWatcher, View.OnClickListener { + + // ------------------------------ FIELDS ------------------------------ + + private static String screenNameKey = "screenName"; + private String screenName; + private EditText editText; + private TextView textViewCount; + private Button buttonSend; + + // --------------------- GETTER / SETTER METHODS --------------------- + + public void setScreenName(String screenName) { + Bundle args = new Bundle(); + args.putString(screenNameKey, screenName); + setArguments(args); + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnClickListener --------------------- + + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.button_send_message: { + sendMessage(); + break; + } + case R.id.button_send_message_delete: { + deleteMessage(); + } + } + } + + // --------------------- Interface TextWatcher --------------------- + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + int remainingCount = 140 - TwitterUtils.getFixedTextLength(s.toString()); + if (!TextUtils.isEmpty(PostState.getState().getMediaFilePath())) { + remainingCount -= new Validator().getShortUrlLength(); + } + textViewCount.setText(String.valueOf(remainingCount)); + if (remainingCount == 140) { + textViewCount.setTextColor(getResources().getColor(R.color.red)); + buttonSend.setEnabled(false); + } else if (remainingCount < 0) { + textViewCount.setTextColor(getResources().getColor(R.color.red)); + buttonSend.setEnabled(false); + } else { + textViewCount.setTextAppearance(getActivity(), android.R.style.TextAppearance_Widget_TextView); + buttonSend.setEnabled(true); + } + } + + @Override + public void afterTextChanged(Editable s) { + + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Bundle args = getArguments(); + screenName = args.getString(screenNameKey); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_send_message, null); + TextView textViewName = (TextView) view.findViewById(R.id.textview_send_message_name); + textViewName.setText("To: @" + screenName); + textViewCount = (TextView) view.findViewById(R.id.textview_send_message_count); + editText = (EditText) view.findViewById(R.id.edittext_send_message); + editText.addTextChangedListener(this); + buttonSend = (Button) view.findViewById(R.id.button_send_message); + buttonSend.setOnClickListener(this); + ImageButton buttonDelete = (ImageButton) view.findViewById(R.id.button_send_message_delete); + buttonDelete.setOnClickListener(this); + editText.setText(""); + return new AlertDialog.Builder(getActivity()) + .setView(view) + .create(); + } + + private void deleteMessage() { + editText.setText(""); + } + + private void hideIME() { + InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + } + + private void sendMessage() { + MainActivity activity = (MainActivity) getActivity(); + Twitter twitter = TwitterApi.getTwitter(activity.getCurrentAccount()); + String text = editText.getText().toString(); + new SendMessageTask(twitter, screenName, text, activity).execute(); + hideIME(); + dismiss(); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/SimpleDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SimpleDialogFragment.java new file mode 100644 index 00000000..3c7d4d10 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/SimpleDialogFragment.java @@ -0,0 +1,83 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; + +import net.lacolaco.smileessence.R; + +public class SimpleDialogFragment extends DialogFragment { + + // ------------------------------ FIELDS ------------------------------ + + public static final String ARG_LAYOUT = "layout"; + public static final String ARG_TITLE = "title"; + private int layoutResourceID; + private String title; + + // -------------------------- STATIC METHODS -------------------------- + + public static SimpleDialogFragment newInstance(int layoutResourceID, String title) { + SimpleDialogFragment fragment = new SimpleDialogFragment(); + Bundle args = new Bundle(); + args.putInt(ARG_LAYOUT, layoutResourceID); + args.putString(ARG_TITLE, title); + fragment.setArguments(args); + return fragment; + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Bundle args = getArguments(); + layoutResourceID = args.getInt(ARG_LAYOUT); + title = args.getString(ARG_TITLE); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + LayoutInflater inflater = getActivity().getLayoutInflater(); + View contentView = inflater.inflate(layoutResourceID, null); + + return new AlertDialog.Builder(getActivity()) + .setTitle(title) + .setView(contentView) + .setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }) + .create(); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.java new file mode 100644 index 00000000..4f7e0358 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.java @@ -0,0 +1,331 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.view.View; +import android.widget.*; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.command.Command; +import net.lacolaco.smileessence.command.CommandOpenURL; +import net.lacolaco.smileessence.data.StatusCache; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.twitter.TweetBuilder; +import net.lacolaco.smileessence.twitter.TwitterApi; +import net.lacolaco.smileessence.twitter.task.DeleteStatusTask; +import net.lacolaco.smileessence.twitter.task.FavoriteTask; +import net.lacolaco.smileessence.twitter.task.RetweetTask; +import net.lacolaco.smileessence.twitter.task.UnfavoriteTask; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.view.adapter.PostState; +import net.lacolaco.smileessence.view.adapter.StatusListAdapter; +import net.lacolaco.smileessence.view.listener.ListItemClickListener; +import net.lacolaco.smileessence.viewmodel.StatusViewModel; + +import twitter4j.MediaEntity; +import twitter4j.Status; +import twitter4j.URLEntity; +import twitter4j.User; + +import java.util.ArrayList; + +public class StatusDetailDialogFragment extends DialogFragment implements View.OnClickListener { + + // ------------------------------ FIELDS ------------------------------ + + private static final String KEY_STATUS_ID = "statusID"; + + // --------------------- GETTER / SETTER METHODS --------------------- + + public long getStatusID() { + return getArguments().getLong(KEY_STATUS_ID); + } + + public void setStatusID(long statusID) { + Bundle args = new Bundle(); + args.putLong(KEY_STATUS_ID, statusID); + setArguments(args); + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnClickListener --------------------- + + @Override + public void onClick(final View v) { + final MainActivity activity = (MainActivity) getActivity(); + final Account account = activity.getCurrentAccount(); + TwitterUtils.tryGetStatus(account, getStatusID(), new TwitterUtils.StatusCallback() { + @Override + public void success(Status status) { + switch (v.getId()) { + case R.id.button_status_detail_reply: { + replyToStatus(activity, account, status); + break; + } + case R.id.button_status_detail_retweet: { + final Long retweetID = (Long) v.getTag(); + toggleRetweet(activity, account, status, retweetID); + break; + } + case R.id.button_status_detail_favorite: { + Boolean isFavorited = (Boolean) v.getTag(); + toggleFavorite(activity, account, status, isFavorited); + break; + } + case R.id.button_status_detail_delete: { + deleteStatus(activity, account, status); + break; + } + case R.id.button_status_detail_menu: { + openMenu(activity); + break; + } + default: { + dismiss(); + } + } + } + + @Override + public void error() { + + } + }); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final MainActivity activity = (MainActivity) getActivity(); + final Account account = activity.getCurrentAccount(); + + Status status = StatusCache.getInstance().get(getStatusID()); + View header = getTitleView(activity, account, status); + ListView listView = (ListView) header.findViewById(R.id.listview_status_detail_reply_to); + final StatusListAdapter adapter = new StatusListAdapter(getActivity()); + listView.setAdapter(adapter); + long inReplyToStatusId = TwitterUtils.getOriginalStatus(status).getInReplyToStatusId(); + if (inReplyToStatusId == -1) { + listView.setVisibility(View.GONE); + } else { + TwitterUtils.tryGetStatus(account, inReplyToStatusId, new TwitterUtils.StatusCallback() { + @Override + public void success(Status status) { + adapter.addToTop(new StatusViewModel(status, account)); + adapter.updateForce(); + } + + @Override + public void error() { + + } + }); + } + return new AlertDialog.Builder(getActivity()).setView(header).create(); + } + + private void confirm(MainActivity activity, Runnable onYes) { + ConfirmDialogFragment.show(activity, getString(R.string.dialog_confirm_commands), onYes); + } + + private void deleteStatus(final MainActivity activity, final Account account, final Status status) { + confirm(activity, new Runnable() { + @Override + public void run() { + new DeleteStatusTask(TwitterApi.getTwitter(account), TwitterUtils.getOriginalStatus(status).getId(), activity).execute(); + dismiss(); + } + }); + } + + private View getTitleView(MainActivity activity, Account account, Status status) { + View view = activity.getLayoutInflater().inflate(R.layout.dialog_status_detail, null); + View statusHeader = view.findViewById(R.id.layout_status_header); + StatusViewModel statusViewModel = new StatusViewModel(status, account); + statusHeader = statusViewModel.getView(activity, activity.getLayoutInflater(), statusHeader); + statusHeader.setClickable(false); + int background = ((ColorDrawable) statusHeader.getBackground()).getColor(); + view.setBackgroundColor(background); + ImageView favCountIcon = (ImageView) view.findViewById(R.id.image_status_detail_fav_count); + ImageView rtCountIcon = (ImageView) view.findViewById(R.id.image_status_detail_rt_count); + TextView favCountText = (TextView) view.findViewById(R.id.textview_status_detail_fav_count); + TextView rtCountText = (TextView) view.findViewById(R.id.textview_status_detail_rt_count); + int favoriteCount = TwitterUtils.getOriginalStatus(status).getFavoriteCount(); + if (favoriteCount == 0) { + favCountIcon.setVisibility(View.GONE); + favCountText.setVisibility(View.GONE); + } else { + favCountText.setText(Integer.toString(favoriteCount)); + } + int retweetCount = TwitterUtils.getOriginalStatus(status).getRetweetCount(); + if (retweetCount == 0) { + rtCountIcon.setVisibility(View.GONE); + rtCountText.setVisibility(View.GONE); + } else { + rtCountText.setText(Integer.toString(retweetCount)); + } + ImageButton menu = (ImageButton) view.findViewById(R.id.button_status_detail_menu); + ImageButton message = (ImageButton) view.findViewById(R.id.button_status_detail_reply); + ImageButton retweet = (ImageButton) view.findViewById(R.id.button_status_detail_retweet); + ImageButton favorite = (ImageButton) view.findViewById(R.id.button_status_detail_favorite); + ImageButton delete = (ImageButton) view.findViewById(R.id.button_status_detail_delete); + menu.setOnClickListener(this); + message.setOnClickListener(this); + retweet.setOnClickListener(this); + favorite.setOnClickListener(this); + delete.setOnClickListener(this); + if (isNotRetweetable(account, status)) { + retweet.setVisibility(View.GONE); + } else if (isRetweetDeletable(account, status)) { + retweet.setImageDrawable(getResources().getDrawable(R.drawable.icon_retweet_on)); + retweet.setTag(status.getId()); + } else { + retweet.setTag(-1L); + } + favorite.setTag(statusViewModel.isFavorited()); + if (statusViewModel.isFavorited()) { + favorite.setImageDrawable(getResources().getDrawable(R.drawable.icon_favorite_on)); + } + boolean deletable = isDeletable(account, status); + delete.setVisibility(deletable ? View.VISIBLE : View.GONE); + LinearLayout commandsLayout = (LinearLayout) view.findViewById(R.id.linearlayout_status_detail_menu); + commandsLayout.setClickable(true); + ArrayList<Command> commands = getCommands(activity, status, account); + Command.filter(commands); + for (final Command command : commands) { + View commandView = command.getView(activity, activity.getLayoutInflater(), null); + commandView.setBackgroundColor(getResources().getColor(R.color.transparent)); + commandView.setOnClickListener(new ListItemClickListener(activity, new Runnable() { + @Override + public void run() { + command.execute(); + dismiss(); + } + })); + commandsLayout.addView(commandView); + } + return view; + } + + + private MediaEntity[] getMediaEntities(Status status) { + if (status.getExtendedMediaEntities().length == 0) { + return status.getMediaEntities(); + } else { + return status.getExtendedMediaEntities(); + } + } + + private ArrayList<Command> getCommands(Activity activity, Status status, Account account) { + ArrayList<Command> commands = new ArrayList<>(); + // URL + if (status.getURLEntities() != null) { + for (URLEntity urlEntity : status.getURLEntities()) { + commands.add(new CommandOpenURL(activity, urlEntity.getExpandedURL())); + } + } + for (MediaEntity mediaEntity : getMediaEntities(status)) { + commands.add(new CommandOpenURL(activity, mediaEntity.getMediaURL())); + } + return commands; + } + + private boolean isDeletable(Account account, Status status) { + boolean deletable; + if (!status.isRetweet()) { + deletable = status.getUser().getId() == account.userID; + } else { + deletable = status.getRetweetedStatus().getUser().getId() == account.userID; + } + return deletable; + } + + private boolean isNotRetweetable(Account account, Status status) { + User user = TwitterUtils.getOriginalStatus(status).getUser(); + return user.isProtected() || user.getId() == account.userID; + } + + private boolean isRetweetDeletable(Account account, Status status) { + return status.isRetweet() && status.getUser().getId() == account.userID; + } + + private void openMenu(MainActivity activity) { + StatusMenuDialogFragment fragment = new StatusMenuDialogFragment(); + fragment.setStatusID(getStatusID()); + DialogHelper.showDialog(activity, fragment, "statusMenuDialog"); + } + + private void replyToStatus(MainActivity activity, Account account, Status status) { + Status originalStatus = TwitterUtils.getOriginalStatus(status); + TweetBuilder builder = new TweetBuilder(); + if (account.userID == originalStatus.getUser().getId()) { + builder.addScreenName(account.screenName); + } + builder.addScreenNames(TwitterUtils.getScreenNames(originalStatus, account.screenName)); + + String text = builder.buildText(); + int selStart = originalStatus.getUser().getScreenName().length() + 2; // "@" and " " + + PostState.newState().beginTransaction() + .insertText(0, text) + .setInReplyToStatusID(originalStatus.getId()) + .setSelection(selStart, text.length()) + .commitWithOpen(activity); + } + + private void toggleFavorite(MainActivity activity, Account account, Status status, Boolean isFavorited) { + long statusID = status.isRetweet() ? status.getRetweetedStatus().getId() : status.getId(); + if (isFavorited) { + new UnfavoriteTask(TwitterApi.getTwitter(account), statusID, activity).execute(); + } else { + new FavoriteTask(TwitterApi.getTwitter(account), statusID, activity).execute(); + } + dismiss(); + } + + private void toggleRetweet(final MainActivity activity, final Account account, final Status status, final Long retweetID) { + confirm(activity, new Runnable() { + @Override + public void run() { + if (retweetID != -1L) { + new DeleteStatusTask(TwitterApi.getTwitter(account), retweetID, activity).execute(); + } else { + new RetweetTask(TwitterApi.getTwitter(account), TwitterUtils.getOriginalStatus(status).getId(), activity).execute(); + } + dismiss(); + } + }); + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusMenuDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusMenuDialogFragment.java new file mode 100644 index 00000000..6572c49a --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusMenuDialogFragment.java @@ -0,0 +1,152 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.os.Bundle; +import android.view.View; +import android.widget.ListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.command.*; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.view.adapter.CustomListAdapter; +import net.lacolaco.smileessence.viewmodel.StatusViewModel; + +import twitter4j.HashtagEntity; +import twitter4j.MediaEntity; +import twitter4j.Status; +import twitter4j.URLEntity; + +import java.util.ArrayList; +import java.util.List; + +public class StatusMenuDialogFragment extends MenuDialogFragment { + + // ------------------------------ FIELDS ------------------------------ + + private static final String KEY_STATUS_ID = "statusID"; + + // --------------------- GETTER / SETTER METHODS --------------------- + + public long getStatusID() { + return getArguments().getLong(KEY_STATUS_ID); + } + + public void setStatusID(long statusID) { + Bundle args = new Bundle(); + args.putLong(KEY_STATUS_ID, statusID); + setArguments(args); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + + @Override + protected void executeCommand(Command command) { + if (command.execute()) { + dismiss(); + DialogHelper.close(getActivity(), StatusViewModel.STATUS_DIALOG); + } + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final MainActivity activity = (MainActivity) getActivity(); + final Account account = activity.getCurrentAccount(); + + View body = activity.getLayoutInflater().inflate(R.layout.dialog_menu_list, null); + ListView listView = (ListView) body.findViewById(R.id.listview_dialog_menu_list); + final CustomListAdapter<Command> adapter = new CustomListAdapter<>(activity, Command.class); + listView.setAdapter(adapter); + listView.setOnItemClickListener(onItemClickListener); + + final AlertDialog alertDialog = new AlertDialog.Builder(activity).setView(body).create(); + TwitterUtils.tryGetStatus(account, getStatusID(), new TwitterUtils.StatusCallback() { + @Override + public void success(Status status) { + List<Command> commands = getCommands(activity, status, account); + Command.filter(commands); + for (Command command : commands) { + adapter.addToBottom(command); + } + adapter.update(); + } + + @Override + public void error() { + dismiss(); + } + }); + return alertDialog; + } + + // -------------------------- OTHER METHODS -------------------------- + + public void addBottomCommands(Activity activity, Status status, Account account, ArrayList<Command> commands) { + commands.add(new CommandSaveAsTemplate(activity, TwitterUtils.getOriginalStatusText(status))); + //User + for (String screenName : TwitterUtils.getScreenNames(status, null)) { + commands.add(new CommandOpenUserDetail(activity, screenName, account)); + } + for (Command command : getHashtagCommands(activity, status)) { + commands.add(command); + } + // Media + if (status.getURLEntities() != null) { + for (URLEntity urlEntity : status.getURLEntities()) { + commands.add(new CommandOpenURL(activity, urlEntity.getExpandedURL())); + } + } + for (MediaEntity mediaEntity : status.getExtendedMediaEntities().length == 0 ? status.getMediaEntities() : status.getExtendedMediaEntities()) { + commands.add(new CommandOpenURL(activity, mediaEntity.getMediaURL())); + } + } + + public boolean addMainCommands(Activity activity, Status status, Account account, ArrayList<Command> commands) { + return commands.addAll(Command.getStatusCommands(activity, status, account)); + } + + public List<Command> getCommands(Activity activity, Status status, Account account) { + ArrayList<Command> commands = new ArrayList<>(); + addMainCommands(activity, status, account, commands); + addBottomCommands(activity, status, account, commands); + return commands; + } + + private ArrayList<Command> getHashtagCommands(Activity activity, Status status) { + ArrayList<Command> commands = new ArrayList<>(); + if (status.getHashtagEntities() != null) { + for (HashtagEntity hashtagEntity : status.getHashtagEntities()) { + commands.add(new CommandOpenHashtagDialog(activity, hashtagEntity)); + } + } + return commands; + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/TalkChainDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/TalkChainDialogFragment.java new file mode 100644 index 00000000..0f7d8667 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/TalkChainDialogFragment.java @@ -0,0 +1,138 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.os.AsyncTask; +import android.os.Bundle; +import android.view.View; +import android.widget.ListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.data.StatusCache; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.logging.Logger; +import net.lacolaco.smileessence.twitter.TwitterApi; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.view.adapter.StatusListAdapter; +import net.lacolaco.smileessence.viewmodel.StatusViewModel; + +import twitter4j.Status; +import twitter4j.Twitter; +import twitter4j.TwitterException; + +public class TalkChainDialogFragment extends DialogFragment { + + // ------------------------------ FIELDS ------------------------------ + + public static final String KEY_STATUS_ID = "statusID"; + + // --------------------- GETTER / SETTER METHODS --------------------- + + private long getStatusID() { + return getArguments().getLong(KEY_STATUS_ID); + } + + public void setStatusID(long id) { + Bundle bundle = new Bundle(); + bundle.putLong(KEY_STATUS_ID, id); + setArguments(bundle); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + MainActivity activity = (MainActivity) getActivity(); + final Account account = activity.getCurrentAccount(); + + View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_talk_list, null); + ListView listView = (ListView) view.findViewById(R.id.listview_dialog_talk_list); + final StatusListAdapter adapter = new StatusListAdapter(getActivity()); + listView.setAdapter(adapter); + TwitterUtils.tryGetStatus(account, getStatusID(), new TwitterUtils.StatusCallback() { + @Override + public void success(Status status) { + adapter.addToTop(new StatusViewModel(status, account)); + adapter.updateForce(); + Twitter twitter = TwitterApi.getTwitter(account); + new GetTalkTask(twitter, account, adapter, status.getInReplyToStatusId()).execute(); + } + + @Override + public void error() { + dismiss(); + } + }); + + return new AlertDialog.Builder(activity) + .setTitle(R.string.dialog_title_talk_chain) + .setView(view) + .setCancelable(true) + .create(); + } + + // -------------------------- INNER CLASSES -------------------------- + + private class GetTalkTask extends AsyncTask<Void, Void, Void> { + + private final Twitter twitter; + private final Account account; + private final StatusListAdapter adapter; + private final long inReplyToStatusId; + + public GetTalkTask(Twitter twitter, Account account, StatusListAdapter adapter, long inReplyToStatusId) { + this.twitter = twitter; + this.account = account; + this.adapter = adapter; + this.inReplyToStatusId = inReplyToStatusId; + } + + @Override + protected Void doInBackground(Void... params) { + try { + long id = inReplyToStatusId; + while (id != -1) { + final twitter4j.Status status = twitter.showStatus(id); + if (status != null) { + StatusCache.getInstance().put(status); + adapter.addToBottom(new StatusViewModel(status, account)); + adapter.updateForce(); + id = status.getInReplyToStatusId(); + } else { + break; + } + } + } catch (TwitterException e) { + e.printStackTrace(); + Logger.error(e); + } + return null; + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.java new file mode 100644 index 00000000..77e92604 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.java @@ -0,0 +1,449 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.text.Html; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.view.View; +import android.widget.*; + +import com.android.volley.toolbox.NetworkImageView; +import com.handmark.pulltorefresh.library.PullToRefreshBase; +import com.handmark.pulltorefresh.library.PullToRefreshListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.command.Command; +import net.lacolaco.smileessence.command.CommandOpenURL; +import net.lacolaco.smileessence.data.ImageCache; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.logging.Logger; +import net.lacolaco.smileessence.twitter.TwitterApi; +import net.lacolaco.smileessence.twitter.task.FollowTask; +import net.lacolaco.smileessence.twitter.task.ShowFriendshipTask; +import net.lacolaco.smileessence.twitter.task.UnfollowTask; +import net.lacolaco.smileessence.twitter.task.UserTimelineTask; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.util.Themes; +import net.lacolaco.smileessence.util.UIHandler; +import net.lacolaco.smileessence.view.adapter.CustomListAdapter; +import net.lacolaco.smileessence.view.adapter.StatusListAdapter; +import net.lacolaco.smileessence.viewmodel.StatusViewModel; + +import twitter4j.Paging; +import twitter4j.Relationship; +import twitter4j.Twitter; +import twitter4j.User; + +public class UserDetailDialogFragment extends DialogFragment implements View.OnClickListener, + PullToRefreshBase.OnRefreshListener2<ListView> { + + // ------------------------------ FIELDS ------------------------------ + + public static final String USER_MENU_DIALOG = "userMenuDialog"; + private static final String KEY_USER_ID = "userID"; + private static final int ADAPTER_INDEX = 100; + private TextView textViewScreenName; + private TextView textViewName; + private TextView textViewURL; + private TextView textViewLocate; + private TextView textViewFollowed; + private TextView textViewProtected; + private TextView textViewDescription; + private TextView textViewTweetCount; + private TextView textViewFriendCount; + private TextView textViewFollowerCount; + private TextView textViewFavoriteCount; + private NetworkImageView imageViewIcon; + private NetworkImageView imageViewHeader; + private Button buttonFollow; + private PullToRefreshListView listViewTimeline; + private TabHost tabHost; + + // --------------------- GETTER / SETTER METHODS --------------------- + + public long getUserID() { + return getArguments().getLong(KEY_USER_ID); + } + + public void setUserID(long userID) { + Bundle args = new Bundle(); + args.putLong(KEY_USER_ID, userID); + setArguments(args); + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnClickListener --------------------- + + @Override + public void onClick(final View v) { + final MainActivity activity = (MainActivity) getActivity(); + final Account account = activity.getCurrentAccount(); + TwitterUtils.tryGetUser(account, getUserID(), new TwitterUtils.UserCallback() { + @Override + public void success(final User user) { + switch (v.getId()) { + case R.id.imageview_user_detail_menu: { + openUserMenu(activity, user); + break; + } + case R.id.imageview_user_detail_icon: { + openUrl(user.getBiggerProfileImageURLHttps()); + break; + } + case R.id.textview_user_detail_screenname: { + openUrl(TwitterUtils.getUserHomeURL(user.getScreenName())); + break; + } + case R.id.textview_user_detail_tweet_count: { + openUrl(TwitterUtils.getUserHomeURL(user.getScreenName())); + break; + } + case R.id.textview_user_detail_friend_count: { + openUrl(String.format("%s/following", TwitterUtils.getUserHomeURL(user.getScreenName()))); + break; + } + case R.id.textview_user_detail_follower_count: { + openUrl(String.format("%s/followers", TwitterUtils.getUserHomeURL(user.getScreenName()))); + break; + } + case R.id.textview_user_detail_favorite_count: { + openUrl(String.format("%s/favorites", TwitterUtils.getUserHomeURL(user.getScreenName()))); + break; + } + case R.id.button_user_detail_follow: { + ConfirmDialogFragment.show(activity, getString(R.string.dialog_confirm_commands), new Runnable() { + @Override + public void run() { + toggleFollowing(user, account, activity); + } + }); + break; + } + } + } + + @Override + public void error() { + dismiss(); + } + }); + } + + // --------------------- Interface OnRefreshListener2 --------------------- + + @Override + public void onPullDownToRefresh(final PullToRefreshBase<ListView> refreshView) { + final MainActivity activity = (MainActivity) getActivity(); + final Account currentAccount = activity.getCurrentAccount(); + Twitter twitter = TwitterApi.getTwitter(currentAccount); + final StatusListAdapter adapter = getListAdapter(activity); + Paging paging = TwitterUtils.getPaging(TwitterUtils.getPagingCount(activity)); + if (adapter.getCount() > 0) { + paging.setSinceId(adapter.getTopID()); + } + new UserTimelineTask(twitter, getUserID(), paging) { + @Override + protected void onPostExecute(twitter4j.Status[] statuses) { + super.onPostExecute(statuses); + for (int i = statuses.length - 1; i >= 0; i--) { + twitter4j.Status status = statuses[i]; + adapter.addToTop(new StatusViewModel(status, currentAccount)); + } + updateListView(refreshView.getRefreshableView(), adapter, true); + refreshView.onRefreshComplete(); + } + }.execute(); + } + + @Override + public void onPullUpToRefresh(final PullToRefreshBase<ListView> refreshView) { + final MainActivity activity = (MainActivity) getActivity(); + final Account currentAccount = activity.getCurrentAccount(); + Twitter twitter = TwitterApi.getTwitter(currentAccount); + final StatusListAdapter adapter = getListAdapter(activity); + Paging paging = TwitterUtils.getPaging(TwitterUtils.getPagingCount(activity)); + if (adapter.getCount() > 0) { + paging.setMaxId(adapter.getLastID() - 1); + } + new UserTimelineTask(twitter, getUserID(), paging) { + @Override + protected void onPostExecute(twitter4j.Status[] statuses) { + super.onPostExecute(statuses); + for (twitter4j.Status status : statuses) { + adapter.addToBottom(new StatusViewModel(status, currentAccount)); + } + updateListView(refreshView.getRefreshableView(), adapter, false); + refreshView.onRefreshComplete(); + } + }.execute(); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + MainActivity activity = (MainActivity) getActivity(); + View v = activity.getLayoutInflater().inflate(R.layout.dialog_user_detail, null); + View menu = v.findViewById(R.id.imageview_user_detail_menu); + menu.setOnClickListener(this); + textViewScreenName = (TextView) v.findViewById(R.id.textview_user_detail_screenname); + textViewScreenName.setOnClickListener(this); + textViewName = (TextView) v.findViewById(R.id.textview_user_detail_name); + textViewURL = (TextView) v.findViewById(R.id.textview_user_detail_url); + textViewLocate = (TextView) v.findViewById(R.id.textview_user_detail_locate); + textViewFollowed = (TextView) v.findViewById(R.id.textview_user_detail_followed); + textViewProtected = (TextView) v.findViewById(R.id.texttview_user_detail_protected); + textViewDescription = (TextView) v.findViewById(R.id.textview_user_detail_description); + textViewTweetCount = (TextView) v.findViewById(R.id.textview_user_detail_tweet_count); + textViewTweetCount.setOnClickListener(this); + textViewFriendCount = (TextView) v.findViewById(R.id.textview_user_detail_friend_count); + textViewFriendCount.setOnClickListener(this); + textViewFollowerCount = (TextView) v.findViewById(R.id.textview_user_detail_follower_count); + textViewFollowerCount.setOnClickListener(this); + textViewFavoriteCount = (TextView) v.findViewById(R.id.textview_user_detail_favorite_count); + textViewFavoriteCount.setOnClickListener(this); + imageViewIcon = (NetworkImageView) v.findViewById(R.id.imageview_user_detail_icon); + imageViewIcon.setOnClickListener(this); + imageViewHeader = (NetworkImageView) v.findViewById(R.id.imageview_user_detail_header); + buttonFollow = (Button) v.findViewById(R.id.button_user_detail_follow); + buttonFollow.setOnClickListener(this); + listViewTimeline = (PullToRefreshListView) v.findViewById(R.id.listview_user_detail_timeline); + + tabHost = (TabHost) v.findViewById(android.R.id.tabhost); + tabHost.setup(); + TabHost.TabSpec tab1 = tabHost.newTabSpec("tab1").setContent(R.id.tab1).setIndicator(getString(R.string.user_detail_tab_info)); + tabHost.addTab(tab1); + TabHost.TabSpec tab2 = tabHost.newTabSpec("tab2").setContent(R.id.tab2).setIndicator(getString(R.string.user_detail_tab_timeline)); + tabHost.addTab(tab2); + tabHost.setCurrentTab(0); + + final Account account = activity.getCurrentAccount(); + TwitterUtils.tryGetUser(account, getUserID(), new TwitterUtils.UserCallback() { + @Override + public void success(User user) { + try { + initUserData(user, account); + } catch (Exception e) { + Logger.error(e); + error(); + } + } + + @Override + public void error() { + dismiss(); + } + }); + return new AlertDialog.Builder(activity) + .setView(v) + .setCancelable(true) + .create(); + } + + private void executeUserTimelineTask(final User user, final Account account, final StatusListAdapter adapter) { + tabHost.getTabWidget().getChildTabViewAt(1).setVisibility(View.GONE); + Twitter twitter = TwitterApi.getTwitter(account); + new UserTimelineTask(twitter, user.getId()) { + @Override + protected void onPostExecute(twitter4j.Status[] statuses) { + super.onPostExecute(statuses); + for (twitter4j.Status status : statuses) { + adapter.addToBottom(new StatusViewModel(status, account)); + } + adapter.updateForce(); + tabHost.getTabWidget().getChildTabViewAt(1).setVisibility(View.VISIBLE); + } + }.execute(); + } + + private String getHtmlDescription(String description) { + if (TextUtils.isEmpty(description)) { + return ""; + } + String html = description; + html = html.replaceAll("https?://[\\w/:%#\\$&\\?\\(\\)~\\.=\\+\\-]+", "<a href=\"$0\">$0</a>"); + html = html.replaceAll("@([a-zA-Z0-9_]+)", "<a href=\"" + TwitterUtils.getUserHomeURL("$1") + "\">$0</a>"); + html = html.replaceAll("\r\n", "<br />"); + return html; + } + + private StatusListAdapter getListAdapter(MainActivity activity) { + return (StatusListAdapter) activity.getListAdapter(ADAPTER_INDEX); + } + + private void initUserData(User user, final Account account) { + textViewName.setText(user.getName()); + textViewScreenName.setText(user.getScreenName()); + if (TextUtils.isEmpty(user.getLocation())) { + textViewLocate.setVisibility(View.GONE); + } else { + textViewLocate.setText(user.getLocation()); + } + if (TextUtils.isEmpty(user.getURL())) { + textViewURL.setVisibility(View.GONE); + } else { + textViewURL.setText(user.getURL()); + } + textViewTweetCount.setText(String.valueOf(user.getStatusesCount())); + textViewFriendCount.setText(String.valueOf(user.getFriendsCount())); + textViewFollowerCount.setText(String.valueOf(user.getFollowersCount())); + textViewFavoriteCount.setText(String.valueOf(user.getFavouritesCount())); + textViewProtected.setVisibility(user.isProtected() ? View.VISIBLE : View.GONE); + String htmlDescription = getHtmlDescription(user.getDescription()); + textViewDescription.setText(Html.fromHtml(htmlDescription)); + textViewDescription.setMovementMethod(LinkMovementMethod.getInstance()); + ImageCache.getInstance().setImageToView(user.getBiggerProfileImageURL(), imageViewIcon); + ImageCache.getInstance().setImageToView(user.getProfileBannerURL(), imageViewHeader); + MainActivity activity = (MainActivity) getActivity(); + final StatusListAdapter adapter = new StatusListAdapter(activity); + listViewTimeline.setAdapter(adapter); + listViewTimeline.setOnRefreshListener(this); + activity.setListAdapter(ADAPTER_INDEX, adapter); + executeUserTimelineTask(user, account, adapter); + updateRelationship(activity, user.getId()); + } + + private void lockFollowButton(Activity activity) { + buttonFollow.setText(R.string.user_detail_loading); + buttonFollow.setBackground(activity.getResources().getDrawable(R.drawable.button_round_gray)); + buttonFollow.setEnabled(false); + } + + private void openUrl(String url) { + new CommandOpenURL(getActivity(), url).execute(); + } + + private void openUserMenu(final MainActivity activity, final User user) { + UserMenuDialogFragment menuFragment = new UserMenuDialogFragment() { + @Override + protected void executeCommand(Command command) { + super.executeCommand(command); + new UIHandler() { + @Override + public void run() { + if (UserDetailDialogFragment.this.isDetached()) { + return; + } + updateRelationship(activity, user.getId()); + } + }.postDelayed(1000); + } + }; + menuFragment.setUserID(user.getId()); + DialogHelper.showDialog(activity, menuFragment, USER_MENU_DIALOG); + } + + private void setFollowButtonState(boolean isFollowing, Drawable unfollowColor, Drawable followColor) { + buttonFollow.setText(isFollowing ? R.string.user_detail_unfollow : R.string.user_detail_follow); + buttonFollow.setBackground(isFollowing ? unfollowColor : followColor); + buttonFollow.setTag(isFollowing); + buttonFollow.setEnabled(true); + } + + private void toggleFollowing(final User user, final Account account, final Activity activity) { + lockFollowButton(activity); + Boolean isFollowing = buttonFollow.getTag() != null ? (Boolean) buttonFollow.getTag() : false; + Twitter twitter = new TwitterApi(account).getTwitter(); + if (isFollowing) { + new UnfollowTask(twitter, user.getId(), activity) { + @Override + public void onPostExecute(User result) { + super.onPostExecute(result); + updateRelationship(activity, user.getId()); + buttonFollow.setEnabled(true); + } + }.execute(); + } else { + new FollowTask(twitter, user.getId(), activity) { + @Override + public void onPostExecute(User result) { + super.onPostExecute(result); + updateRelationship(activity, user.getId()); + buttonFollow.setEnabled(true); + } + }.execute(); + } + } + + protected void updateListView(AbsListView absListView, CustomListAdapter<?> adapter, boolean addedToTop) { + int before = adapter.getCount(); + adapter.notifyDataSetChanged(); // synchronized call (not adapter#updateForce()) + int after = adapter.getCount(); + int increments = after - before; + if (increments > 0) { + adapter.setNotifiable(false); + if (addedToTop) { + absListView.setSelection(increments + 1); + absListView.smoothScrollToPositionFromTop(increments, 0); + absListView.setSelection(increments); + } else { + absListView.smoothScrollToPositionFromTop(before, 0); + } + + if (increments == 1) { + adapter.setNotifiable(true); + } + } else { + adapter.setNotifiable(true); + } + } + + private void updateRelationship(Activity activity, final long userId) { + MainActivity mainActivity = (MainActivity) activity; + Account account = mainActivity.getCurrentAccount(); + Twitter twitter = new TwitterApi(account).getTwitter(); + if (userId == account.userID) { + textViewFollowed.setText(R.string.user_detail_followed_is_me); + buttonFollow.setVisibility(View.GONE); + } else { + int theme = mainActivity.getThemeIndex(); + lockFollowButton(activity); + textViewFollowed.setText(R.string.user_detail_loading); + final Drawable red = Themes.getStyledDrawable(activity, theme, R.attr.button_round_red); + final Drawable blue = Themes.getStyledDrawable(activity, theme, R.attr.button_round_blue); + new ShowFriendshipTask(twitter, userId) { + @Override + protected void onPostExecute(Relationship relationship) { + if (relationship != null) { + boolean isFollowing = relationship.isSourceFollowingTarget(); + boolean isFollowed = relationship.isSourceFollowedByTarget(); + setFollowButtonState(isFollowing, red, blue); + textViewFollowed.setText(isFollowed ? R.string.user_detail_followed : R.string.user_detail_not_followed); + } + } + }.execute(); + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserMenuDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserMenuDialogFragment.java new file mode 100644 index 00000000..96f2cc30 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserMenuDialogFragment.java @@ -0,0 +1,123 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.dialog; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.os.Bundle; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ListView; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.MainActivity; +import net.lacolaco.smileessence.command.Command; +import net.lacolaco.smileessence.command.CommandSearchOnTwitter; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.twitter.util.TwitterUtils; +import net.lacolaco.smileessence.view.adapter.CustomListAdapter; + +import twitter4j.User; + +import java.util.ArrayList; +import java.util.List; + +public class UserMenuDialogFragment extends MenuDialogFragment { + + // ------------------------------ FIELDS ------------------------------ + + private static final String KEY_USER_ID = "userID"; + + // --------------------- GETTER / SETTER METHODS --------------------- + + public long getUserID() { + return getArguments().getLong(KEY_USER_ID); + } + + public void setUserID(long userID) { + Bundle args = new Bundle(); + args.putLong(KEY_USER_ID, userID); + setArguments(args); + } + + // ------------------------ OVERRIDE METHODS ------------------------ + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final MainActivity activity = (MainActivity) getActivity(); + final Account account = activity.getCurrentAccount(); + View body = activity.getLayoutInflater().inflate(R.layout.dialog_menu_list, null); + ListView listView = (ListView) body.findViewById(R.id.listview_dialog_menu_list); + final CustomListAdapter<Command> adapter = new CustomListAdapter<>(activity, Command.class); + listView.setAdapter(adapter); + listView.setOnItemClickListener(onItemClickListener); + + TwitterUtils.tryGetUser(account, getUserID(), new TwitterUtils.UserCallback() { + @Override + public void success(User user) { + List<Command> commands = getCommands(activity, user, account); + Command.filter(commands); + for (Command command : commands) { + adapter.addToBottom(command); + } + adapter.update(); + } + + @Override + public void error() { + dismiss(); + } + }); + + return new AlertDialog.Builder(activity) + .setView(body) + .setCancelable(true) + .create(); + } + + @Override + protected void onItemClick(AdapterView<?> adapterView, int i) { + super.onItemClick(adapterView, i); + dismiss(); + } + + // -------------------------- OTHER METHODS -------------------------- + + public boolean addBottomCommands(Activity activity, User user, ArrayList<Command> commands) { + return commands.add(new CommandSearchOnTwitter(activity, user.getScreenName())); + } + + public boolean addMainCommands(Activity activity, User user, Account account, ArrayList<Command> commands) { + return commands.addAll(Command.getUserCommands(activity, user, account)); + } + + public List<Command> getCommands(Activity activity, User user, Account account) { + ArrayList<Command> commands = new ArrayList<>(); + addMainCommands(activity, user, account, commands); + addBottomCommands(activity, user, commands); + return commands; + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/view/listener/ListItemClickListener.java b/app/src/main/java/net/lacolaco/smileessence/view/listener/ListItemClickListener.java new file mode 100644 index 00000000..bfb3573f --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/view/listener/ListItemClickListener.java @@ -0,0 +1,67 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.view.listener; + +import android.app.Activity; +import android.graphics.drawable.ColorDrawable; +import android.view.View; + +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.util.UIHandler; + +public class ListItemClickListener implements View.OnClickListener { + + // ------------------------------ FIELDS ------------------------------ + + private final Activity activity; + private final Runnable callback; + + // --------------------------- CONSTRUCTORS --------------------------- + + public ListItemClickListener(Activity activity, Runnable callback) { + this.activity = activity; + this.callback = callback; + } + + // ------------------------ INTERFACE METHODS ------------------------ + + + // --------------------- Interface OnClickListener --------------------- + + @Override + public void onClick(final View v) { + final int currentBgColor = ((ColorDrawable) v.getBackground()).getColor(); + v.setBackgroundColor(activity.getResources().getColor(R.color.metro_blue)); + v.invalidate(); + new UIHandler() { + + @Override + public void run() { + v.setBackgroundColor(currentBgColor); + callback.run(); + } + }.post(); + } +} |