Skip to content

Commit d832fff

Browse files
committed
feat: Create CodeXPUIManager to move the logic of displaying the gained XP label from CodeXPEventListener
1 parent 5ba55ab commit d832fff

File tree

5 files changed

+182
-147
lines changed

5 files changed

+182
-147
lines changed
Lines changed: 15 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,176 +1,52 @@
11
package com.github.ilovegamecoding.intellijcodexp.listeners
22

33
import com.github.ilovegamecoding.intellijcodexp.enums.Event
4-
import com.github.ilovegamecoding.intellijcodexp.services.CodeXPService
5-
import com.intellij.openapi.actionSystem.*
4+
import com.intellij.openapi.actionSystem.AnAction
5+
import com.intellij.openapi.actionSystem.AnActionEvent
6+
import com.intellij.openapi.actionSystem.AnActionResult
7+
import com.intellij.openapi.actionSystem.DataContext
68
import com.intellij.openapi.actionSystem.ex.AnActionListener
79
import com.intellij.openapi.application.ApplicationManager
8-
import com.intellij.openapi.diagnostic.thisLogger
9-
import com.intellij.ui.JBColor
10-
import java.awt.Color
11-
import java.awt.Font
12-
import javax.swing.JComponent
13-
import javax.swing.JLabel
14-
import kotlin.math.max
1510

