aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/net/lacolaco/smileessence/view
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/net/lacolaco/smileessence/view')
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/CustomListFragment.java167
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/HistoryFragment.java55
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/HomeFragment.java123
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/MentionsFragment.java106
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/MessagesFragment.java109
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/PostFragment.java388
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/SearchFragment.java346
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.java182
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/TextFragment.java55
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/UserListFragment.java214
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.java178
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/adapter/EventListAdapter.java38
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/adapter/MessageListAdapter.java107
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.java186
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/adapter/PostState.java202
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/adapter/SearchListAdapter.java83
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/adapter/StatusListAdapter.java113
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/ChooseTemplateDialogFragment.java80
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/ConfirmDialogFragment.java125
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/DialogHelper.java97
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/DisposeDialog.java51
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTextDialogFragment.java91
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/HashtagDialogFragment.java95
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/MenuDialogFragment.java68
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageDetailDialogFragment.java264
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/MessageMenuDialogFragment.java151
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/PostMenuDialogFragment.java98
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/QuoteDialogFragment.java106
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/ReviewDialogFragment.java129
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/SearchOnGoogleDialogFragment.java132
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/SelectImageDialogFragment.java130
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/SelectSearchQueryDialogFragment.java106
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/SelectUserListDialogFragment.java79
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/SendMessageDialogFragment.java165
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/SimpleDialogFragment.java83
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.java331
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusMenuDialogFragment.java152
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/TalkChainDialogFragment.java138
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.java449
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/UserMenuDialogFragment.java123
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/listener/ListItemClickListener.java67
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();
+ }
+}