diff options
Diffstat (limited to 'app/src/main/java/net/lacolaco/smileessence/World.kt')
-rw-r--r-- | app/src/main/java/net/lacolaco/smileessence/World.kt | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/app/src/main/java/net/lacolaco/smileessence/World.kt b/app/src/main/java/net/lacolaco/smileessence/World.kt new file mode 100644 index 00000000..b18522e5 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/World.kt @@ -0,0 +1,230 @@ +package net.lacolaco.smileessence + +import android.support.annotation.StringRes +import de.keyboardsurfer.android.widget.crouton.Configuration +import de.keyboardsurfer.android.widget.crouton.Crouton +import de.keyboardsurfer.android.widget.crouton.Style +import net.lacolaco.smileessence.activity.MainActivity +import net.lacolaco.smileessence.compat.Twitter4J +import net.lacolaco.smileessence.data.Account +import net.lacolaco.smileessence.data.PostState +import net.lacolaco.smileessence.entity.DirectMessage +import net.lacolaco.smileessence.entity.Event +import net.lacolaco.smileessence.entity.SavedSearch +import net.lacolaco.smileessence.entity.Tweet +import net.lacolaco.smileessence.logging.Logger +import net.lacolaco.smileessence.twitter.UserStreamListener +import net.lacolaco.smileessence.twitter.task.Accounts +import net.lacolaco.smileessence.twitter.task.Searches +import net.lacolaco.smileessence.twitter.task.Users +import net.lacolaco.smileessence.util.* +import twitter4j.TwitterStream + +import java.lang.ref.WeakReference +import java.util.* +import java.util.concurrent.ConcurrentHashMap + +/** + * World contains data that are specific to an account. + */ +class World(var account: Account) { + private val resId: Int = 0 // XXX: Fetch from Account + // XXX: Move to MainActivity + val postState = PostState() + // Timelines + private val tweets = ArrayList<Tweet>() + private val tweetNotifiers = WeakHashMap<Any, (Tweet) -> Unit>() + // Direct messages + private val directMessages = ConcurrentHashMap<Long, DirectMessage>() + private val directMessageNotifiers = WeakHashMap<Any, (DirectMessage) -> Unit>() + // Events + val events = ArrayList<Event>() + private val eventNotifiers = WeakHashMap<Any, () -> Unit>() + // Streaming APIs + private var stream: TwitterStream? = null + private var userStreamListener: UserStreamListener? = null + // Lists + val listSubscriptions = Collections.newSetFromMap(ConcurrentHashMap<String, Boolean>()) + // Mute + private val muteUserIds = Collections.newSetFromMap(ConcurrentHashMap<Long, Boolean>()) + // Saved searches + val savedSearches = HashMap<Long, SavedSearch>() + // Notification + private var mainActivity: WeakReference<MainActivity>? = null + private var isMainActivityActive: Boolean = false + + // Timelines + + @Synchronized + fun addTimeline(key: Any, notify: (Tweet) -> Unit) { + for (tweet in tweets) + notify(tweet) + tweetNotifiers.put(key, notify) + } + + @Synchronized + fun addTweet(tweet: Tweet) { + tweets.add(tweet) + tweetNotifiers.forEach { o, c -> c(tweet) } + } + + @Synchronized + fun addTweetAll(ts: Collection<Tweet>) { + tweets.addAll(ts) + for (tweet in ts) { + tweetNotifiers.forEach { o, c -> c(tweet) } + } + } + + // Direct messages + + @Synchronized + fun addDirectMessageTimeline(key: Any, notify: (DirectMessage) -> Unit) { + directMessageNotifiers.put(key, notify) + } + + fun addDirectMessage(entity: DirectMessage) { + if (directMessages.put(entity.id, entity) == null) + directMessageNotifiers.forEach { o, c -> c(entity) } + } + + // Events + + @Synchronized + fun addEventNotifier(key: Any, notify: () -> Unit) { + eventNotifiers.put(key, notify) + } + + fun addEvent(e: Event) { + events.add(e) + eventNotifiers.forEach { o, a -> a() } + } + + // Streaming APIs + + fun setupStreaming() { + if (stream == null) { + stream = account.twitterStream + userStreamListener = UserStreamListener(this) + Twitter4J.twitterStreamAddListener(stream!!, userStreamListener!!) + stream!!.addConnectionLifeCycleListener(userStreamListener) + stream!!.user() + } + } + + val isStreaming: Boolean + get() = stream != null && userStreamListener!!.isConnected + + // Lists + + fun refreshListSubscriptions(): BackgroundTask<List<String>, Void> { + return Users.GetManyTask(account) + .onDone { lists -> + listSubscriptions.clear() + listSubscriptions.addAll(lists) + } + // .onFail(x -> { }) // TODO: error message? + .execute() + } + + fun addListSubscription(fullName: String): Boolean { + return listSubscriptions.add(fullName) + } + + fun removeListSubscription(fullName: String): Boolean { + return listSubscriptions.remove(fullName) + } + + // Mute + + fun refreshUserMuteList(): List<BackgroundTask<*, *>> { + val tasks = ArrayList<BackgroundTask<*, *>>() + tasks.add(Accounts.BlockIDsTask(account).onDone { muteUserIds.addAll(it) }.execute()) + tasks.add(Accounts.MutesIDsTask(account).onDone { muteUserIds.addAll(it) }.execute()) + return tasks + } + + fun isMutedUserListContains(id: Long): Boolean { + return muteUserIds.contains(id) + } + + // Saved search queries + + fun refreshSavedSearches(): BackgroundTask<List<SavedSearch>, Void> { + return Searches.GetAllSavedSearchesTask(account).onDone { ssl -> + savedSearches.clear() + for (ss in ssl) + savedSearches.put(ss.id, ss) + }.execute() + } + + // Notifications + + fun setMainActivity(activity: MainActivity) { + mainActivity = WeakReference(activity) + } + + fun setMainActivityActive(yes: Boolean) { + isMainActivityActive = yes + } + + fun notify(text: String) { + doNotify(NotificationType.INFO, text) + } + + fun notify(@StringRes resId: Int, vararg formatArgs: Any) { + doNotify(NotificationType.INFO, resId, *formatArgs) + } + + fun notifyError(text: String) { + doNotify(NotificationType.ALERT, text) + } + + fun notifyError(@StringRes resId: Int, vararg formatArgs: Any) { + doNotify(NotificationType.ALERT, resId, *formatArgs) + } + + private fun doNotify(type: NotificationType, @StringRes resId: Int, vararg formatArgs: Any) { + val context = mainActivity!!.get() + if (context != null) { + val text = context.getString(resId, *formatArgs) + doNotify(type, text) + } else { + Logger.debug("MainActivity is dead") + } + } + + private fun doNotify(type: NotificationType, text: String) { + val activity = mainActivity!!.get() + if (activity == null || activity.isFinishing) { + Logger.debug(String.format("notify(log): %s", text)) + } else { + UIHandler().post { + if (isMainActivityActive) { + Logger.debug(String.format("notify(crouton): %s", text)) + val conf = Configuration.Builder() + conf.setDuration(NOTIFICATION_DURATION) + val bstyle = Style.Builder() + bstyle.setConfiguration(conf.build()) + bstyle.setBackgroundColorValue(if (type == NotificationType.ALERT) + Style.holoRedLight + else + Style.holoBlueLight) + Crouton.makeText(activity, text, bstyle.build()).show() + } else { + Logger.debug(String.format("notify(toast): %s", text)) + Application.toast(text) + } + } + } + } + + internal enum class NotificationType { + INFO, + ALERT + } + + companion object { + private val NOTIFICATION_DURATION = 1000 + } +} |