mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[feature suggestion] don't leak notifications with the project
Disposing alarm doesn't cancel delay which is attached to the application level coroutine scope by default; thus it waits for 10 seconds and might prevent test for leaked project perform normally ^KTIJ-31624 fixed GitOrigin-RevId: 8879b47391699175fb8440465444c959f87da077
This commit is contained in:
committed by
intellij-monorepo-bot
parent
6c2b4a6022
commit
93e897da83
+3
-2
@@ -11,6 +11,7 @@ import com.intellij.openapi.editor.ex.EditorEventMulticasterEx
|
||||
import com.intellij.openapi.editor.ex.FocusChangeListener
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.project.Project
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import training.featuresSuggester.actions.Action
|
||||
import training.featuresSuggester.actions.EditorFocusGainedAction
|
||||
import training.featuresSuggester.settings.FeatureSuggesterSettings
|
||||
@@ -19,7 +20,7 @@ import training.featuresSuggester.ui.NotificationSuggestionPresenter
|
||||
import training.featuresSuggester.ui.SuggestionPresenter
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
internal class FeatureSuggestersManager(private val project: Project) : Disposable {
|
||||
internal class FeatureSuggestersManager(private val project: Project, private val coroutineScope: CoroutineScope) : Disposable {
|
||||
private val suggestionPresenter: SuggestionPresenter = NotificationSuggestionPresenter()
|
||||
|
||||
init {
|
||||
@@ -56,7 +57,7 @@ internal class FeatureSuggestersManager(private val project: Project) : Disposab
|
||||
if (suggestion is PopupSuggestion) {
|
||||
suggester.logStatisticsThatSuggestionIsFound(suggestion)
|
||||
if (suggester.isEnabled() && (SuggestingUtils.forceShowSuggestions || suggester.isSuggestionNeeded())) {
|
||||
suggestionPresenter.showSuggestion(project, suggestion, disposable = this)
|
||||
suggestionPresenter.showSuggestion(project, suggestion, coroutineScope = coroutineScope)
|
||||
fireSuggestionFound(suggestion)
|
||||
FeatureSuggesterSettings.instance().updateSuggestionShownTime(suggestion.suggesterId)
|
||||
}
|
||||
|
||||
+34
-17
@@ -8,16 +8,16 @@ import com.intellij.notification.Notification
|
||||
import com.intellij.notification.NotificationGroup
|
||||
import com.intellij.notification.NotificationGroupManager
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.components.ComponentManagerEx
|
||||
import com.intellij.openapi.application.asContextElement
|
||||
import com.intellij.openapi.components.serviceAsync
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.util.Alarm
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.*
|
||||
import training.featuresSuggester.DocumentationSuggestion
|
||||
import training.featuresSuggester.FeatureSuggesterBundle
|
||||
import training.featuresSuggester.PopupSuggestion
|
||||
@@ -26,7 +26,7 @@ import training.featuresSuggester.settings.FeatureSuggesterSettings
|
||||
import training.featuresSuggester.statistics.FeatureSuggesterStatistics
|
||||
|
||||
internal interface SuggestionPresenter {
|
||||
fun showSuggestion(project: Project, suggestion: PopupSuggestion, disposable: Disposable)
|
||||
fun showSuggestion(project: Project, suggestion: PopupSuggestion, coroutineScope: CoroutineScope)
|
||||
}
|
||||
|
||||
@Suppress("DialogTitleCapitalization")
|
||||
@@ -34,34 +34,42 @@ internal class NotificationSuggestionPresenter : SuggestionPresenter {
|
||||
private val notificationGroup: NotificationGroup = NotificationGroupManager.getInstance()
|
||||
.getNotificationGroup("IDE Feature Suggester")
|
||||
|
||||
override fun showSuggestion(project: Project, suggestion: PopupSuggestion, disposable: Disposable) {
|
||||
override fun showSuggestion(project: Project, suggestion: PopupSuggestion, coroutineScope: CoroutineScope) {
|
||||
val notification = notificationGroup.createNotification(
|
||||
title = FeatureSuggesterBundle.message("notification.title"),
|
||||
content = suggestion.message,
|
||||
type = NotificationType.INFORMATION
|
||||
)
|
||||
|
||||
val expireJob = coroutineScope.launch(Dispatchers.EDT + ModalityState.any().asContextElement(), start = CoroutineStart.LAZY) {
|
||||
if (!notification.isExpired) {
|
||||
delay(10_000)
|
||||
notification.expire()
|
||||
}
|
||||
}
|
||||
|
||||
when (suggestion) {
|
||||
is TipSuggestion -> {
|
||||
val action = createShowTipAction(project, notification, suggestion)
|
||||
val action = createShowTipAction(project, notification, suggestion, coroutineScope, expireJob)
|
||||
if (action != null) {
|
||||
notification.addAction(action)
|
||||
}
|
||||
}
|
||||
is DocumentationSuggestion -> {
|
||||
notification.addAction(createGoToDocumentationAction(notification, suggestion))
|
||||
notification.addAction(createGoToDocumentationAction(notification, suggestion, expireJob))
|
||||
}
|
||||
}
|
||||
notification.addAction(createDontSuggestAction(notification, suggestion))
|
||||
notification.addAction(createDontSuggestAction(notification, suggestion, expireJob))
|
||||
|
||||
notification.notify(project)
|
||||
Alarm(disposable).addRequest(notification::expire, 10000, ModalityState.any())
|
||||
expireJob.start()
|
||||
FeatureSuggesterStatistics.logNotificationShowed(suggestion.suggesterId)
|
||||
}
|
||||
|
||||
private fun createDontSuggestAction(notification: Notification, suggestion: PopupSuggestion): AnAction {
|
||||
private fun createDontSuggestAction(notification: Notification, suggestion: PopupSuggestion, expireJob: Job): AnAction {
|
||||
return object : AnAction(FeatureSuggesterBundle.message("notification.dont.suggest")) {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
expireJob.cancel()
|
||||
val settings = FeatureSuggesterSettings.instance()
|
||||
settings.setEnabled(suggesterId = suggestion.suggesterId, enabled = false)
|
||||
notification.hideBalloon()
|
||||
@@ -70,7 +78,7 @@ internal class NotificationSuggestionPresenter : SuggestionPresenter {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createGoToDocumentationAction(notification: Notification, suggestion: DocumentationSuggestion): AnAction {
|
||||
private fun createGoToDocumentationAction(notification: Notification, suggestion: DocumentationSuggestion, expireJob: Job): AnAction {
|
||||
return object : AnAction(
|
||||
FeatureSuggesterBundle.message(
|
||||
"notification.open.help",
|
||||
@@ -78,6 +86,7 @@ internal class NotificationSuggestionPresenter : SuggestionPresenter {
|
||||
)
|
||||
) {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
expireJob.cancel()
|
||||
BrowserUtil.open(suggestion.documentURL)
|
||||
notification.hideBalloon()
|
||||
FeatureSuggesterStatistics.logNotificationLearnMore(suggestion.suggesterId)
|
||||
@@ -85,14 +94,22 @@ internal class NotificationSuggestionPresenter : SuggestionPresenter {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createShowTipAction(project: Project, notification: Notification, suggestion: TipSuggestion): AnAction? {
|
||||
private fun createShowTipAction(
|
||||
project: Project,
|
||||
notification: Notification,
|
||||
suggestion: TipSuggestion,
|
||||
coroutineScope: CoroutineScope,
|
||||
expireJob: Job,
|
||||
): AnAction? {
|
||||
val tip = TipAndTrickBean.findById(suggestion.suggestingTipId) ?: return null
|
||||
return object : AnAction(FeatureSuggesterBundle.message("notification.learn.more")) {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
(project as ComponentManagerEx).getCoroutineScope().launch {
|
||||
TipAndTrickManager.getInstance().showTipDialog(project, tip)
|
||||
notification.hideBalloon()
|
||||
FeatureSuggesterStatistics.logNotificationLearnMore(suggestion.suggesterId)
|
||||
expireJob.cancel()
|
||||
notification.hideBalloon()
|
||||
FeatureSuggesterStatistics.logNotificationLearnMore(suggestion.suggesterId)
|
||||
|
||||
coroutineScope.launch {
|
||||
serviceAsync<TipAndTrickManager>().showTipDialog(project, tip)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user