diff --git a/.gitignore b/.gitignore index a22392ad..d3f5d3e1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,16 @@ -/bin -/gen +# built application files +*.apk +*.ap_ + +# files for the dex VM +*.dex + +# Java class files +*.class + +# generated files +bin/ +gen/ + +# Local configuration file (sdk path, etc) +local.properties diff --git a/project.properties b/project.properties index 7d327052..321efc44 100644 --- a/project.properties +++ b/project.properties @@ -16,4 +16,4 @@ android.library.reference.1=../ActionBarSherlock android.library.reference.2=../viewpagerindicator android.library.reference.3=../android-preferences android.library.reference.4=../android-holocompat -android.library.reference.5=../Android-PullToRefresh +android.library.reference.5=../android-pulltorefresh diff --git a/res/layout/view_status.xml b/res/layout/view_status.xml index bfe69ab6..d155a8a9 100644 --- a/res/layout/view_status.xml +++ b/res/layout/view_status.xml @@ -34,7 +34,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" - android:text="Name" android:textAppearance="?android:attr/textAppearanceMedium"/> @@ -70,24 +68,34 @@ - + android:padding="8dip"> + + + + - + + + \ No newline at end of file diff --git a/src/org/mariotaku/twidere/IUpdateService.aidl b/src/org/mariotaku/twidere/IUpdateService.aidl index 3fd72c01..a146141a 100644 --- a/src/org/mariotaku/twidere/IUpdateService.aidl +++ b/src/org/mariotaku/twidere/IUpdateService.aidl @@ -1,14 +1,14 @@ package org.mariotaku.twidere; interface IUpdateService { - void getHomeTimeline(in long[] account_ids, in long[] max_ids); - void getMentions(in long[] account_ids, in long[] max_ids); - void getMessages(in long[] account_ids, in long[] max_ids); - void updateStatus(in long[] account_ids, String content, in Location location, in Uri image_uri, long in_reply_to); - void destroyStatus(long account_id, long status_id); - void retweetStatus(in long[] account_ids, long status_id); - void createFavorite(in long[] account_ids, long status_id); - void destroyFavorite(in long[] account_id, long status_id); + int getHomeTimeline(in long[] account_ids, in long[] max_ids); + int getMentions(in long[] account_ids, in long[] max_ids); + int getMessages(in long[] account_ids, in long[] max_ids); + int updateStatus(in long[] account_ids, String content, in Location location, in Uri image_uri, long in_reply_to); + int destroyStatus(long account_id, long status_id); + int retweetStatus(in long[] account_ids, long status_id); + int createFavorite(in long[] account_ids, long status_id); + int destroyFavorite(in long[] account_id, long status_id); boolean isHomeTimelineRefreshing(); boolean isMentionsRefreshing(); boolean hasActivatedTask(); diff --git a/src/org/mariotaku/twidere/fragment/ViewStatusFragment.java b/src/org/mariotaku/twidere/fragment/ViewStatusFragment.java index cf21d281..182fd8af 100644 --- a/src/org/mariotaku/twidere/fragment/ViewStatusFragment.java +++ b/src/org/mariotaku/twidere/fragment/ViewStatusFragment.java @@ -177,11 +177,6 @@ public void onPrepareOptionsMenu(Menu menu) { if (cur != null) { cur.close(); } - if (getSherlockActivity() instanceof ViewStatusActivity) { - getSherlockActivity().finish(); - } else { - getFragmentManager().beginTransaction().remove(this); - } } if (cur != null && cur.getCount() > 0) { @@ -197,6 +192,13 @@ public void onPrepareOptionsMenu(Menu menu) { itemFav.getIcon().clearColorFilter(); itemFav.setTitle(R.string.fav); } + } else { + if (getSherlockActivity() instanceof ViewStatusActivity) { + getSherlockActivity().finish(); + } else { + //Do what? I will make a decision after I have a tablet. + //getFragmentManager().beginTransaction().remove(this); + } } if (cur != null) { cur.close(); @@ -245,7 +247,8 @@ private void displayStatus() { String screen_name = cur.getString(cur.getColumnIndexOrThrow(Statuses.SCREEN_NAME)); mScreenName.setText(screen_name != null ? "@" + screen_name : ""); String text = cur.getString(cur.getColumnIndexOrThrow(Statuses.TEXT)); - mText.setText(text != null ? text : ""); + if (text != null) mText.setText(Html.fromHtml(text)); + mText.setMovementMethod(LinkMovementMethod.getInstance()); String source = cur.getString(cur.getColumnIndexOrThrow(Statuses.SOURCE)); mSource.setText(Html.fromHtml(getString(R.string.sent_from, source))); mSource.setMovementMethod(LinkMovementMethod.getInstance()); @@ -285,7 +288,7 @@ private boolean isAllFollowing() { Twitter twitter = CommonUtils.getTwitterInstance(getSherlockActivity(), id); try { Relationship result = twitter.showFriendship(id, mTweetUserId); - if (!result.isSourceFollowingTarget()) return false; + if (!result.isSourceFollowingTarget() && id != mTweetUserId) return false; } catch (TwitterException e) { e.printStackTrace(); } diff --git a/src/org/mariotaku/twidere/service/UpdateService.java b/src/org/mariotaku/twidere/service/UpdateService.java index 004b7b1a..ee6a5cd6 100644 --- a/src/org/mariotaku/twidere/service/UpdateService.java +++ b/src/org/mariotaku/twidere/service/UpdateService.java @@ -20,6 +20,7 @@ import twitter4j.MediaEntity; import twitter4j.Paging; import twitter4j.ResponseList; +import twitter4j.Status; import twitter4j.StatusUpdate; import twitter4j.Twitter; import twitter4j.TwitterException; @@ -39,19 +40,19 @@ public class UpdateService extends RoboService implements Constants { private int mRefreshHomeTimelineTaskId, mRefreshMentionsTaskId; - public void createFavorite(long[] account_ids, long status_id) { + public int createFavorite(long[] account_ids, long status_id) { CreateFavoriteTask task = new CreateFavoriteTask(account_ids, status_id); - mAsyncTaskManager.add(task, true); + return mAsyncTaskManager.add(task, true); } - public void destroyFavorite(long[] account_ids, long status_id) { + public int destroyFavorite(long[] account_ids, long status_id) { DestroyFavoriteTask task = new DestroyFavoriteTask(account_ids, status_id); - mAsyncTaskManager.add(task, true); + return mAsyncTaskManager.add(task, true); } - public void destroyStatus(long account_id, long status_id) { + public int destroyStatus(long account_id, long status_id) { DestroyStatusTask task = new DestroyStatusTask(account_id, status_id); - mAsyncTaskManager.add(task, true); + return mAsyncTaskManager.add(task, true); } public boolean hasActivatedTask() { @@ -77,32 +78,32 @@ public void onCreate() { mAsyncTaskManager = ((TwidereApplication) getApplication()).getAsyncTaskManager(); } - public void refreshHomeTimeline(long[] account_ids, long[] max_ids) { + public int refreshHomeTimeline(long[] account_ids, long[] max_ids) { mAsyncTaskManager.cancel(mRefreshHomeTimelineTaskId); GetHomeTimelineTask task = new GetHomeTimelineTask(account_ids, max_ids); - mRefreshHomeTimelineTaskId = mAsyncTaskManager.add(task, true); + return mRefreshHomeTimelineTaskId = mAsyncTaskManager.add(task, true); } - public void refreshMentions(long[] account_ids, long[] max_ids) { + public int refreshMentions(long[] account_ids, long[] max_ids) { mAsyncTaskManager.cancel(mRefreshMentionsTaskId); GetMentionsTask task = new GetMentionsTask(account_ids, max_ids); - mRefreshMentionsTaskId = mAsyncTaskManager.add(task, true); + return mRefreshMentionsTaskId = mAsyncTaskManager.add(task, true); } - public void refreshMessages(long[] account_ids, long[] max_ids) { - + public int refreshMessages(long[] account_ids, long[] max_ids) { + return -1; } - public void retweetStatus(long[] account_ids, long status_id) { + public int retweetStatus(long[] account_ids, long status_id) { RetweetStatusTask task = new RetweetStatusTask(account_ids, status_id); - mAsyncTaskManager.add(task, true); + return mAsyncTaskManager.add(task, true); } - public void updateStatus(long[] account_ids, String content, Location location, Uri image_uri, + public int updateStatus(long[] account_ids, String content, Location location, Uri image_uri, long in_reply_to) { UpdateStatusTask task = new UpdateStatusTask(account_ids, content, location, image_uri, in_reply_to); - mAsyncTaskManager.add(task, true); + return mAsyncTaskManager.add(task, true); } private class CreateFavoriteTask extends @@ -336,6 +337,7 @@ protected void onPostExecute(List responces) { long min_id = -1, max_id = -1; for (twitter4j.Status status : statuses) { + if (status == null) continue; ContentValues values = new ContentValues(); User user = status.getUser(); long status_id = status.getId(); @@ -344,7 +346,7 @@ protected void onPostExecute(List responces) { values.put(Statuses.ACCOUNT_ID, account_id); values.put(Statuses.USER_ID, user.getId()); values.put(Statuses.STATUS_TIMESTAMP, status.getCreatedAt().getTime()); - values.put(Statuses.TEXT, status.getText()); + values.put(Statuses.TEXT, CommonUtils.formatStatusString(status)); values.put(Statuses.NAME, user.getName()); values.put(Statuses.SCREEN_NAME, user.getScreenName()); values.put(Statuses.PROFILE_IMAGE_URL, user.getProfileImageURL().toString()); @@ -460,6 +462,7 @@ protected void onPostExecute(List responces) { long min_id = -1, max_id = -1; for (twitter4j.Status mention : mentions) { + if (mention == null) continue; ContentValues values = new ContentValues(); long status_id = mention.getId(); MediaEntity[] medias = mention.getMediaEntities(); @@ -468,7 +471,7 @@ protected void onPostExecute(List responces) { values.put(Mentions.STATUS_ID, status_id); values.put(Mentions.USER_ID, user.getId()); values.put(Mentions.STATUS_TIMESTAMP, mention.getCreatedAt().getTime()); - values.put(Mentions.TEXT, mention.getText()); + values.put(Mentions.TEXT, CommonUtils.formatStatusString(mention)); values.put(Mentions.NAME, user.getName()); values.put(Mentions.SCREEN_NAME, user.getScreenName()); values.put(Mentions.PROFILE_IMAGE_URL, user.getProfileImageURL().toString()); @@ -658,33 +661,33 @@ public ServiceStub(UpdateService service) { } @Override - public void createFavorite(long[] account_ids, long status_id) throws RemoteException { - mService.get().createFavorite(account_ids, status_id); + public int createFavorite(long[] account_ids, long status_id) throws RemoteException { + return mService.get().createFavorite(account_ids, status_id); } @Override - public void destroyFavorite(long[] account_ids, long status_id) throws RemoteException { - mService.get().destroyFavorite(account_ids, status_id); + public int destroyFavorite(long[] account_ids, long status_id) throws RemoteException { + return mService.get().destroyFavorite(account_ids, status_id); } @Override - public void destroyStatus(long account_id, long status_id) throws RemoteException { - mService.get().destroyStatus(account_id, status_id); + public int destroyStatus(long account_id, long status_id) throws RemoteException { + return mService.get().destroyStatus(account_id, status_id); } @Override - public void getHomeTimeline(long[] account_ids, long[] max_ids) throws RemoteException { - mService.get().refreshHomeTimeline(account_ids, max_ids); + public int getHomeTimeline(long[] account_ids, long[] max_ids) throws RemoteException { + return mService.get().refreshHomeTimeline(account_ids, max_ids); } @Override - public void getMentions(long[] account_ids, long[] max_ids) throws RemoteException { - mService.get().refreshMentions(account_ids, max_ids); + public int getMentions(long[] account_ids, long[] max_ids) throws RemoteException { + return mService.get().refreshMentions(account_ids, max_ids); } @Override - public void getMessages(long[] account_ids, long[] max_ids) throws RemoteException { - mService.get().refreshMessages(account_ids, max_ids); + public int getMessages(long[] account_ids, long[] max_ids) throws RemoteException { + return mService.get().refreshMessages(account_ids, max_ids); } @Override @@ -703,14 +706,14 @@ public boolean isMentionsRefreshing() throws RemoteException { } @Override - public void retweetStatus(long[] account_ids, long status_id) throws RemoteException { - mService.get().retweetStatus(account_ids, status_id); + public int retweetStatus(long[] account_ids, long status_id) throws RemoteException { + return mService.get().retweetStatus(account_ids, status_id); } @Override - public void updateStatus(long[] account_ids, String content, Location location, + public int updateStatus(long[] account_ids, String content, Location location, Uri image_uri, long in_reply_to) throws RemoteException { - mService.get().updateStatus(account_ids, content, location, image_uri, in_reply_to); + return mService.get().updateStatus(account_ids, content, location, image_uri, in_reply_to); } diff --git a/src/org/mariotaku/twidere/util/CommonUtils.java b/src/org/mariotaku/twidere/util/CommonUtils.java index 138393e0..7243bf81 100644 --- a/src/org/mariotaku/twidere/util/CommonUtils.java +++ b/src/org/mariotaku/twidere/util/CommonUtils.java @@ -1,5 +1,6 @@ package org.mariotaku.twidere.util; +import java.net.URL; import java.util.Date; import java.util.HashMap; @@ -8,9 +9,13 @@ import org.mariotaku.twidere.provider.TweetStore.Accounts; import org.mariotaku.twidere.service.UpdateService; +import twitter4j.HashtagEntity; +import twitter4j.Status; import twitter4j.Twitter; import twitter4j.TwitterException; import twitter4j.TwitterFactory; +import twitter4j.URLEntity; +import twitter4j.UserMentionEntity; import twitter4j.auth.AccessToken; import twitter4j.auth.BasicAuthorization; import twitter4j.conf.ConfigurationBuilder; @@ -30,8 +35,12 @@ import android.net.Uri; import android.os.Build; import android.provider.MediaStore; +import android.text.Html; +import android.text.SpannableString; +import android.text.Spanned; import android.text.format.DateUtils; import android.text.format.Time; +import android.text.style.URLSpan; import android.util.Log; import android.view.View; import android.view.Window; @@ -388,5 +397,56 @@ public void onServiceDisconnected(ComponentName className) { } } } + + public static String formatStatusString(Status status) { + final CharSequence TAG_START = "

