@@ -16,9 +16,15 @@ import com.intellij.openapi.wm.ToolWindowManager
16
16
import com.intellij.ui.dsl.builder.panel
17
17
import com.intellij.util.ui.JBUI
18
18
import com.intellij.util.ui.UIUtil
19
- import java.awt.BorderLayout
20
- import javax.swing.JLabel
21
- import javax.swing.JPanel
19
+ import java.awt.*
20
+ import java.awt.event.ActionEvent
21
+ import java.awt.event.ActionListener
22
+ import javax.swing.*
23
+ import javax.swing.border.EmptyBorder
24
+ import javax.swing.border.LineBorder
25
+ import javax.swing.text.SimpleAttributeSet
26
+ import javax.swing.text.StyleConstants
27
+ import javax.swing.text.StyledDocument
22
28
23
29
class AutoDevPlannerToolWindow (val project : Project ) : SimpleToolWindowPanel(true , true ), Disposable {
24
30
override fun getName (): String = " AutoDev Planner"
@@ -50,6 +56,11 @@ class AutoDevPlannerToolWindow(val project: Project) : SimpleToolWindowPanel(tru
50
56
if (! isEditorMode && ! isIssueInputMode) {
51
57
runInEdt {
52
58
planLangSketch.updatePlan(items)
59
+ contentPanel.components.find { it is LoadingPanel }?.let {
60
+ contentPanel.remove(it)
61
+ contentPanel.revalidate()
62
+ contentPanel.repaint()
63
+ }
53
64
}
54
65
}
55
66
}
@@ -156,10 +167,7 @@ class AutoDevPlannerToolWindow(val project: Project) : SimpleToolWindowPanel(tru
156
167
contentPanel.removeAll()
157
168
contentPanel.add(planPanel, BorderLayout .CENTER )
158
169
159
- val loadingPanel = JPanel (BorderLayout ()).apply {
160
- add(JLabel (" Processing your request..." ), BorderLayout .NORTH )
161
- background = JBUI .CurrentTheme .ToolWindow .background()
162
- }
170
+ val loadingPanel = LoadingPanel (project)
163
171
contentPanel.add(loadingPanel, BorderLayout .NORTH )
164
172
165
173
contentPanel.revalidate()
@@ -176,7 +184,8 @@ class AutoDevPlannerToolWindow(val project: Project) : SimpleToolWindowPanel(tru
176
184
companion object {
177
185
fun showPlanEditor (project : Project , planText : String , callback : (String ) -> Unit ) {
178
186
val toolWindow =
179
- ToolWindowManager .Companion .getInstance(project).getToolWindow(AutoDevPlannerToolWindowFactory .Companion .PlANNER_ID )
187
+ ToolWindowManager .Companion .getInstance(project)
188
+ .getToolWindow(AutoDevPlannerToolWindowFactory .Companion .PlANNER_ID )
180
189
if (toolWindow != null ) {
181
190
val content = toolWindow.contentManager.getContent(0 )
182
191
val plannerWindow = content?.component as ? AutoDevPlannerToolWindow
@@ -195,7 +204,8 @@ class AutoDevPlannerToolWindow(val project: Project) : SimpleToolWindowPanel(tru
195
204
196
205
fun showIssueInput (project : Project ) {
197
206
val toolWindow = ToolWindowManager .Companion .getInstance(project).getToolWindow(
198
- AutoDevPlannerToolWindowFactory .Companion .PlANNER_ID )
207
+ AutoDevPlannerToolWindowFactory .Companion .PlANNER_ID
208
+ )
199
209
if (toolWindow == null ) return
200
210
201
211
val content = toolWindow.contentManager.getContent(0 )
@@ -208,3 +218,94 @@ class AutoDevPlannerToolWindow(val project: Project) : SimpleToolWindowPanel(tru
208
218
}
209
219
}
210
220
}
221
+
222
+ private class LoadingPanel (project : Project ) : JPanel(BorderLayout ()) {
223
+ private val textPane = JTextPane ()
224
+ private val timer = Timer (50 , null )
225
+ private var currentText = " "
226
+ private var currentIndex = 0
227
+ private val loadingTexts = listOf (
228
+ " 🤔 Analyzing your request..." ,
229
+ " 💡 Generating a plan..." ,
230
+ " ⚙️ Processing the steps..." ,
231
+ " ✨ Almost there..."
232
+ )
233
+ private var currentTextIndex = 0
234
+
235
+ init {
236
+ background = JBUI .CurrentTheme .ToolWindow .background()
237
+ border = JBUI .Borders .empty(10 )
238
+ preferredSize = Dimension (0 , JBUI .scale(60 ))
239
+
240
+ val containerPanel = object : JPanel (BorderLayout ()) {
241
+ override fun paintComponent (g : Graphics ) {
242
+ super .paintComponent(g)
243
+ val g2d = g as Graphics2D
244
+ g2d.setRenderingHint(RenderingHints .KEY_RENDERING , RenderingHints .VALUE_RENDER_QUALITY )
245
+ g2d.setRenderingHint(RenderingHints .KEY_ANTIALIASING , RenderingHints .VALUE_ANTIALIAS_ON )
246
+
247
+ val gradient = GradientPaint (
248
+ 0f , 0f ,
249
+ JBUI .CurrentTheme .ToolWindow .background(),
250
+ 0f , height.toFloat(),
251
+ JBUI .CurrentTheme .ToolWindow .background().darker()
252
+ )
253
+ g2d.paint = gradient
254
+ g2d.fillRect(0 , 0 , width, height)
255
+ }
256
+ }
257
+ containerPanel.border = LineBorder (UIUtil .getBoundsColor(), 1 , true )
258
+ containerPanel.preferredSize = Dimension (0 , JBUI .scale(50 ))
259
+
260
+ textPane.apply {
261
+ background = Color (0 , 0 , 0 , 0 )
262
+ foreground = UIUtil .getLabelForeground()
263
+ font = JBUI .Fonts .create(" Monospaced" , 14 )
264
+ isEditable = false
265
+ isOpaque = false
266
+ border = JBUI .Borders .empty(10 , 0 )
267
+ }
268
+
269
+ containerPanel.add(textPane, BorderLayout .CENTER )
270
+ add(containerPanel, BorderLayout .CENTER )
271
+
272
+ startTypingAnimation()
273
+ }
274
+
275
+ private fun startTypingAnimation () {
276
+ timer.addActionListener(object : ActionListener {
277
+ override fun actionPerformed (e : ActionEvent ) {
278
+ if (currentIndex < loadingTexts[currentTextIndex].length) {
279
+ currentText + = loadingTexts[currentTextIndex][currentIndex]
280
+ updateText()
281
+ currentIndex++
282
+ } else {
283
+ currentIndex = 0
284
+ currentText = " "
285
+ currentTextIndex = (currentTextIndex + 1 ) % loadingTexts.size
286
+ }
287
+ }
288
+ })
289
+ timer.start()
290
+ }
291
+
292
+ private fun updateText () {
293
+ val doc = textPane.styledDocument
294
+ val style = SimpleAttributeSet ()
295
+ StyleConstants .setForeground(style, UIUtil .getLabelForeground())
296
+ StyleConstants .setFontSize(style, 14 )
297
+ StyleConstants .setFontFamily(style, " Monospaced" )
298
+
299
+ try {
300
+ doc.remove(0 , doc.length)
301
+ doc.insertString(0 , currentText, style)
302
+ } catch (e: Exception ) {
303
+ // Ignore any document modification errors
304
+ }
305
+ }
306
+
307
+ override fun removeNotify () {
308
+ super .removeNotify()
309
+ timer.stop()
310
+ }
311
+ }
0 commit comments