Change the way the message list widget listens to changes

Also change the code to only listen for message list changes when the message list widget has been added to the home screen.
This commit is contained in:
cketti 2022-10-19 14:36:40 +02:00
parent eaa88f3c47
commit da283a7c32
7 changed files with 139 additions and 79 deletions

View file

@ -5,19 +5,32 @@ import java.util.concurrent.CopyOnWriteArraySet
class MessageListRepository(
private val messageStoreManager: MessageStoreManager
) {
private val listeners = CopyOnWriteArraySet<Pair<String, MessageListChangedListener>>()
private val globalListeners = CopyOnWriteArraySet<MessageListChangedListener>()
private val accountListeners = CopyOnWriteArraySet<Pair<String, MessageListChangedListener>>()
fun addListener(listener: MessageListChangedListener) {
globalListeners.add(listener)
}
fun addListener(accountUuid: String, listener: MessageListChangedListener) {
listeners.add(accountUuid to listener)
accountListeners.add(accountUuid to listener)
}
fun removeListener(listener: MessageListChangedListener) {
val entries = listeners.filter { it.second == listener }.toSet()
listeners.removeAll(entries)
globalListeners.remove(listener)
val accountEntries = accountListeners.filter { it.second == listener }.toSet()
if (accountEntries.isNotEmpty()) {
accountListeners.removeAll(accountEntries)
}
}
fun notifyMessageListChanged(accountUuid: String) {
for (listener in listeners) {
for (listener in globalListeners) {
listener.onMessageListChanged()
}
for (listener in accountListeners) {
if (listener.first == accountUuid) {
listener.second.onMessageListChanged()
}

View file

@ -3,7 +3,7 @@ package com.fsck.k9
import android.app.Application
import android.content.res.Configuration
import android.content.res.Resources
import app.k9mail.ui.widget.list.MessageListWidgetProvider
import app.k9mail.ui.widget.list.MessageListWidgetManager
import com.fsck.k9.activity.MessageCompose
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.notification.NotificationChannelManager
@ -28,6 +28,7 @@ class App : Application() {
private val themeManager: ThemeManager by inject()
private val appLanguageManager: AppLanguageManager by inject()
private val notificationChannelManager: NotificationChannelManager by inject()
private val messageListWidgetManager: MessageListWidgetManager by inject()
private val appCoroutineScope: CoroutineScope = GlobalScope + Dispatchers.Main
private var appLanguageManagerInitialized = false
@ -43,7 +44,7 @@ class App : Application() {
initializeAppLanguage()
updateNotificationChannelsOnAppLanguageChanges()
themeManager.init()
MessageListWidgetProvider.init(this)
messageListWidgetManager.init()
messagingListenerProvider.listeners.forEach { listener ->
messagingController.addListener(listener)

View file

@ -1,6 +1,5 @@
package com.fsck.k9
import app.k9mail.ui.widget.list.MessageListWidgetUpdateListener
import app.k9mail.ui.widget.list.messageListWidgetModule
import com.fsck.k9.auth.createOAuthConfigurationProvider
import com.fsck.k9.backends.backendsModule
@ -24,7 +23,6 @@ private val mainAppModule = module {
MessagingListenerProvider(
listOf(
get<UnreadWidgetUpdateListener>(),
get<MessageListWidgetUpdateListener>()
)
)
}

View file

@ -3,6 +3,6 @@ package app.k9mail.ui.widget.list
import org.koin.dsl.module
val messageListWidgetModule = module {
single { MessageListWidgetUpdateListener(context = get()) }
single { MessageListWidgetManager(context = get(), messageListRepository = get(), config = get()) }
factory { MessageListLoader(preferences = get(), messageListRepository = get(), messageHelper = get()) }
}

View file

@ -0,0 +1,106 @@
package app.k9mail.ui.widget.list
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import com.fsck.k9.core.BuildConfig
import com.fsck.k9.mailstore.MessageListChangedListener
import com.fsck.k9.mailstore.MessageListRepository
import timber.log.Timber
class MessageListWidgetManager(
private val context: Context,
private val messageListRepository: MessageListRepository,
private val config: MessageListWidgetConfig,
) {
private lateinit var appWidgetManager: AppWidgetManager
private var listenerAdded = false
private val listener = MessageListChangedListener {
onMessageListChanged()
}
fun init() {
appWidgetManager = AppWidgetManager.getInstance(context)
if (isAtLeastOneMessageListWidgetAdded()) {
resetMessageListWidget()
registerMessageListChangedListener()
}
}
private fun onMessageListChanged() {
try {
triggerMessageListWidgetUpdate()
} catch (e: RuntimeException) {
if (BuildConfig.DEBUG) {
throw e
} else {
Timber.e(e, "Error while updating message list widget")
}
}
}
internal fun onWidgetAdded() {
Timber.v("Message list widget added")
registerMessageListChangedListener()
}
internal fun onWidgetRemoved() {
Timber.v("Message list widget removed")
if (!isAtLeastOneMessageListWidgetAdded()) {
unregisterMessageListChangedListener()
}
}
@Synchronized
private fun registerMessageListChangedListener() {
if (!listenerAdded) {
listenerAdded = true
messageListRepository.addListener(listener)
Timber.v("Message list widget is now listening for message list changes…")
}
}
@Synchronized
private fun unregisterMessageListChangedListener() {
if (listenerAdded) {
listenerAdded = false
messageListRepository.removeListener(listener)
Timber.v("Message list widget stopped listening for message list changes.")
}
}
private fun isAtLeastOneMessageListWidgetAdded(): Boolean {
return getAppWidgetIds().isNotEmpty()
}
private fun triggerMessageListWidgetUpdate() {
val appWidgetIds = getAppWidgetIds()
if (appWidgetIds.isNotEmpty()) {
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.listView)
}
}
private fun resetMessageListWidget() {
val appWidgetIds = getAppWidgetIds()
if (appWidgetIds.isNotEmpty()) {
val intent = Intent(context, config.providerClass).apply {
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds)
}
context.sendBroadcast(intent)
}
}
private fun getAppWidgetIds(): IntArray {
val componentName = ComponentName(context, config.providerClass)
return appWidgetManager.getAppWidgetIds(componentName)
}
}

View file

@ -3,7 +3,6 @@ package app.k9mail.ui.widget.list
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.widget.RemoteViews
@ -17,7 +16,17 @@ import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import com.fsck.k9.ui.R as UiR
open class MessageListWidgetProvider : AppWidgetProvider() {
open class MessageListWidgetProvider : AppWidgetProvider(), KoinComponent {
private val messageListWidgetManager: MessageListWidgetManager by inject()
override fun onEnabled(context: Context) {
messageListWidgetManager.onWidgetAdded()
}
override fun onDisabled(context: Context) {
messageListWidgetManager.onWidgetRemoved()
}
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId)
@ -73,36 +82,4 @@ open class MessageListWidgetProvider : AppWidgetProvider() {
}
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE)
}
companion object : KoinComponent {
private val messageListWidgetConfig: MessageListWidgetConfig by inject()
fun init(context: Context) {
resetMessageListWidget(context)
}
private fun resetMessageListWidget(context: Context) {
val appWidgetManager = AppWidgetManager.getInstance(context)
val providerClass = messageListWidgetConfig.providerClass
val componentName = ComponentName(context, providerClass)
val appWidgetIds = appWidgetManager.getAppWidgetIds(componentName)
val intent = Intent(context, providerClass).apply {
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds)
}
context.sendBroadcast(intent)
}
fun triggerMessageListWidgetUpdate(context: Context) {
val appWidgetManager = AppWidgetManager.getInstance(context)
val providerClass = messageListWidgetConfig.providerClass
val componentName = ComponentName(context, providerClass)
val appWidgetIds = appWidgetManager.getAppWidgetIds(componentName)
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.listView)
}
}
}

View file

@ -1,35 +0,0 @@
package app.k9mail.ui.widget.list
import android.content.Context
import com.fsck.k9.Account
import com.fsck.k9.controller.SimpleMessagingListener
import com.fsck.k9.core.BuildConfig
import com.fsck.k9.mail.Message
import timber.log.Timber
class MessageListWidgetUpdateListener(private val context: Context) : SimpleMessagingListener() {
private fun updateMailListWidget() {
try {
MessageListWidgetProvider.triggerMessageListWidgetUpdate(context)
} catch (e: RuntimeException) {
if (BuildConfig.DEBUG) {
throw e
} else {
Timber.e(e, "Error while updating message list widget")
}
}
}
override fun synchronizeMailboxRemovedMessage(account: Account, folderServerId: String, messageServerId: String) {
updateMailListWidget()
}
override fun synchronizeMailboxNewMessage(account: Account, folderServerId: String, message: Message) {
updateMailListWidget()
}
override fun folderStatusChanged(account: Account, folderId: Long) {
updateMailListWidget()
}
}