"; + final CharSequence TAG_END = "

"; + if (status == null) return ""; + SpannableString text = new SpannableString(status.getText()); + //Format links. + URLEntity[] urls = status.getURLEntities(); + if (urls != null) { + for (URLEntity url : urls) { + int start = url.getStart(); + int end = url.getEnd(); + URL expanded_url = url.getExpandedURL(); + if (expanded_url != null) { + text.setSpan(new URLSpan(expanded_url.toString()), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + } + //Format mentioned users. + UserMentionEntity[] mentions = status.getUserMentionEntities(); + if (mentions != null) { + for (UserMentionEntity mention : mentions) { + int start = mention.getStart(); + int end = mention.getEnd(); + String link = "https://twitter.com/#!/" + mention.getScreenName(); + if (link != null) { + text.setSpan(new URLSpan(link), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + } + //Format hashtags. + HashtagEntity[] hashtags = status.getHashtagEntities(); + if (hashtags != null) { + for (HashtagEntity hashtag : hashtags) { + int start = hashtag.getStart(); + int end = hashtag.getEnd(); + String link = "https://twitter.com/search/#" + hashtag.getText(); + if (link != null) { + text.setSpan(new URLSpan(link), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + } + String formatted = Html.toHtml(text); + if (formatted != null && formatted.contains(TAG_START) && formatted.contains(TAG_END)) { + int start = formatted.indexOf(TAG_START.toString()) + TAG_START.length(); + int end = formatted.lastIndexOf(TAG_END.toString()); + return formatted.substring(start, end); + } else { + return formatted; + } + } } diff --git a/src/org/mariotaku/twidere/util/ServiceInterface.java b/src/org/mariotaku/twidere/util/ServiceInterface.java index 1e8c5f52..59e02c12 100644 --- a/src/org/mariotaku/twidere/util/ServiceInterface.java +++ b/src/org/mariotaku/twidere/util/ServiceInterface.java @@ -89,64 +89,69 @@ public IBinder asBinder() { } @Override - public void createFavorite(long[] account_ids, long status_id) { - if (mService == null) return; + public int createFavorite(long[] account_ids, long status_id) { + if (mService == null) return -1; try { - mService.createFavorite(account_ids, status_id); + return mService.createFavorite(account_ids, status_id); } catch (RemoteException e) { e.printStackTrace(); } + return -1; } @Override - public void destroyFavorite(long[] account_ids, long status_id) { - if (mService == null) return; + public int destroyFavorite(long[] account_ids, long status_id) { + if (mService == null) return -1; try { - mService.destroyFavorite(account_ids, status_id); + return mService.destroyFavorite(account_ids, status_id); } catch (RemoteException e) { e.printStackTrace(); } + return -1; } @Override - public void destroyStatus(long account_id, long status_id) { - if (mService == null) return; + public int destroyStatus(long account_id, long status_id) { + if (mService == null) return -1; try { - mService.destroyStatus(account_id, status_id); + return mService.destroyStatus(account_id, status_id); } catch (RemoteException e) { e.printStackTrace(); } + return -1; } @Override - public void getHomeTimeline(long[] account_ids, long[] max_ids) { - if (mService == null) return; + public int getHomeTimeline(long[] account_ids, long[] max_ids) { + if (mService == null) return -1; try { - mService.getHomeTimeline(account_ids, max_ids); + return mService.getHomeTimeline(account_ids, max_ids); } catch (RemoteException e) { e.printStackTrace(); } - + return -1; } @Override - public void getMentions(long[] account_ids, long[] max_ids) { - if (mService == null) return; + public int getMentions(long[] account_ids, long[] max_ids) { + if (mService == null) return -1; try { - mService.getMentions(account_ids, max_ids); + return mService.getMentions(account_ids, max_ids); } catch (RemoteException e) { e.printStackTrace(); } + return -1; } @Override - public void getMessages(long[] account_ids, long[] max_ids) { - if (mService == null) return; + public int getMessages(long[] account_ids, long[] max_ids) { + if (mService == null) return -1; try { - mService.getMessages(account_ids, max_ids); + return mService.getMessages(account_ids, max_ids); } catch (RemoteException e) { e.printStackTrace(); } + return -1; } @Override @@ -189,25 +194,26 @@ public void removeStateListener(StateListener listener) { } @Override - public void retweetStatus(long[] account_ids, long status_id) { - if (mService == null) return; + public int retweetStatus(long[] account_ids, long status_id) { + if (mService == null) return -1; try { - mService.retweetStatus(account_ids, status_id); + return mService.retweetStatus(account_ids, status_id); } catch (RemoteException e) { e.printStackTrace(); } + return -1; } @Override - public void updateStatus(long[] account_ids, String content, Location location, Uri image_uri, + public int updateStatus(long[] account_ids, String content, Location location, Uri image_uri, long in_reply_to) { - if (mService == null) return; + if (mService == null) return -1; try { - mService.updateStatus(account_ids, content, location, image_uri, in_reply_to); + return mService.updateStatus(account_ids, content, location, image_uri, in_reply_to); } catch (RemoteException e) { e.printStackTrace(); } - + return -1; } public interface StateListener { diff --git a/src/org/mariotaku/twidere/util/StatusItemHolder.java b/src/org/mariotaku/twidere/util/StatusItemHolder.java index 8cf1c417..e4cd0036 100644 --- a/src/org/mariotaku/twidere/util/StatusItemHolder.java +++ b/src/org/mariotaku/twidere/util/StatusItemHolder.java @@ -10,7 +10,7 @@ public class StatusItemHolder { public ImageView profile_image, color_indicator; - public TextView user_name, screen_name, tweet_content, tweet_time, in_reply_to; + public TextView user_name, screen_name, text, tweet_time, in_reply_to; public long status_id, account_id; private View content, gap_text; private boolean is_gap; @@ -22,7 +22,7 @@ public StatusItemHolder(View view) { color_indicator = (ImageView) view.findViewById(R.id.color); user_name = (TextView) view.findViewById(R.id.user_name); screen_name = (TextView) view.findViewById(R.id.screen_name); - tweet_content = (TextView) view.findViewById(R.id.text); + text = (TextView) view.findViewById(R.id.text); tweet_time = (TextView) view.findViewById(R.id.tweet_time); in_reply_to = (TextView) view.findViewById(R.id.in_reply_to); diff --git a/src/org/mariotaku/twidere/widget/StatusesAdapter.java b/src/org/mariotaku/twidere/widget/StatusesAdapter.java index 24d8a84c..ed7f8856 100644 --- a/src/org/mariotaku/twidere/widget/StatusesAdapter.java +++ b/src/org/mariotaku/twidere/widget/StatusesAdapter.java @@ -14,16 +14,17 @@ import android.database.Cursor; import android.graphics.Color; import android.support.v4.widget.SimpleCursorAdapter; +import android.text.Html; import android.view.View; import android.view.ViewGroup; public class StatusesAdapter extends SimpleCursorAdapter { - private final static String[] mFrom = new String[] { Statuses.NAME, Statuses.TEXT }; - private final static int[] mTo = new int[] { R.id.user_name, R.id.text }; + private final static String[] mFrom = new String[] { Statuses.NAME}; + private final static int[] mTo = new int[] { R.id.user_name}; private boolean mDisplayProfileImage, mMultipleAccountsActivated; private LazyImageLoader mImageLoader; - private int mAccountIdIdx, mStatusIdIdx, mStatusTimestampIdx, mScreenNameIdx, + private int mAccountIdIdx, mStatusIdIdx, mStatusTimestampIdx, mScreenNameIdx, mTextIdx, mProfileImageUrlIdx, mIsRetweetIdx, mIsFavoriteIdx, mIsGapIdx, mHasLocationIdx, mHasMediaIdx, mInReplyToStatusIdIdx, mInReplyToScreennameIdx; @@ -55,6 +56,7 @@ public void bindView(View view, Context context, Cursor cursor) { if (!is_gap) { String screen_name = cursor.getString(mScreenNameIdx); + String text = cursor.getString(mTextIdx); String profile_image_url = cursor.getString(mProfileImageUrlIdx); boolean is_retweet = cursor.getInt(mIsRetweetIdx) == 1; boolean is_favorite = cursor.getInt(mIsFavoriteIdx) == 1; @@ -63,6 +65,7 @@ public void bindView(View view, Context context, Cursor cursor) { boolean is_reply = cursor.getInt(mInReplyToStatusIdIdx) != -1; holder.screen_name.setText("@" + screen_name); + holder.text.setText(Html.fromHtml(text).toString()); holder.tweet_time.setText(CommonUtils.formatToShortTimeString(context, cursor.getLong(mStatusTimestampIdx))); holder.tweet_time.setCompoundDrawablesWithIntrinsicBounds(0, 0, @@ -101,6 +104,7 @@ public void changeCursor(Cursor cursor) { mStatusIdIdx = cursor.getColumnIndexOrThrow(Statuses.STATUS_ID); mStatusTimestampIdx = cursor.getColumnIndexOrThrow(Statuses.STATUS_TIMESTAMP); mScreenNameIdx = cursor.getColumnIndexOrThrow(Statuses.SCREEN_NAME); + mTextIdx = cursor.getColumnIndexOrThrow(Statuses.TEXT); mProfileImageUrlIdx = cursor.getColumnIndexOrThrow(Statuses.PROFILE_IMAGE_URL); mIsRetweetIdx = cursor.getColumnIndexOrThrow(Statuses.IS_RETWEET); mIsFavoriteIdx = cursor.getColumnIndexOrThrow(Statuses.IS_FAVORITE);