1611
/**
1712
* CodeXPEventListener class
1813
*
1914
* This class listens to events from the IDE and fires them to the message bus.
2015
*/
2116
internal class CodeXPEventListener : AnActionListener {
22-
/**
23-
* Fading labels in each swing component.
24-
*/
25-
private val fadingLabels: MutableMap<JComponent, FadingLabel> = mutableMapOf()
26-
27-
/**
28-
* Current value of the fading label.
29-
*/
30-
private var currentXPGainValue: Int = 0
31-
3217
override fun afterEditorTyping(c: Char, dataContext: DataContext) {
3318
super.afterEditorTyping(c, dataContext)
3419

35-
fireEventAndDisplayXPLabel(Event.TYPING, dataContext)
20+
fireEvent(Event.TYPING, dataContext)
3621
}
3722

3823
override fun afterActionPerformed(action: AnAction, event: AnActionEvent, result: AnActionResult) {
3924
super.afterActionPerformed(action, event, result)
40-
thisLogger().warn("Action performed: ${action.templateText}")
4125

42-
when (action.templateText) { // Fire event based on action.
26+
when (action.templateText) {
4327
"Run" -> fireEvent(Event.RUN)
4428
"Save All" -> fireEvent(Event.SAVE)
4529
"Debug" -> fireEvent(Event.DEBUG)
4630
"Build Project" -> fireEvent(Event.BUILD)
4731
"Rebuild Project" -> fireEvent(Event.BUILD)
48-
"Cut" -> fireEventAndDisplayXPLabel(Event.CUT, event.dataContext)
49-
"Copy" -> fireEventAndDisplayXPLabel(Event.COPY, event.dataContext)
50-
"Paste" -> fireEventAndDisplayXPLabel(Event.PASTE, event.dataContext)
51-
"Backspace" -> fireEventAndDisplayXPLabel(Event.BACKSPACE, event.dataContext)
52-
"Tab" -> fireEventAndDisplayXPLabel(Event.TAB, event.dataContext)
53-
"Enter" -> fireEventAndDisplayXPLabel(Event.ENTER, event.dataContext)
32+
"Cut" -> fireEvent(Event.CUT, event.dataContext)
33+
"Copy" -> fireEvent(Event.COPY, event.dataContext)
34+
"Paste" -> fireEvent(Event.PASTE, event.dataContext)
35+
"Backspace" -> fireEvent(Event.BACKSPACE, event.dataContext)
36+
"Tab" -> fireEvent(Event.TAB, event.dataContext)
37+
"Enter" -> fireEvent(Event.ENTER, event.dataContext)
5438
else -> fireEvent(Event.ACTION)
5539
}
5640
}
5741

58-
/**
59-
* Fire event to the message bus and display XP label.
60-
*
61-
* @param event The event to fire.
62-
* @param dataContext The data context of the event.
63-
*/
64-
private fun fireEventAndDisplayXPLabel(event: Event, dataContext: DataContext) {
65-
fireEvent(event)
66-
displayXPLabel(event, dataContext)
67-
}
68-
6942
/**
7043
* Fire event to the message bus.
7144
*
7245
* @param event The event to fire.
73-
*/
74-
private fun fireEvent(event: Event) {
75-
ApplicationManager.getApplication().messageBus.syncPublisher(CodeXPListener.CODEXP_EVENT)
76-
.eventOccurred(event)
77-
}
78-
79-
/**
80-
* Display XP label at the caret position.
81-
*
82-
* @param event The event to fire.
8346
* @param dataContext The data context of the event.
8447
*/
85-
private fun displayXPLabel(event: Event, dataContext: DataContext) {
86-
val codeXPConfiguration =
87-
ApplicationManager.getApplication().getService(CodeXPService::class.java).state.codeXPConfiguration
88-
89-
if (!codeXPConfiguration.showGainedXP) {
90-
return
91-
}
92-
93-
val editor = CommonDataKeys.EDITOR.getData(dataContext) ?: return
94-
val caretModel = editor.caretModel
95-
val fadingLabelPosition = editor.visualPositionToXY(caretModel.visualPosition)
96-
97-
val component = editor.contentComponent
98-
99-
fadingLabels[component]?.let { fadingLabel ->
100-
fadingLabel.cancelFadeOut()
101-
currentXPGainValue = fadingLabel.value
102-
component.remove(fadingLabel)
103-
component.revalidate()
104-
component.repaint()
105-
}
106-
107-
currentXPGainValue += event.xpValue.toInt()
108-
109-
val newFadingLabel = FadingLabel(currentXPGainValue).apply {
110-
font = Font(font.fontName, Font.BOLD, editor.colorsScheme.editorFontSize)
111-
size = preferredSize
112-
val caretHeight = editor.lineHeight
113-
fadingLabelPosition.let { point ->
114-
val position = codeXPConfiguration.positionToDisplayGainedXP
115-
val xOffset = when {
116-
position.name.contains("LEFT") -> -width
117-
position.name.contains("RIGHT") -> 0
118-
else -> -width / 2
119-
}
120-
point.translate(
121-
(position.x * 4) + xOffset,
122-
position.y * (caretHeight / 2)
123-
)
124-
location = point
125-
}
126-
startFadeOut()
127-
}
128-
129-
fadingLabels[component] = newFadingLabel
130-
131-
component.add(newFadingLabel)
132-
component.revalidate()
133-
component.repaint()
134-
}
135-
136-
internal class FadingLabel(initialValue: Int) : JLabel(if (initialValue == 0) "0 xp" else "+$initialValue XP") {
137-
private lateinit var timer: javax.swing.Timer
138-
139-
/**
140-
* Start fade out animation.
141-
*/
142-
fun startFadeOut() {
143-
timer = javax.swing.Timer(100, null)
144-
timer.addActionListener {
145-
val newAlpha = max(foreground.alpha - 255 / 10, 0)
146-
if (newAlpha <= 0) {
147-
timer.stop()
148-
value = 0
149-
} else {
150-
foreground =
151-
Color(JBColor.foreground().red, JBColor.foreground().green, JBColor.foreground().blue, newAlpha)
152-
}
153-
}
154-
timer.start()
155-
}
156-
157-
/**
158-
* Cancel fade out animation.
159-
*/
160-
fun cancelFadeOut() {
161-
timer.stop()
162-
}
163-
164-
/**
165-
* Current value of the fading label.
166-
*/
167-
var value: Int = initialValue
168-
set(newValue) {
169-
field = newValue
170-
text = if (newValue == 0) "0 xp" else "+$newValue xp"
171-
if (newValue == 0) {
172-
timer.stop()
173-
}
174-
}
48+
private fun fireEvent(event: Event, dataContext: DataContext? = null) {
49+
ApplicationManager.getApplication().messageBus.syncPublisher(CodeXPListener.CODEXP_EVENT)
50+
.eventOccurred(event, dataContext)
17551
}
17652
}

src/main/kotlin/com/github/ilovegamecoding/intellijcodexp/listeners/CodeXPListener.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.github.ilovegamecoding.intellijcodexp.listeners
22

33
import com.github.ilovegamecoding.intellijcodexp.enums.Event
4+
import com.intellij.openapi.actionSystem.DataContext
45
import com.intellij.util.messages.Topic
56

67
/**
@@ -20,6 +21,7 @@ interface CodeXPListener {
2021
* Function that is called when an event occurs.
2122
*
2223
* @param event The event that occurred.
24+
* @param dataContext The data context of the event.
2325
*/
24-
fun eventOccurred(event: Event)
26+
fun eventOccurred(event: Event, dataContext: DataContext? = null)
2527
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package com.github.ilovegamecoding.intellijcodexp.managers
2+
3+
import com.github.ilovegamecoding.intellijcodexp.enums.Event
4+
import com.github.ilovegamecoding.intellijcodexp.listeners.CodeXPListener
5+
import com.github.ilovegamecoding.intellijcodexp.services.CodeXPService
6+
import com.intellij.openapi.actionSystem.CommonDataKeys
7+
import com.intellij.openapi.actionSystem.DataContext
8+
import com.intellij.openapi.application.ApplicationManager
9+
import com.intellij.ui.JBColor
10+
import java.awt.Color
11+
import java.awt.Font
12+
import javax.swing.JComponent
13+
import javax.swing.JLabel
14+
import kotlin.math.max
15+
16+
/**
17+
* CodeXPUIManager class
18+
*
19+
* This class manages the UI of the CodeXP plugin.
20+
*/
21+
object CodeXPUIManager : CodeXPListener {
22+
/**
23+
* Fading labels in each swing component.
24+
*/
25+
private val fadingLabels: MutableMap<JComponent, FadingLabel> = mutableMapOf()
26+
27+
/**
28+
* Current value of the fading label.
29+
*/
30+
private var currentXPGainValue: Int = 0
31+
32+
/**
33+
* The message bus for the plugin
34+
*/
35+
private val messageBus = ApplicationManager.getApplication().messageBus
36+
37+
/**
38+
* The connection to the message bus
39+
*/
40+
private val connection = messageBus.connect()
41+
42+
init {
43+
connection.subscribe(CodeXPListener.CODEXP_EVENT, this)
44+
}
45+
46+
override fun eventOccurred(event: Event, dataContext: DataContext?) {
47+
displayXPLabel(event, dataContext)
48+
}
49+
50+
/**
51+
* Display XP label at the caret position.
52+
*
53+
* @param event The event to fire.
54+
* @param dataContext The data context of the event.
55+
*/
56+
private fun displayXPLabel(event: Event, dataContext: DataContext?) {
57+
if (dataContext == null) return
58+
59+
val codeXPConfiguration =
60+
ApplicationManager.getApplication().getService(CodeXPService::class.java).state.codeXPConfiguration
61+
62+
if (!codeXPConfiguration.showGainedXP) {
63+
return
64+
}
65+
66+
val editor = CommonDataKeys.EDITOR.getData(dataContext) ?: return
67+
val caretModel = editor.caretModel
68+
val fadingLabelPosition = editor.visualPositionToXY(caretModel.visualPosition)
69+
70+
val component = editor.contentComponent
71+
72+
fadingLabels[component]?.let { fadingLabel ->
73+
fadingLabel.cancelFadeOut()
74+
currentXPGainValue = fadingLabel.value
75+
component.remove(fadingLabel)
76+
component.revalidate()
77+
component.repaint()
78+
}
79+
80+
currentXPGainValue += event.xpValue.toInt()
81+
82+
val newFadingLabel = FadingLabel(currentXPGainValue).apply {
83+
font = Font(font.fontName, Font.BOLD, editor.colorsScheme.editorFontSize)
84+
size = preferredSize
85+
val caretHeight = editor.lineHeight
86+
fadingLabelPosition.let { point ->
87+
val position = codeXPConfiguration.positionToDisplayGainedXP
88+
val xOffset = when {
89+
position.name.contains("LEFT") -> -width
90+
position.name.contains("RIGHT") -> 0
91+
else -> -width / 2
92+
}
93+
point.translate(
94+
(position.x * 4) + xOffset,
95+
position.y * (caretHeight / 2)
96+
)
97+
location = point
98+
}
99+
startFadeOut()
100+
}
101+
102+
fadingLabels[component] = newFadingLabel
103+
104+
component.add(newFadingLabel)
105+
component.revalidate()
106+
component.repaint()
107+
}
108+
109+
/**
110+
* Fading label class for displaying XP gain.
111+
*/
112+
internal class FadingLabel(initialValue: Int) : JLabel(if (initialValue == 0) "0 xp" else "+$initialValue XP") {
113+
private lateinit var timer: javax.swing.Timer
114+
115+
/**
116+
* Start fade out animation.
117+
*/
118+
fun startFadeOut() {
119+
timer = javax.swing.Timer(100, null)
120+
timer.addActionListener {
121+
val newAlpha = max(foreground.alpha - 255 / 10, 0)
122+
if (newAlpha <= 0) {
123+
timer.stop()
124+
value = 0
125+
} else {
126+
foreground =
127+
Color(JBColor.foreground().red, JBColor.foreground().green, JBColor.foreground().blue, newAlpha)
128+
}
129+
}
130+
timer.start()
131+
}
132+
133+
/**
134+
* Cancel fade out animation.
135+
*/
136+
fun cancelFadeOut() {
137+
timer.stop()
138+
}
139+
140+
/**
141+
* Current value of the fading label.
142+
*/
143+
var value: Int = initialValue
144+
set(newValue) {
145+
field = newValue
146+
text = if (newValue == 0) "0 xp" else "+$newValue xp"
147+
if (newValue == 0) {
148+
timer.stop()
149+
}
150+
}
151+
}
152+
}

0 commit comments

Comments
 (0)