diff --git a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/Activity.java b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/Activity.java index be66f82be..d0ec50749 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/Activity.java +++ b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/Activity.java @@ -25,7 +25,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.NonNull; import android.support.annotation.StringDef; -import android.text.TextUtils; import com.bluelinelabs.logansquare.JsonMapper; import com.bluelinelabs.logansquare.LoganSquare; @@ -248,34 +247,6 @@ public class Activity extends TwitterResponseObject implements TwitterResponse, } } - public static Activity fromMention(@NonNull String accountId, @NonNull Status status) { - final Activity activity = new Activity(); - - activity.maxPosition = activity.minPosition = status.getId(); - activity.maxSortPosition = activity.minSortPosition = status.getSortId(); - activity.createdAt = status.getCreatedAt(); - - if (TextUtils.equals(status.getInReplyToUserId(), accountId)) { - activity.action = Action.REPLY; - activity.targetStatuses = new Status[]{status}; - - //TODO set target statuses (in reply to status) - activity.targetObjectStatuses = new Status[0]; - } else if (status.quotedStatus != null && TextUtils.equals(status.quotedStatus.user.getId(), - accountId)) { - activity.action = Action.QUOTE; - activity.targetStatuses = new Status[]{status}; - activity.targetObjectStatuses = new Status[0]; - } else { - activity.action = Action.MENTION; - activity.targetUsers = new User[0]; - activity.targetObjectStatuses = new Status[]{status}; - } - activity.sourcesSize = 1; - activity.sources = new User[]{status.getUser()}; - return activity; - } - @StringDef({Action.FAVORITE, Action.FOLLOW, Action.MENTION, Action.REPLY, Action.RETWEET, Action.LIST_MEMBER_ADDED, Action.LIST_CREATED, Action.FAVORITED_RETWEET, Action.RETWEETED_RETWEET, Action.QUOTE, Action.RETWEETED_MENTION, diff --git a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/Warning.java b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/Warning.java index 4d799fbe3..18a16b334 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/Warning.java +++ b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/model/Warning.java @@ -21,6 +21,7 @@ package org.mariotaku.microblog.library.twitter.model; +import com.bluelinelabs.logansquare.annotation.JsonField; import com.bluelinelabs.logansquare.annotation.JsonObject; /** @@ -28,4 +29,31 @@ import com.bluelinelabs.logansquare.annotation.JsonObject; */ @JsonObject public class Warning { + @JsonField(name = "code") + String code; + @JsonField(name = "message") + String message; + @JsonField(name = "percent_full") + int percentFull; + + public String getCode() { + return code; + } + + public String getMessage() { + return message; + } + + public int getPercentFull() { + return percentFull; + } + + @Override + public String toString() { + return "Warning{" + + "code='" + code + '\'' + + ", message='" + message + '\'' + + ", percentFull=" + percentFull + + '}'; + } } diff --git a/twidere/src/debug/kotlin/org/mariotaku/twidere/util/stetho/UserStreamDumper.kt b/twidere/src/debug/kotlin/org/mariotaku/twidere/util/stetho/UserStreamDumper.kt index 839cc7f6a..b1516c900 100644 --- a/twidere/src/debug/kotlin/org/mariotaku/twidere/util/stetho/UserStreamDumper.kt +++ b/twidere/src/debug/kotlin/org/mariotaku/twidere/util/stetho/UserStreamDumper.kt @@ -28,12 +28,17 @@ import org.apache.commons.cli.GnuParser import org.apache.commons.cli.Options import org.apache.commons.cli.ParseException import org.mariotaku.microblog.library.twitter.TwitterUserStream -import org.mariotaku.microblog.library.twitter.UserStreamCallback -import org.mariotaku.microblog.library.twitter.model.* +import org.mariotaku.microblog.library.twitter.model.Activity +import org.mariotaku.microblog.library.twitter.model.DirectMessage +import org.mariotaku.microblog.library.twitter.model.Status import org.mariotaku.twidere.extension.model.getCredentials import org.mariotaku.twidere.extension.model.newMicroBlogInstance +import org.mariotaku.twidere.model.ActivityTitleSummaryMessage import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.model.util.AccountUtils +import org.mariotaku.twidere.model.util.ParcelableActivityUtils +import org.mariotaku.twidere.util.dagger.DependencyHolder +import org.mariotaku.twidere.util.streaming.TimelineStreamCallback /** * Created by mariotaku on 2017/3/9. @@ -44,12 +49,16 @@ class UserStreamDumper(val context: Context) : DumperPlugin { val parser = GnuParser() val options = Options() options.addRequiredOption("a", "account", true, "Account key") + options.addOption("t", "timeline", false, "Include timeline") + options.addOption("i", "interactions", false, "Include interactions") val cmdLine = try { parser.parse(options, dumpContext.argsAsList.toTypedArray()) } catch (e: ParseException) { throw DumpException(e.message) } - + val manager = DependencyHolder.get(context).userColorNameManager + val includeTimeline = cmdLine.hasOption("timeline") + val includeInteractions = cmdLine.hasOption("interactions") val accountKey = UserKey.valueOf(cmdLine.getOptionValue("account")) val am = AccountManager.get(context) val account = AccountUtils.findByAccountKey(am, accountKey) ?: return @@ -58,17 +67,30 @@ class UserStreamDumper(val context: Context) : DumperPlugin { cls = TwitterUserStream::class.java) dumpContext.stdout.println("Beginning user stream...") dumpContext.stdout.flush() - val callback = object : UserStreamCallback() { + val callback = object : TimelineStreamCallback(accountKey.id) { override fun onException(ex: Throwable): Boolean { ex.printStackTrace(dumpContext.stderr) dumpContext.stderr.flush() return true } - override fun onStatus(status: Status): Boolean { - dumpContext.stdout.println("Status: @${status.user.screenName}: ${status.text.trim('\n')}") + override fun onHomeTimeline(status: Status) { + if (!includeTimeline && includeInteractions) return + dumpContext.stdout.println("Home: @${status.user.screenName}: ${status.text.trim('\n')}") + dumpContext.stdout.flush() + } + + override fun onActivityAboutMe(activity: Activity) { + if (!includeInteractions && includeTimeline) return + val pActivity = ParcelableActivityUtils.fromActivity(activity, accountKey) + val message = ActivityTitleSummaryMessage.get(context, manager, pActivity, pActivity.sources, 0, + true, true) + if (message != null) { + dumpContext.stdout.println("Activity: ${message.title}: ${message.summary}") + } else { + dumpContext.stdout.println("Activity unsupported: ${activity.action}") + } dumpContext.stdout.flush() - return true } override fun onDirectMessage(directMessage: DirectMessage): Boolean { @@ -76,38 +98,9 @@ class UserStreamDumper(val context: Context) : DumperPlugin { dumpContext.stdout.flush() return true } - - override fun onStatusDeleted(event: DeletionEvent): Boolean { - dumpContext.stdout.println("Status deleted: ${event.id}") - dumpContext.stdout.flush() - return true - } - - override fun onDirectMessageDeleted(event: DeletionEvent): Boolean { - dumpContext.stdout.println("Message deleted: ${event.id}") - dumpContext.stdout.flush() - return true - } - - override fun onFriendList(friendIds: Array): Boolean { - dumpContext.stdout.println("Friends list: ${friendIds.size} in total") - dumpContext.stdout.flush() - return true - } - - override fun onFavorite(source: User, target: User, targetStatus: Status): Boolean { - dumpContext.stdout.println("Favorited: @${source.screenName} -> ${targetStatus.text.trim('\n')}") - dumpContext.stdout.flush() - return true - } - - override fun onUnhandledEvent(obj: TwitterStreamObject, json: String) { - dumpContext.stdout.println("Unhandled: ${obj.determine()} = $json") - dumpContext.stdout.flush() - } } try { - userStream.getUserStream(callback) + userStream.getUserStream("user", callback) } catch (e: Exception) { e.printStackTrace(dumpContext.stderr) } diff --git a/twidere/src/main/java/org/mariotaku/microblog/library/twitter/TwitterUserStream.java b/twidere/src/main/java/org/mariotaku/microblog/library/twitter/TwitterUserStream.java index f49b39203..4b9105680 100644 --- a/twidere/src/main/java/org/mariotaku/microblog/library/twitter/TwitterUserStream.java +++ b/twidere/src/main/java/org/mariotaku/microblog/library/twitter/TwitterUserStream.java @@ -19,9 +19,7 @@ package org.mariotaku.microblog.library.twitter; -import org.mariotaku.microblog.library.MicroBlogException; import org.mariotaku.restfu.annotation.method.GET; -import org.mariotaku.restfu.callback.RawCallback; /** * Created by mariotaku on 15/5/26. @@ -29,6 +27,6 @@ import org.mariotaku.restfu.callback.RawCallback; public interface TwitterUserStream { @GET("/user.json") - void getUserStream(UserStreamCallback callback); + void getUserStream(String with, UserStreamCallback callback); } diff --git a/twidere/src/main/java/org/mariotaku/microblog/library/twitter/UserStreamCallback.java b/twidere/src/main/java/org/mariotaku/microblog/library/twitter/UserStreamCallback.java index d9c597e6c..0661101dd 100644 --- a/twidere/src/main/java/org/mariotaku/microblog/library/twitter/UserStreamCallback.java +++ b/twidere/src/main/java/org/mariotaku/microblog/library/twitter/UserStreamCallback.java @@ -29,11 +29,13 @@ import org.mariotaku.microblog.library.MicroBlogException; import org.mariotaku.microblog.library.twitter.model.DeletionEvent; import org.mariotaku.microblog.library.twitter.model.DirectMessage; import org.mariotaku.microblog.library.twitter.model.Status; -import org.mariotaku.microblog.library.twitter.model.StatusFavoriteEvent; +import org.mariotaku.microblog.library.twitter.model.StatusTargetObjectEvent; +import org.mariotaku.microblog.library.twitter.model.StreamEvent; import org.mariotaku.microblog.library.twitter.model.TwitterStreamObject; import org.mariotaku.microblog.library.twitter.model.TwitterStreamObject.Type; import org.mariotaku.microblog.library.twitter.model.User; import org.mariotaku.microblog.library.twitter.model.UserList; +import org.mariotaku.microblog.library.twitter.model.UserListTargetObjectEvent; import org.mariotaku.microblog.library.twitter.model.Warning; import org.mariotaku.microblog.library.twitter.util.CRLFLineReader; import org.mariotaku.restfu.callback.RawCallback; @@ -41,6 +43,7 @@ import org.mariotaku.restfu.http.HttpResponse; import java.io.IOException; import java.io.InputStreamReader; +import java.util.Date; /** * Created by mariotaku on 15/5/26. @@ -83,8 +86,8 @@ public abstract class UserStreamCallback implements RawCallback + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.microblog.library.twitter.model; + +import com.bluelinelabs.logansquare.annotation.JsonField; +import com.bluelinelabs.logansquare.annotation.JsonObject; + +import org.mariotaku.microblog.library.twitter.util.TwitterDateConverter; + +import java.util.Date; + +/** + * Created by mariotaku on 16/2/26. + */ +@JsonObject +public class StreamEvent { + @JsonField(name = "created_at", typeConverter = TwitterDateConverter.class) + Date createdAt; + @JsonField(name = "source") + User source; + @JsonField(name = "target") + User target; + + public Date getCreatedAt() { + return createdAt; + } + + public User getSource() { + return source; + } + + public User getTarget() { + return target; + } + + @Override + public String toString() { + return "StreamEvent{" + + "createdAt=" + createdAt + + ", source=" + source + + ", target=" + target + + '}'; + } +} diff --git a/twidere/src/main/java/org/mariotaku/microblog/library/twitter/model/TwitterStreamObject.java b/twidere/src/main/java/org/mariotaku/microblog/library/twitter/model/TwitterStreamObject.java index db88e11a8..17535559b 100644 --- a/twidere/src/main/java/org/mariotaku/microblog/library/twitter/model/TwitterStreamObject.java +++ b/twidere/src/main/java/org/mariotaku/microblog/library/twitter/model/TwitterStreamObject.java @@ -27,10 +27,10 @@ public class TwitterStreamObject { @JsonField(name = "limit") Limit limit; @JsonField(name = "warning") - EmptyObject warning; + Warning warning; @JsonField(name = "scrub_geo") ScrubGeo scrubGeo; - @JsonField(name = "friends") + @JsonField(name = {"friends", "friends_str"}) String[] friends; @Type @@ -38,9 +38,7 @@ public class TwitterStreamObject { // This code originally lived in AbstractStreamImplementation. // I've moved it in here to expose it as a public encapsulation of // the object type determination logic. - if (sender != null) { - return Type.SENDER; - } else if (text != null) { + if (sender == null && text != null) { return Type.STATUS; } else if (directMessage != null) { return Type.DIRECT_MESSAGE; @@ -82,14 +80,16 @@ public class TwitterStreamObject { return Type.USER_LIST_DESTROYED; case "user_update": return Type.USER_UPDATE; - case "user_delete": - return Type.USER_DELETE; - case "user_suspend": - return Type.USER_SUSPEND; case "block": return Type.BLOCK; case "unblock": return Type.UNBLOCK; + case "quoted_tweet": + return Type.QUOTED_TWEET; + case "favorited_retweet": + return Type.FAVORITED_RETWEET; + case "retweeted_retweet": + return Type.RETWEETED_RETWEET; } } return Type.UNKNOWN; @@ -119,14 +119,18 @@ public class TwitterStreamObject { return friends; } - @StringDef({Type.SENDER, Type.STATUS, Type.DIRECT_MESSAGE, Type.DELETE, Type.LIMIT, + public Warning getWarning() { + return warning; + } + + @StringDef({Type.STATUS, Type.DIRECT_MESSAGE, Type.DELETE, Type.LIMIT, Type.STALL_WARNING, Type.SCRUB_GEO, Type.FRIENDS, Type.FAVORITE, Type.UNFAVORITE, Type.FOLLOW, Type.UNFOLLOW, Type.USER_LIST_MEMBER_ADDED, Type.USER_LIST_MEMBER_DELETED, Type.USER_LIST_SUBSCRIBED, Type.USER_LIST_UNSUBSCRIBED, Type.USER_LIST_CREATED, - Type.USER_LIST_UPDATED, Type.USER_LIST_DESTROYED, Type.USER_UPDATE, Type.USER_DELETE, - Type.USER_SUSPEND, Type.BLOCK, Type.UNBLOCK, Type.DISCONNECTION, Type.UNKNOWN}) + Type.USER_LIST_UPDATED, Type.USER_LIST_DESTROYED, Type.USER_UPDATE, Type.BLOCK, + Type.UNBLOCK, Type.DISCONNECTION, Type.QUOTED_TWEET, Type.FAVORITED_RETWEET, + Type.RETWEETED_RETWEET, Type.UNKNOWN}) public @interface Type { - String SENDER = "sender"; String STATUS = "status"; String DIRECT_MESSAGE = "direct_message"; String DELETE = "delete"; @@ -146,11 +150,12 @@ public class TwitterStreamObject { String USER_LIST_UPDATED = "user_list_updated"; String USER_LIST_DESTROYED = "user_list_destroyed"; String USER_UPDATE = "user_update"; - String USER_DELETE = "user_delete"; - String USER_SUSPEND = "user_suspend"; String BLOCK = "block"; String UNBLOCK = "unblock"; String DISCONNECTION = "disconnection"; + String QUOTED_TWEET = "quoted_tweet"; + String FAVORITED_RETWEET = "favorited_retweet"; + String RETWEETED_RETWEET = "retweeted_retweet"; String UNKNOWN = "unknown"; } diff --git a/twidere/src/main/java/org/mariotaku/microblog/library/twitter/model/UserListTargetObjectEvent.java b/twidere/src/main/java/org/mariotaku/microblog/library/twitter/model/UserListTargetObjectEvent.java new file mode 100644 index 000000000..4ff839633 --- /dev/null +++ b/twidere/src/main/java/org/mariotaku/microblog/library/twitter/model/UserListTargetObjectEvent.java @@ -0,0 +1,43 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.microblog.library.twitter.model; + +import com.bluelinelabs.logansquare.annotation.JsonField; +import com.bluelinelabs.logansquare.annotation.JsonObject; + +/** + * Created by mariotaku on 16/2/26. + */ +@JsonObject +public class UserListTargetObjectEvent extends StreamEvent { + @JsonField(name = "target_object") + UserList targetObject; + + public UserList getTargetObject() { + return targetObject; + } + + @Override + public String toString() { + return "StatusTargetObjectEvent{" + + "targetObject=" + targetObject + + "} " + super.toString(); + } +} diff --git a/twidere/src/main/java/org/mariotaku/twidere/model/ActivityTitleSummaryMessage.java b/twidere/src/main/java/org/mariotaku/twidere/model/ActivityTitleSummaryMessage.java index e2f46ca9b..052b06a43 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/model/ActivityTitleSummaryMessage.java +++ b/twidere/src/main/java/org/mariotaku/twidere/model/ActivityTitleSummaryMessage.java @@ -41,7 +41,6 @@ public class ActivityTitleSummaryMessage { boolean shouldUseStarsForLikes, boolean nameFirst) { final Resources resources = context.getResources(); - boolean byFriends = false; switch (activity.action) { case Activity.Action.FOLLOW: { int typeIcon = R.drawable.ic_activity_action_follow; diff --git a/twidere/src/main/java/org/mariotaku/twidere/model/DefaultFeatures.java b/twidere/src/main/java/org/mariotaku/twidere/model/DefaultFeatures.java index 228b79b69..d4491fb3f 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/model/DefaultFeatures.java +++ b/twidere/src/main/java/org/mariotaku/twidere/model/DefaultFeatures.java @@ -43,7 +43,7 @@ public class DefaultFeatures { long twitterDirectMessageMediaLimit = 1; @JsonField(name = "twitter_direct_message_max_participants") - long twitterDirectMessageMaxParticipants = 20; + long twitterDirectMessageMaxParticipants = 50; public boolean isMediaLinkCountsInStatus() { return mediaLinkCountsInStatus; diff --git a/twidere/src/main/kotlin/org/mariotaku/microblog/library/twitter/model/InternalActivityCreator.kt b/twidere/src/main/kotlin/org/mariotaku/microblog/library/twitter/model/InternalActivityCreator.kt new file mode 100644 index 000000000..72877d447 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/microblog/library/twitter/model/InternalActivityCreator.kt @@ -0,0 +1,116 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.microblog.library.twitter.model + +import java.util.* + +/** + * Created by mariotaku on 2017/3/10. + */ + +object InternalActivityCreator { + fun status(accountId: String, status: Status): Activity { + val activity = Activity() + + activity.minPosition = status.getId() + activity.maxPosition = activity.minPosition + activity.minSortPosition = status.sortId + activity.maxSortPosition = activity.minSortPosition + activity.createdAt = status.getCreatedAt() + + if (status.getInReplyToUserId() == accountId) { + activity.action = Activity.Action.REPLY + activity.targetStatuses = arrayOf(status) + + //TODO set target statuses (in reply to status) + activity.targetObjectStatuses = arrayOfNulls(0) + } else if (status.quotedStatus?.user?.id == accountId) { + activity.action = Activity.Action.QUOTE + activity.targetStatuses = arrayOf(status) + activity.targetObjectStatuses = arrayOfNulls(0) + } else { + activity.action = Activity.Action.MENTION + activity.targetUsers = arrayOfNulls(0) + activity.targetObjectStatuses = arrayOf(status) + } + activity.sourcesSize = 1 + activity.sources = arrayOf(status.getUser()) + return activity + } + + fun retweet(status: Status): Activity { + val activity = Activity() + + activity.initBasic(status.createdAt) + + activity.action = Activity.Action.RETWEET + + activity.sources = arrayOf(status.user) + activity.targetStatuses = arrayOf(status) + activity.targetObjectStatuses = arrayOf(status.retweetedStatus) + return activity + } + + fun follow(createdAt: Date, source: User, target: User): Activity { + val activity = Activity() + + activity.initBasic(createdAt) + + activity.action = Activity.Action.FOLLOW + + activity.sources = arrayOf(source) + activity.targetUsers = arrayOf(target) + return activity + } + + fun targetStatus(action: String, createdAt: Date, source: User, target: Status): Activity { + val activity = Activity() + + activity.initBasic(createdAt) + + activity.action = action + + activity.sources = arrayOf(source) + activity.targetStatuses = arrayOf(target) + return activity + } + + fun targetObject(action: String, createdAt: Date, source: User, target: User, targetObject: UserList): Activity { + val activity = Activity() + + activity.initBasic(createdAt) + + activity.action = action + + activity.sources = arrayOf(source) + activity.targetUsers = arrayOf(target) + activity.targetObjectUserLists = arrayOf(targetObject) + return activity + } + + private fun Activity.initBasic(createdAt: Date) { + val timestamp = createdAt.time + minPosition = timestamp.toString() + maxPosition = timestamp.toString() + minSortPosition = timestamp + maxSortPosition = timestamp + this.createdAt = createdAt + } +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/model/util/ParcelableActivityUtils.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/model/util/ParcelableActivityUtils.kt index e16aa076b..445e16053 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/model/util/ParcelableActivityUtils.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/model/util/ParcelableActivityUtils.kt @@ -57,7 +57,7 @@ object ParcelableActivityUtils { return result } - fun fromActivity(activity: Activity, accountKey: UserKey, isGap: Boolean, + fun fromActivity(activity: Activity, accountKey: UserKey, isGap: Boolean = false, profileImageSize: String = "normal"): ParcelableActivity { val result = ParcelableActivity() result.account_key = accountKey diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/service/StreamingService.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/service/StreamingService.kt index 19f41f9a7..b37976ae8 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/service/StreamingService.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/service/StreamingService.kt @@ -5,7 +5,6 @@ import android.accounts.OnAccountsUpdateListener import android.app.NotificationManager import android.app.PendingIntent import android.app.Service -import android.content.ContentValues import android.content.Context import android.content.Intent import android.os.IBinder @@ -16,11 +15,6 @@ import org.mariotaku.ktextension.addOnAccountsUpdatedListenerSafe import org.mariotaku.ktextension.removeOnAccountsUpdatedListenerSafe import org.mariotaku.microblog.library.twitter.TwitterUserStream import org.mariotaku.microblog.library.twitter.UserStreamCallback -import org.mariotaku.microblog.library.twitter.model.DeletionEvent -import org.mariotaku.microblog.library.twitter.model.Status -import org.mariotaku.microblog.library.twitter.model.User -import org.mariotaku.microblog.library.twitter.model.Warning -import org.mariotaku.sqliteqb.library.Expression import org.mariotaku.twidere.BuildConfig import org.mariotaku.twidere.R import org.mariotaku.twidere.TwidereConstants.LOGTAG @@ -31,11 +25,9 @@ import org.mariotaku.twidere.model.AccountPreferences import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.model.account.cred.OAuthCredentials import org.mariotaku.twidere.model.util.AccountUtils -import org.mariotaku.twidere.provider.TwidereDataStore.* import org.mariotaku.twidere.util.DataStoreUtils import org.mariotaku.twidere.util.DebugLog import org.mariotaku.twidere.util.TwidereArrayUtils -import java.io.IOException class StreamingService : Service() { @@ -105,7 +97,7 @@ class StreamingService : Service() { callbacks.put(account.key, callback) object : Thread() { override fun run() { - twitter.getUserStream(callback) + twitter.getUserStream("user", callback) Log.d(LOGTAG, String.format("Stream %s disconnected", account.key)) callbacks.remove(account.key) updateStreamState() @@ -153,83 +145,6 @@ class StreamingService : Service() { private var statusStreamStarted: Boolean = false private val mentionsStreamStarted: Boolean = false - override fun onConnected() = true - - override fun onBlock(source: User, blockedUser: User): Boolean { - val message = String.format("%s blocked %s", source.screenName, blockedUser.screenName) - Log.d(LOGTAG, message) - return true - } - - override fun onDirectMessageDeleted(event: DeletionEvent): Boolean { - val where = Expression.equalsArgs(Messages.MESSAGE_ID).sql - val whereArgs = arrayOf(event.id) - context.contentResolver.delete(Messages.CONTENT_URI, where, whereArgs) - return true - } - - override fun onStatusDeleted(event: DeletionEvent): Boolean { - val statusId = event.id - context.contentResolver.delete(Statuses.CONTENT_URI, Expression.equalsArgs(Statuses.STATUS_ID).sql, - arrayOf(statusId)) - context.contentResolver.delete(Activities.AboutMe.CONTENT_URI, Expression.equalsArgs(Activities.STATUS_ID).sql, - arrayOf(statusId)) - return true - } - - override fun onFavorite(source: User, target: User, targetStatus: Status): Boolean { - val message = String.format("%s favorited %s's tweet: %s", source.screenName, - target.screenName, targetStatus.extendedText) - Log.d(LOGTAG, message) - return true - } - - override fun onFollow(source: User, followedUser: User): Boolean { - val message = String - .format("%s followed %s", source.screenName, followedUser.screenName) - Log.d(LOGTAG, message) - return true - } - - override fun onFriendList(friendIds: Array): Boolean { - return true - } - - override fun onScrubGeo(userId: String, upToStatusId: String): Boolean { - val resolver = context.contentResolver - - val where = Expression.and(Expression.equalsArgs(Statuses.USER_KEY), - Expression.greaterEqualsArgs(Statuses.SORT_ID)).sql - val whereArgs = arrayOf(userId, upToStatusId) - val values = ContentValues() - values.putNull(Statuses.LOCATION) - resolver.update(Statuses.CONTENT_URI, values, where, whereArgs) - return true - } - - override fun onStallWarning(warn: Warning): Boolean { - return true - } - - @Throws(IOException::class) - override fun onStatus(status: Status): Boolean { - return true - } - - override fun onUnblock(source: User, unblockedUser: User): Boolean { - val message = String.format("%s unblocked %s", source.screenName, - unblockedUser.screenName) - Log.d(LOGTAG, message) - return true - } - - override fun onUnfavorite(source: User, target: User, targetStatus: Status): Boolean { - val message = String.format("%s unfavorited %s's tweet: %s", source.screenName, - target.screenName, targetStatus.extendedText) - Log.d(LOGTAG, message) - return true - } - } companion object { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesAboutMeTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesAboutMeTask.kt index 9a91438d5..b1b9b132e 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesAboutMeTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesAboutMeTask.kt @@ -23,10 +23,7 @@ import android.content.Context import android.net.Uri import org.mariotaku.microblog.library.MicroBlog import org.mariotaku.microblog.library.MicroBlogException -import org.mariotaku.microblog.library.twitter.model.Activity -import org.mariotaku.microblog.library.twitter.model.Paging -import org.mariotaku.microblog.library.twitter.model.ResponseList -import org.mariotaku.microblog.library.twitter.model.Status +import org.mariotaku.microblog.library.twitter.model.* import org.mariotaku.twidere.annotation.AccountType import org.mariotaku.twidere.annotation.ReadPositionTag import org.mariotaku.twidere.extension.model.isOfficial @@ -73,7 +70,7 @@ class GetActivitiesAboutMeTask(context: Context) : GetActivitiesTask(context) { statuses = twitter.getMentionsTimeline(paging) } } - statuses.mapTo(activities) { Activity.fromMention(details.key.id, it) } + statuses.mapTo(activities) { InternalActivityCreator.status(details.key.id, it) } return activities } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/streaming/TimelineStreamCallback.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/streaming/TimelineStreamCallback.kt new file mode 100644 index 000000000..a84e76f9f --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/streaming/TimelineStreamCallback.kt @@ -0,0 +1,129 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.util.streaming + +import org.mariotaku.microblog.library.twitter.UserStreamCallback +import org.mariotaku.microblog.library.twitter.model.* +import java.util.* + +/** + * Created by mariotaku on 2017/3/10. + */ + +abstract class TimelineStreamCallback(val accountId: String) : UserStreamCallback() { + + private val friends = mutableSetOf() + + override final fun onFriendList(friendIds: Array): Boolean { + friends.addAll(friendIds) + return true + } + + override final fun onStatus(status: Status): Boolean { + val userId = status.user.id + if (accountId == userId || userId in friends) { + onHomeTimeline(status) + } + if (status.inReplyToUserId == accountId) { + // Reply + onActivityAboutMe(InternalActivityCreator.status(accountId, status)) + } else if (userId != accountId && status.retweetedStatus?.user?.id == accountId) { + // Retweet + onActivityAboutMe(InternalActivityCreator.retweet(status)) + } else if (status.userMentionEntities?.find { it.id == accountId } != null) { + // Mention + onActivityAboutMe(InternalActivityCreator.status(accountId, status)) + } + return true + } + + override fun onFollow(createdAt: Date, source: User, target: User): Boolean { + if (source.id == accountId) { + friends.add(target.id) + } else if (target.id == accountId) { + // Dispatch follow activity + onActivityAboutMe(InternalActivityCreator.follow(createdAt, source, target)) + } + return true + } + + override fun onFavorite(createdAt: Date, source: User, target: User, + targetObject: Status): Boolean { + if (source.id == accountId) { + // Update my favorite status + } else if (target.id == accountId) { + // Dispatch favorite activity + onActivityAboutMe(InternalActivityCreator.targetStatus(Activity.Action.FAVORITE, + createdAt, source, targetObject)) + } + return true + } + + override fun onUnfollow(createdAt: Date, source: User, followedUser: User): Boolean { + if (source.id == accountId) { + friends.remove(followedUser.id) + } + return true + } + + override fun onQuotedTweet(createdAt: Date, source: User, target: User, targetObject: Status): Boolean { + if (source.id == accountId) { + } else if (target.id == accountId) { + // Dispatch activity + onActivityAboutMe(InternalActivityCreator.targetStatus(Activity.Action.QUOTE, + createdAt, source, targetObject)) + } + return true + } + + override fun onFavoritedRetweet(createdAt: Date, source: User, target: User, targetObject: Status): Boolean { + if (source.id == accountId) { + } else if (target.id == accountId) { + // Dispatch activity + onActivityAboutMe(InternalActivityCreator.targetStatus(Activity.Action.FAVORITED_RETWEET, + createdAt, source, targetObject)) + } + return true + } + + override fun onRetweetedRetweet(createdAt: Date, source: User, target: User, targetObject: Status): Boolean { + if (source.id == accountId) { + } else if (target.id == accountId) { + // Dispatch activity + onActivityAboutMe(InternalActivityCreator.targetStatus(Activity.Action.RETWEETED_RETWEET, + createdAt, source, targetObject)) + } + return true + } + + override fun onUserListMemberAddition(createdAt: Date, source: User, target: User, targetObject: UserList): Boolean { + if (source.id == accountId) { + } else if (target.id == accountId) { + // Dispatch activity + onActivityAboutMe(InternalActivityCreator.targetObject(Activity.Action.LIST_MEMBER_ADDED, + createdAt, source, target, targetObject)) + } + return true + } + + protected abstract fun onHomeTimeline(status: Status) + + protected abstract fun onActivityAboutMe(activity: Activity) +}