Skip to content

Commit a1ba0dd

Browse files
committed
refactor(dev-planner): rewrite UI logic using MVC pattern #352
- Restructured AutoDevPlannerToolWindow to use a PlannerView interface - Implemented separate view classes for different states (PlanView, EditorView, IssueInputView, LoadingView) - Refactored switchToView method to handle view changes more efficiently - Simplified IssueInputPanel initialization and text handling
1 parent d4bf83c commit a1ba0dd

File tree

2 files changed

+110
-108
lines changed

2 files changed

+110
-108
lines changed

core/src/main/kotlin/cc/unitmesh/devti/gui/planner/AutoDevPlannerToolWindow.kt

Lines changed: 108 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,9 @@ class AutoDevPlannerToolWindow(val project: Project) : SimpleToolWindowPanel(tru
3030

3131
private var markdownEditor: MarkdownLanguageField? = null
3232
private val contentPanel = JPanel(BorderLayout())
33-
34-
private var isEditorMode = false
35-
private var isIssueInputMode = false
33+
34+
private var currentView: PlannerView? = null
3635
private var currentCallback: ((String) -> Unit)? = null
37-
private val planPanel: JPanel by lazy { createPlanPanel() }
38-
private lateinit var issueInputPanel: IssueInputPanel
3936
private val plannerResultSummary = PlannerResultSummary(project, mutableListOf())
4037

4138
init {
@@ -50,20 +47,17 @@ class AutoDevPlannerToolWindow(val project: Project) : SimpleToolWindowPanel(tru
5047
toolbarPanel.add(toolbar.component)
5148

5249
add(toolbarPanel, BorderLayout.NORTH)
50+
add(contentPanel, BorderLayout.CENTER)
5351

5452
if (content.isBlank()) {
55-
isIssueInputMode = true
56-
contentPanel.add(createIssueInputPanel(), BorderLayout.CENTER)
53+
switchToView(IssueInputView())
5754
} else {
58-
contentPanel.add(planPanel, BorderLayout.CENTER)
59-
contentPanel.add(plannerResultSummary, BorderLayout.SOUTH)
55+
switchToView(PlanView())
6056
}
6157

62-
add(contentPanel, BorderLayout.CENTER)
63-
6458
connection.subscribe(PlanUpdateListener.Companion.TOPIC, object : PlanUpdateListener {
6559
override fun onPlanUpdate(items: MutableList<AgentTaskEntry>) {
66-
if (!isEditorMode && !isIssueInputMode) {
60+
if (currentView is PlanView) {
6761
runInEdt {
6862
planLangSketch.updatePlan(items)
6963
contentPanel.components.find { it is LoadingPanel }?.let {
@@ -78,7 +72,7 @@ class AutoDevPlannerToolWindow(val project: Project) : SimpleToolWindowPanel(tru
7872
override fun onUpdateChange(changes: MutableList<Change>) {
7973
runInEdt {
8074
plannerResultSummary.updateChanges(changes)
81-
if (!isEditorMode && !isIssueInputMode) {
75+
if (currentView is PlanView) {
8276
if (contentPanel.components.none { it == plannerResultSummary }) {
8377
contentPanel.add(plannerResultSummary, BorderLayout.SOUTH)
8478
}
@@ -91,74 +85,16 @@ class AutoDevPlannerToolWindow(val project: Project) : SimpleToolWindowPanel(tru
9185
})
9286
}
9387

94-
private fun createPlanPanel(): JPanel {
95-
return panel {
96-
row {
97-
cell(planLangSketch)
98-
.fullWidth()
99-
.resizableColumn()
100-
}
101-
}
102-
}
103-
104-
private fun createIssueInputPanel(): JPanel {
105-
issueInputPanel = IssueInputPanel(
106-
project,
107-
placeholder = "Enter Issue Description",
108-
onSubmit = { issueText ->
109-
if (issueText.isNotBlank()) {
110-
showLoadingState(issueText)
111-
}
112-
},
113-
onCancel = {
114-
switchToPlanView()
115-
}
116-
)
117-
return issueInputPanel
118-
}
119-
120-
private fun switchToEditorView() {
121-
if (isEditorMode) return
122-
if (isIssueInputMode) {
123-
isIssueInputMode = false
124-
}
125-
126-
contentPanel.removeAll()
127-
val editPlanPanel = EditPlanPanel(
128-
project = project,
129-
content = content,
130-
onSave = { newContent ->
131-
if (newContent == content) {
132-
return@EditPlanPanel
133-
}
134-
switchToPlanView(newContent)
135-
currentCallback?.invoke(newContent)
136-
},
137-
onCancel = {
138-
switchToPlanView()
139-
}
140-
)
141-
contentPanel.add(editPlanPanel, BorderLayout.CENTER)
142-
contentPanel.revalidate()
143-
contentPanel.repaint()
144-
145-
isEditorMode = true
146-
}
147-
148-
private fun switchToIssueInputView() {
149-
if (isIssueInputMode) return
150-
if (isEditorMode) {
151-
isEditorMode = false
152-
}
153-
88+
private fun switchToView(view: PlannerView) {
89+
if (currentView?.viewType == view.viewType) return
90+
15491
contentPanel.removeAll()
155-
contentPanel.add(issueInputPanel, BorderLayout.CENTER)
92+
93+
currentView = view
94+
view.initialize(this)
95+
15696
contentPanel.revalidate()
15797
contentPanel.repaint()
158-
159-
isIssueInputMode = true
160-
issueInputPanel.setText("")
161-
issueInputPanel.requestTextAreaFocus()
16298
}
16399

164100
fun switchToPlanView(newContent: String? = null) {
@@ -168,37 +104,109 @@ class AutoDevPlannerToolWindow(val project: Project) : SimpleToolWindowPanel(tru
168104
planLangSketch.updatePlan(parsedItems)
169105
}
170106

171-
contentPanel.removeAll()
172-
contentPanel.add(planPanel, BorderLayout.CENTER)
173-
contentPanel.add(plannerResultSummary, BorderLayout.SOUTH)
174-
contentPanel.revalidate()
175-
contentPanel.repaint()
176-
177-
isEditorMode = false
178-
isIssueInputMode = false
107+
switchToView(PlanView())
179108
}
180109

181-
private fun showLoadingState(issueText: String) {
110+
fun showLoadingState(issueText: String) {
182111
content = issueText
183112
val parsedItems = MarkdownPlanParser.parse(issueText).toMutableList()
184113
planLangSketch.updatePlan(parsedItems)
185114

186-
contentPanel.removeAll()
187-
contentPanel.add(planPanel, BorderLayout.CENTER)
188-
189-
val loadingPanel = LoadingPanel(project)
190-
contentPanel.add(loadingPanel, BorderLayout.NORTH)
191-
192-
contentPanel.revalidate()
193-
contentPanel.repaint()
194-
195-
isEditorMode = false
196-
isIssueInputMode = false
115+
switchToView(LoadingView())
197116
}
198117

199118
override fun dispose() {
200119
markdownEditor = null
201120
}
121+
122+
interface PlannerView {
123+
val viewType: PlannerViewType
124+
fun initialize(window: AutoDevPlannerToolWindow)
125+
}
126+
127+
enum class PlannerViewType {
128+
PLAN, EDITOR, ISSUE_INPUT, LOADING
129+
}
130+
131+
inner class PlanView : PlannerView {
132+
override val viewType = PlannerViewType.PLAN
133+
134+
override fun initialize(window: AutoDevPlannerToolWindow) {
135+
val planPanel = panel {
136+
row {
137+
cell(planLangSketch)
138+
.fullWidth()
139+
.resizableColumn()
140+
}
141+
}
142+
143+
contentPanel.add(planPanel, BorderLayout.CENTER)
144+
contentPanel.add(plannerResultSummary, BorderLayout.SOUTH)
145+
}
146+
}
147+
148+
inner class EditorView : PlannerView {
149+
override val viewType = PlannerViewType.EDITOR
150+
151+
override fun initialize(window: AutoDevPlannerToolWindow) {
152+
val editPlanPanel = EditPlanPanel(
153+
project = project,
154+
content = content,
155+
onSave = { newContent ->
156+
if (newContent == content) {
157+
return@EditPlanPanel
158+
}
159+
switchToPlanView(newContent)
160+
currentCallback?.invoke(newContent)
161+
},
162+
onCancel = {
163+
switchToPlanView()
164+
}
165+
)
166+
167+
contentPanel.add(editPlanPanel, BorderLayout.CENTER)
168+
}
169+
}
170+
171+
inner class IssueInputView : PlannerView {
172+
override val viewType = PlannerViewType.ISSUE_INPUT
173+
private lateinit var issueInputPanel: IssueInputPanel
174+
175+
override fun initialize(window: AutoDevPlannerToolWindow) {
176+
issueInputPanel = IssueInputPanel(
177+
project,
178+
onSubmit = { issueText ->
179+
if (issueText.isNotBlank()) {
180+
showLoadingState(issueText)
181+
}
182+
},
183+
onCancel = {
184+
switchToPlanView()
185+
}
186+
)
187+
188+
contentPanel.add(issueInputPanel, BorderLayout.CENTER)
189+
issueInputPanel.setText("")
190+
issueInputPanel.requestTextAreaFocus()
191+
}
192+
}
193+
194+
inner class LoadingView : PlannerView {
195+
override val viewType = PlannerViewType.LOADING
196+
197+
override fun initialize(window: AutoDevPlannerToolWindow) {
198+
val planPanel = panel {
199+
row {
200+
cell(planLangSketch)
201+
.fullWidth()
202+
.resizableColumn()
203+
}
204+
}
205+
206+
contentPanel.add(planPanel, BorderLayout.CENTER)
207+
contentPanel.add(LoadingPanel(project), BorderLayout.NORTH)
208+
}
209+
}
202210

203211
companion object {
204212
fun showPlanEditor(project: Project, planText: String, callback: (String) -> Unit) {
@@ -215,7 +223,7 @@ class AutoDevPlannerToolWindow(val project: Project) : SimpleToolWindowPanel(tru
215223
it.content = planText
216224
}
217225

218-
it.switchToEditorView()
226+
it.switchToView(it.EditorView())
219227
toolWindow.show()
220228
}
221229
}
@@ -231,10 +239,9 @@ class AutoDevPlannerToolWindow(val project: Project) : SimpleToolWindowPanel(tru
231239
val plannerWindow = content?.component as? AutoDevPlannerToolWindow
232240

233241
plannerWindow?.let {
234-
it.switchToIssueInputView()
242+
it.switchToView(it.IssueInputView())
235243
toolWindow.show()
236244
}
237245
}
238246
}
239247
}
240-

core/src/main/kotlin/cc/unitmesh/devti/shadow/IssueInputPanel.kt

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@ import javax.swing.JPanel
1818

1919
class IssueInputPanel(
2020
private val project: Project,
21-
private val placeholder: String,
2221
private val onSubmit: (String) -> Unit,
2322
private val onCancel: () -> Unit
2423
) : JPanel(BorderLayout()) {
2524
private var textArea: MarkdownLanguageField? = null
2625

2726
init {
28-
textArea = MarkdownLanguageField(project, "", placeholder, "issue.md").apply {
27+
textArea = MarkdownLanguageField(project, "", "Enter Issue Description", "issue.md").apply {
2928
border = AutoDevLineBorder(JBColor.namedColor("Focus.borderColor", JBColor.BLUE), 1, true, 4)
3029
}
3130

@@ -67,11 +66,7 @@ class IssueInputPanel(
6766
fun getText(): String = textArea?.text ?: ""
6867

6968
fun setText(text: String) {
70-
if (text.isNotBlank()) {
71-
textArea?.text = text
72-
} else {
73-
textArea?.text = placeholder
74-
}
69+
textArea?.text = text
7570
}
7671

7772
fun requestTextAreaFocus() {

0 commit comments

Comments
 (0)