,
+ private val project: Project,
+ val visualMemeContent: VisualMemeContent,
) : Disposable {
+ fun clone(): Meme =
+ Meme(
+ memePlayer,
+ memePanel.clone(),
+ userEvent,
+ comparator,
+ metadata,
+ project,
+ visualMemeContent
+ )
+
class Builder(
private val visualMemeContent: VisualMemeContent,
private val audibleContent: AudibleContent?,
private val userEvent: UserEvent,
private val rootPane: JLayeredPane,
+ private val project: Project,
) {
private var notificationMode = Config.instance.notificationMode
private var notificationAnchor = Config.instance.notificationAnchor
@@ -106,6 +125,8 @@ class Meme(
userEvent,
memeComparator,
metaData,
+ project,
+ visualMemeContent,
)
}
}
@@ -129,6 +150,12 @@ class Meme(
}
}
+ override fun onClick() {
+ if (ApplicationManager.getApplication().getConfig().infoOnClick) {
+ project.memeInfoService().displayInfo(visualMemeContent)
+ }
+ }
+
override fun onDismiss() {
listeners.forEach { it.onDismiss() }
}
diff --git a/src/main/kotlin/io/unthrottled/amii/memes/MemeInfoService.kt b/src/main/kotlin/io/unthrottled/amii/memes/MemeInfoService.kt
new file mode 100644
index 00000000..332abfea
--- /dev/null
+++ b/src/main/kotlin/io/unthrottled/amii/memes/MemeInfoService.kt
@@ -0,0 +1,98 @@
+package io.unthrottled.amii.memes
+
+import com.intellij.ide.BrowserUtil
+import com.intellij.notification.Notification
+import com.intellij.notification.NotificationAction
+import com.intellij.notification.NotificationGroupManager
+import com.intellij.notification.NotificationListener
+import com.intellij.notification.NotificationType
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.project.Project
+import icons.AMIIIcons
+import io.unthrottled.amii.assets.VisualEntityRepository
+import io.unthrottled.amii.assets.VisualMemeContent
+import io.unthrottled.amii.config.getConfig
+import io.unthrottled.amii.tools.PluginMessageBundle
+import io.unthrottled.amii.tools.toOptional
+import org.intellij.lang.annotations.Language
+import java.net.URLEncoder
+
+fun Project.memeInfoService(): MemeInfoService = this.getService(MemeInfoService::class.java)
+
+class MemeInfoService(private val project: Project) {
+
+ private val notificationGroup =
+ NotificationGroupManager.getInstance()
+ .getNotificationGroup("AMII Info")
+
+ fun stopShowing() {
+ ApplicationManager.getApplication().getConfig().infoOnClick = false
+ }
+
+ fun displayInfo(visualMemeContent: VisualMemeContent) {
+ val stopShowingAction = object : NotificationAction(PluginMessageBundle.message("amii.meme.info.stop")) {
+ override fun actionPerformed(e: AnActionEvent, notification: Notification) {
+ stopShowing()
+ notification.expire()
+ }
+ }
+ val visualAssetEntity = VisualEntityRepository.instance.visualAssetEntities[visualMemeContent.id] ?: return
+ visualAssetEntity.toOptional()
+ .filter {
+ it.characters.none { character ->
+ character.name.contains("Unknown ", ignoreCase = true)
+ } &&
+ it.characters.isNotEmpty()
+ }
+ .map {
+ val animeShown = visualAssetEntity.characters
+ .map { it.anime }
+ .distinct()
+ .map { it.name }
+ val characters = visualAssetEntity.characters.map { it.name }
+ val characterPluralization = if (characters.size > 1) "s" else ""
+
+ @Language("HTML")
+ val content = """
+ | Anime: ${animeShown.joinToString(", ")}
+ | Character$characterPluralization: ${characters.joinToString(", ")}
+ |
""".trimMargin()
+
+ notificationGroup.createNotification(
+ content,
+ NotificationType.INFORMATION
+ ).addAction(
+ object : NotificationAction(PluginMessageBundle.message("amii.meme.info.search")) {
+ override fun actionPerformed(e: AnActionEvent, notification: Notification) {
+ val queryString = URLEncoder.encode(
+ "${animeShown.joinToString(" ") { "\"$it\"" }} ${characters.joinToString(" ")}",
+ Charsets.UTF_8
+ )
+ val queryParameters = "q=$queryString&oq=$queryString"
+ val searchUrl = "https://google.com/search?$queryParameters"
+ BrowserUtil.browse(searchUrl)
+ }
+ }
+ )
+ .addAction(
+ stopShowingAction
+ )
+ }.orElseGet {
+ @Language("HTML")
+ val lulDunno = """
+ |${PluginMessageBundle.message("amii.meme.info.dunno")}
+ |¯\_(ツ)_/¯
+ """.trimMargin()
+ notificationGroup.createNotification(
+ lulDunno,
+ NotificationType.INFORMATION
+ )
+ .addAction(stopShowingAction)
+ }
+ .setIcon(AMIIIcons.PLUGIN_ICON)
+ .setTitle(PluginMessageBundle.message("amii.meme.info.title"))
+ .setListener(NotificationListener.UrlOpeningListener(false))
+ .notify(project)
+ }
+}
diff --git a/src/main/kotlin/io/unthrottled/amii/memes/MemePanel.kt b/src/main/kotlin/io/unthrottled/amii/memes/MemePanel.kt
index 8f433aaf..2ab4bbca 100644
--- a/src/main/kotlin/io/unthrottled/amii/memes/MemePanel.kt
+++ b/src/main/kotlin/io/unthrottled/amii/memes/MemePanel.kt
@@ -87,6 +87,9 @@ class MemePanel(
private val memePanelSettings: MemePanelSettings,
) : HwFacadeJPanel(), Disposable, Logging {
+ fun clone(): MemePanel =
+ MemePanel(rootPane, visualMeme, memePlayer, memePanelSettings)
+
companion object {
val PANEL_LAYER: Int = JBLayeredPane.DRAG_LAYER
private const val TOTAL_FRAMES = 8
@@ -113,7 +116,7 @@ class MemePanel(
private val fadeoutAlarm = Alarm()
private val invulnerabilityAlarm = Alarm()
- private val mouseListener: AWTEventListener = createMouseLister()
+ private val mouseListener: AWTEventListener = createMouseListener()
private val memeDisplay: JComponent
init {
@@ -156,7 +159,7 @@ class MemePanel(
)
}
- private fun createMouseLister(): AWTEventListener {
+ private fun createMouseListener(): AWTEventListener {
var clickedInside = false
return AWTEventListener { event ->
if (invulnerable) return@AWTEventListener
@@ -176,6 +179,7 @@ class MemePanel(
} else if (wasInside) {
fadeoutAlarm.cancelAllRequests()
clickedInside = true
+ this.lifecycleListener.onClick()
}
}
} else if (
diff --git a/src/main/kotlin/io/unthrottled/amii/memes/MemeService.kt b/src/main/kotlin/io/unthrottled/amii/memes/MemeService.kt
index 17ca9c3e..df7196d7 100644
--- a/src/main/kotlin/io/unthrottled/amii/memes/MemeService.kt
+++ b/src/main/kotlin/io/unthrottled/amii/memes/MemeService.kt
@@ -20,6 +20,12 @@ fun Project.memeService(): MemeService = this.getService(MemeService::class.java
class MemeService(private val project: Project) {
+ fun displayLastMeme() {
+ val memeToShow = previousMeme ?: return
+
+ displayMeme(memeToShow.clone())
+ }
+
fun createMeme(
userEvent: UserEvent,
memeAssetCategory: MemeAssetCategory,
@@ -52,7 +58,8 @@ class MemeService(private val project: Project) {
memeAssets.visualMemeContent,
memeAssets.audibleMemeContent,
userEvent,
- rootPane
+ rootPane,
+ project
)
)
}
@@ -73,28 +80,34 @@ class MemeService(private val project: Project) {
)?.layeredPane
private var displayedMeme: Meme? = null
+ private var previousMeme: Meme? = null
private fun attemptToDisplayMeme(meme: Meme) {
val currentlyDisplayedMeme = displayedMeme
val comparison = currentlyDisplayedMeme?.compareTo(meme) ?: Comparison.UNKNOWN
if (comparison == Comparison.GREATER || comparison == Comparison.UNKNOWN) {
currentlyDisplayedMeme?.dismiss()
-
- // be paranoid about existing memes
- // hanging around for some reason https://github.com/ani-memes/AMII/issues/108
- getRootPane().toOptional().ifPresent { dismissAllMemesInPane(it) }
-
- showMeme(meme)
+ previousMeme = currentlyDisplayedMeme ?: previousMeme
+ displayMeme(meme)
} else {
meme.dispose()
}
}
+ private fun displayMeme(meme: Meme) {
+ // be paranoid about existing memes
+ // hanging around for some reason https://github.com/ani-memes/AMII/issues/108
+ getRootPane().toOptional().ifPresent { dismissAllMemesInPane(it) }
+
+ showMeme(meme)
+ }
+
private fun showMeme(meme: Meme) {
displayedMeme = meme
meme.addListener(
object : MemeLifecycleListener {
override fun onRemoval() {
displayedMeme = null
+ previousMeme = meme
}
}
)
diff --git a/src/main/kotlin/io/unthrottled/amii/onboarding/UpdateNotification.kt b/src/main/kotlin/io/unthrottled/amii/onboarding/UpdateNotification.kt
index 68d0490a..cfee613a 100644
--- a/src/main/kotlin/io/unthrottled/amii/onboarding/UpdateNotification.kt
+++ b/src/main/kotlin/io/unthrottled/amii/onboarding/UpdateNotification.kt
@@ -23,6 +23,8 @@ private fun buildUpdateMessage(updateAsset: String): String =
What's New?
- Added Integrated Discreet Mode
+ - Click Meme to show info!
+ - Show Previous Meme action.
- 2021.3 Build Support
- Handling vertical overflow better in settings UI
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index 7cdb11de..9a96c2ee 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -21,8 +21,10 @@
/>
+
+
@@ -95,6 +97,12 @@
description="Displays AMII's Settings">
+
+
+
Plugins" and search for "Anime Memes"
settings.general.modes.discreet-mode=羞耻设置
+amii.meme.info.title=Meme Information
+amii.meme.info.search=Search
+amii.meme.info.dunno=Sorry, I do not know the source of this asset.
+amii.meme.info.stop=Stop Showing Info
+settings.general.misc.show-info=Info On Click