2019-10-10 00:38:43 +00:00
package org.thoughtcrime.securesms.loki
import android.content.Context
import android.database.ContentObserver
2019-10-11 01:37:45 +00:00
import android.text.TextUtils
2019-10-10 00:38:43 +00:00
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.functional.bind
import nl.komponents.kovenant.functional.map
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.database.DatabaseContentProviders
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.groups.GroupManager
2020-01-31 01:50:25 +00:00
import org.thoughtcrime.securesms.loki.redesign.messaging.LokiPublicChatPoller
2019-10-10 00:38:43 +00:00
import org.thoughtcrime.securesms.util.TextSecurePreferences
2019-10-11 01:37:45 +00:00
import org.thoughtcrime.securesms.util.Util
2019-10-15 02:39:17 +00:00
import org.whispersystems.signalservice.loki.api.LokiPublicChat
2019-10-10 00:38:43 +00:00
class LokiPublicChatManager ( private val context : Context ) {
2019-10-15 02:39:17 +00:00
private var chats = mutableMapOf < Long , LokiPublicChat > ( )
private val pollers = mutableMapOf < Long , LokiPublicChatPoller > ( )
2019-10-10 00:38:43 +00:00
private val observers = mutableMapOf < Long , ContentObserver > ( )
private var isPolling = false
public fun startPollersIfNeeded ( ) {
refreshChatsAndPollers ( )
for ( ( threadId , chat ) in chats ) {
2019-10-15 02:39:17 +00:00
val poller = pollers [ threadId ] ?: LokiPublicChatPoller ( context , chat )
2019-10-10 00:38:43 +00:00
poller . startIfNeeded ( )
listenToThreadDeletion ( threadId )
if ( ! pollers . containsKey ( threadId ) ) { pollers [ threadId ] = poller }
}
isPolling = true
}
public fun stopPollers ( ) {
pollers . values . forEach { it . stop ( ) }
isPolling = false
}
2019-10-15 02:39:17 +00:00
public fun addChat ( server : String , channel : Long ) : Promise < LokiPublicChat , Exception > {
val groupChatAPI = ApplicationContext . getInstance ( context ) . lokiPublicChatAPI ?: return Promise . ofFail ( IllegalStateException ( " LokiPublicChatAPI is not set! " ) )
2019-10-10 00:38:43 +00:00
return groupChatAPI . getAuthToken ( server ) . bind {
groupChatAPI . getChannelInfo ( channel , server )
} . map {
addChat ( server , channel , it )
}
}
2019-10-15 02:39:17 +00:00
public fun addChat ( server : String , channel : Long , name : String ) : LokiPublicChat {
val chat = LokiPublicChat ( channel , server , name , true )
2019-12-11 23:07:17 +00:00
var threadID = GroupManager . getPublicChatThreadId ( chat . id , context )
2019-10-10 00:38:43 +00:00
// Create the group if we don't have one
if ( threadID < 0 ) {
2019-12-11 23:07:17 +00:00
val result = GroupManager . createPublicChatGroup ( chat . id , context , null , chat . displayName )
2019-10-10 00:38:43 +00:00
threadID = result . threadId
}
2019-10-15 02:39:17 +00:00
DatabaseFactory . getLokiThreadDatabase ( context ) . setPublicChat ( chat , threadID )
2019-10-10 00:38:43 +00:00
// Set our name on the server
2019-10-11 01:37:45 +00:00
val displayName = TextSecurePreferences . getProfileName ( context )
if ( ! TextUtils . isEmpty ( displayName ) ) {
2019-10-15 03:32:23 +00:00
ApplicationContext . getInstance ( context ) . lokiPublicChatAPI ?. setDisplayName ( displayName , server )
2019-10-11 01:37:45 +00:00
}
// Start polling
Util . runOnMain { startPollersIfNeeded ( ) }
2019-10-10 00:38:43 +00:00
return chat
}
private fun refreshChatsAndPollers ( ) {
2019-10-15 02:39:17 +00:00
val chatsInDB = DatabaseFactory . getLokiThreadDatabase ( context ) . getAllPublicChats ( )
2019-10-10 00:38:43 +00:00
val removedChatThreadIds = chats . keys . filter { ! chatsInDB . keys . contains ( it ) }
removedChatThreadIds . forEach { pollers . remove ( it ) ?. stop ( ) }
// Only append to chats if we have a thread for the chat
2019-12-11 23:07:17 +00:00
chats = chatsInDB . filter { GroupManager . getPublicChatThreadId ( it . value . id , context ) > - 1 } . toMutableMap ( )
2019-10-10 00:38:43 +00:00
}
private fun listenToThreadDeletion ( threadID : Long ) {
if ( threadID < 0 || observers [ threadID ] != null ) { return }
val observer = createDeletionObserver ( threadID , Runnable {
val chat = chats [ threadID ]
// Reset last message cache
if ( chat != null ) {
val apiDatabase = DatabaseFactory . getLokiAPIDatabase ( context )
apiDatabase . removeLastDeletionServerID ( chat . channel , chat . server )
apiDatabase . removeLastMessageServerID ( chat . channel , chat . server )
}
2019-10-15 02:39:17 +00:00
DatabaseFactory . getLokiThreadDatabase ( context ) . removePublicChat ( threadID )
2019-10-10 00:38:43 +00:00
pollers . remove ( threadID ) ?. stop ( )
observers . remove ( threadID )
startPollersIfNeeded ( )
} )
observers [ threadID ] = observer
context . applicationContext . contentResolver . registerContentObserver ( DatabaseContentProviders . Conversation . getUriForThread ( threadID ) , true , observer )
}
private fun createDeletionObserver ( threadID : Long , onDelete : Runnable ) : ContentObserver {
return object : ContentObserver ( null ) {
override fun onChange ( selfChange : Boolean ) {
super . onChange ( selfChange )
// Stop the poller if thread is deleted
try {
if ( ! DatabaseFactory . getThreadDatabase ( context ) . hasThread ( threadID ) ) {
onDelete . run ( )
context . applicationContext . contentResolver . unregisterContentObserver ( this )
}
} catch ( e : Exception ) {
// TODO: Handle
}
}
}
}
}