aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/net/lacolaco/smileessence/World.kt
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/net/lacolaco/smileessence/World.kt')
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/World.kt230
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
+ }
+}