Explorar o código

add: 完成自动生成界面及功能,release 1.0

hwh97 %!s(int64=4) %!d(string=hai) anos
pai
achega
321dc9442e

+ 1 - 1
build.gradle.kts

@@ -8,7 +8,7 @@ plugins {
 }
 
 group = "com.i2edu"
-version = "1.0-SNAPSHOT"
+version = "1.0"
 
 repositories {
     mavenCentral()

+ 49 - 14
src/main/kotlin/PageCreateAction.kt

@@ -1,30 +1,65 @@
-import com.intellij.openapi.actionSystem.*
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
 import com.intellij.openapi.actionSystem.LangDataKeys
+import com.intellij.openapi.actionSystem.PlatformDataKeys
+import com.intellij.psi.PsiDirectory
 import com.intellij.psi.PsiElement
-
 import constant.Constants
-import util.NotifierType
-import util.NotifierUtil
-import util.FlutterUtil
+import template.CodeTemplate
+import ui.ConfirmAction
+import ui.PageCreateDialog
+import util.*
 
 
 class PageCreateAction : AnAction() {
     override fun actionPerformed(e: AnActionEvent) {
         val project = e.getData(PlatformDataKeys.PROJECT)!!
         val psiElement: PsiElement? = e.getData(LangDataKeys.PSI_ELEMENT)
-        val isValidAction = FlutterUtil.isValidAction(project, psiElement)
+        val rootPath: String = PathUtil.getRootPath(project)
+        val isValidAction = FlutterUtil.isValidAction(project, psiElement, rootPath)
 
         if (isValidAction) {
-            NotifierUtil.showNotifier(
-                project, "you did a correction action congratulations!",
-                type = NotifierType.INFO,
-            )
-//            val directory = PsiDirectoryFactory.getInstance(project).createDirectory(project.projectFile!!)
+            PageCreateDialog(project, object : ConfirmAction {
+                override fun onConFirm(pageName: String, stateful: Boolean, router: Boolean) {
+                    if (pageName.isEmpty()) {
+                        NotifierUtil.showNotifier(
+                            project, Constants.emptyPageNameHint, type = NotifierType.ERROR,
+                        )
+                    } else {
+                        // 生成ViewModel路径
+                        // 读取lib下目录 /pages/mine/collection
+                        val selectFullPath = (psiElement as PsiDirectory).virtualFile.path
+                        var pathDir = selectFullPath.replace("$rootPath/lib", "")
+                        pathDir = pathDir.replace("/${Constants.pageDirectory}", "")
+
+                        // 生成view model文件
+                        FlutterUtil.writePage(
+                            project,
+                            "$rootPath/lib/view_model$pathDir",
+                            "${CodeUtil.toFileName(pageName)}_view_model.dart",
+                            CodeTemplate.getViewModel(
+                                pageName,
+                            )
+                        )
+                        // 生成page文件
+                        FlutterUtil.writePage(
+                            project,
+                            selectFullPath,
+                            "${CodeUtil.toFileName(pageName)}_page.dart",
+                            CodeTemplate.getStatefulRouter(
+                                stateful,
+                                pageName,
+                                if (router) CodeUtil.toCamelCase(pageName) else null,
+                                pathDir
+                            )
+                        )
+
+                    }
+                }
+            }).show()
         } else {
             NotifierUtil.showNotifier(
-                project,
-                Constants.validFailedHint,
-                type = NotifierType.ERROR
+                project, Constants.validFailedHint, type = NotifierType.ERROR
             )
         }
     }

+ 0 - 54
src/main/kotlin/RouterGenerateAction.kt

@@ -1,54 +0,0 @@
-import com.intellij.execution.configurations.GeneralCommandLine
-import com.intellij.ide.util.gotoByName.ModelDiff
-import com.intellij.openapi.actionSystem.AnAction
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.actionSystem.PlatformDataKeys
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.command.WriteCommandAction
-import com.intellij.openapi.diagnostic.LoggerRt
-import com.intellij.openapi.vfs.VfsUtil
-import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.psi.PsiFileFactory
-import com.intellij.psi.impl.file.PsiDirectoryFactory
-import com.jetbrains.lang.dart.DartLanguage
-import org.omg.SendingContext.RunTime
-import template.CodeTemplate
-import util.CodeUtil
-import util.FlutterUtil
-
-
-class RouterGenerateAction : AnAction() {
-    private val log = LoggerRt.getInstance(RouterGenerateAction::class.java)
-
-    override fun actionPerformed(e: AnActionEvent) {
-        val project = e.getData(PlatformDataKeys.PROJECT)!!
-        val isTargetProject = FlutterUtil.isTargetProject(project)
-        if (isTargetProject) {
-            NotifierUtil.showNotifier(project, "you found our project cheer!", type = NotifierType.INFO)
-
-            val fileFactory = PsiFileFactory.getInstance(project)
-            // create generated directory
-            var saveFile: VirtualFile? = null
-            WriteCommandAction.runWriteCommandAction(project) {
-                saveFile = VfsUtil.createDirectoryIfMissing("${project.basePath}/lib/router_gen")!!
-            }
-            val saveDirectory = PsiDirectoryFactory.getInstance(project).createDirectory(saveFile!!)
-
-
-            // create file
-            val saveTextFile = fileFactory.createFileFromText("router_meta.dart", DartLanguage.INSTANCE, CodeTemplate.RouterMeta)
-            WriteCommandAction.runWriteCommandAction(project) {
-                CodeUtil.reformatDartCode(saveTextFile)
-            }
-
-            // add to file
-            WriteCommandAction.runWriteCommandAction(project) {
-               saveDirectory.add(saveTextFile!!)
-            }
-
-//            val directory = PsiDirectoryFactory.getInstance(project).createDirectory(project.projectFile!!)
-        } else {
-            NotifierUtil.showNotifier(project, "oh... you lose our project, check again?", type = NotifierType.ERROR)
-        }
-    }
-}

+ 4 - 2
src/main/kotlin/constant/Constants.kt

@@ -2,11 +2,13 @@ package constant
 
 object Constants {
     const val title: String = "i2 code generate"
-    //    const val projectName: String = "i2-school-app"
-    const val projectName: String = "example"
+    const val projectName: String = "i2-school-app"
+//    const val projectName: String = "example"
     const val flutterTarget: String = "pubspec.yaml"
+    const val pageDirectory: String = "pages"
 
     // failed hint
     const val validFailedHint = "1.是否为${projectName}项目<br>" +
             "2.是否选择在lib及子文件夹下创建"
+    const val emptyPageNameHint = "请输入页面名"
 }

+ 65 - 4
src/main/kotlin/template/CodeTemplate.kt

@@ -1,11 +1,72 @@
 package template
 
+import util.CodeUtil.toFileName
+
 object CodeTemplate {
-    const val RouterMeta: String = """
-class RouterMeta {
-   final String paramName;
-   const RouterMeta({this.paramName});
+    fun getStatefulRouter(stateful: Boolean, pageName: String, routerPath: String?, viewModelLocation: String): String {
+        val routerAnnotation = if (routerPath != null) "\n@RouterPage(path: \"${routerPath}\")" else ""
+        val routerAnnotationImport = if (routerPath != null) "\nimport 'package:router_gen/router_gen.dart';\n" else ""
+        if (stateful) {
+            return  """import 'package:flutter/material.dart';$routerAnnotationImport
+import 'package:school_parent/core/provider/exports.dart';
+import 'package:school_parent/apps/learning_park/common/common_app_bar.dart';
+import 'package:school_parent/view_model${viewModelLocation}/${toFileName(pageName)}_view_model.dart';
+$routerAnnotation
+class ${pageName}Page extends StatefulWidget {
+  @override
+  _${pageName}PageState createState() => _${pageName}PageState();
+}
+
+class _${pageName}PageState extends State<${pageName}Page>
+    with StatePageHelper<${pageName}Page, ${pageName}ViewModel> {
+  @override
+  Widget buildAppBar(${pageName}ViewModel model) => CommonAppBar(
+    title: '${pageName}',
+  );
+  
+  @override
+  Widget buildWidget(BuildContext context, ${pageName}ViewModel model) {
+    return Container();
+  }
+ 
+  @override
+  void initState() {
+    super.initState();
+  }
+ 
+  @override
+  void dispose() { 
+    super.dispose();
+  }
 }"""
+        } else {
+            return """import 'package:flutter/material.dart';$routerAnnotationImport
+import 'package:school_parent/core/provider/exports.dart';
+import 'package:school_parent/view_model${viewModelLocation}/${toFileName(pageName)}_view_model.dart';
+$routerAnnotation
+class ${pageName}Page extends StatelessWidget
+    with StatelessPageHelper<${pageName}ViewModel> {
+  @override
+  Widget buildWidget(BuildContext context, ${pageName}ViewModel model) {
+    return Container();
+  }
+}
+"""
+        }
+    }
+
+    fun getViewModel(pageName: String, ): String{
+        return """import 'package:injectable/injectable.dart';
+import 'package:school_parent/core/provider/base_future_view_model.dart';
 
+@injectable
+class ${pageName}ViewModel extends BaseFutureViewModel<void> {
+  ${pageName}ViewModel();
 
+  @override
+  Future<void> futureToRun() {
+    return null;
+  }
+}""";
+    }
 }

+ 74 - 0
src/main/kotlin/ui/PageCreateDialog.kt

@@ -0,0 +1,74 @@
+package ui
+
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.ui.DialogWrapper
+import java.awt.FlowLayout
+import java.awt.GridLayout
+import javax.swing.*
+
+interface ConfirmAction {
+    fun onConFirm(pageName: String, stateful: Boolean, router: Boolean)
+}
+
+class PageCreateDialog(project: Project, private val onConfirm: ConfirmAction) : DialogWrapper(project) {
+    private val textField = JTextField()
+    private val stateGroup = ButtonGroup()
+    private val checkbox = JCheckBox("生成路由注解")
+
+    init {
+        // dialog config
+        title = "i2 Page Creation"
+        setOKButtonText("确定")
+        setCancelButtonText("取消")
+        setResizable(true)
+        init()
+    }
+
+    override fun createCenterPanel(): JComponent? = createCenter()
+
+    override fun getPreferredFocusedComponent(): JComponent? {
+        return textField
+    }
+
+    override fun doOKAction() {
+        super.doOKAction()
+        onConfirm.onConFirm(
+            textField.text.trim(),
+            stateGroup.selection.actionCommand == "Stateful",
+            checkbox.isSelected
+        )
+    }
+
+    private fun createCenter() : JPanel {
+        val panel  = JPanel()
+        panel.layout = GridLayout(4, 1)
+        // page name hint
+        val hintLabel = JLabel("页面名(如MyHomePage只需输入MyHome)")
+        panel.add(hintLabel)
+
+        // page name text field
+        panel.add(textField)
+
+        // choose stateful or stateless
+        val statePanel = JPanel()
+        statePanel.layout = FlowLayout(FlowLayout.LEFT)
+        val hintPageLabel = JLabel("页面类型")
+        statePanel.add(hintPageLabel)
+        val statefulRadioBtn = JRadioButton("Stateful", true)
+        statefulRadioBtn.actionCommand = "Stateful"
+        statePanel.add(statefulRadioBtn)
+
+        val statelessRadioBtn = JRadioButton("Stateless")
+        statelessRadioBtn.actionCommand = "Stateless"
+        statePanel.add(statelessRadioBtn)
+
+        stateGroup.add(statefulRadioBtn)
+        stateGroup.add(statelessRadioBtn)
+        panel.add(statePanel)
+
+        // choose generate router
+        panel.add(checkbox)
+
+        return panel
+    }
+}

+ 22 - 1
src/main/kotlin/util/CodeUtil.kt

@@ -3,7 +3,8 @@ package util
 import com.intellij.openapi.diagnostic.logger
 import com.intellij.psi.PsiElement
 import com.intellij.psi.codeStyle.CodeStyleManager
-import com.jetbrains.rd.util.string.print
+import com.jetbrains.lang.dart.ide.formatter.settings.DartLanguageCodeStyleSettingsProvider
+import java.lang.StringBuilder
 
 object CodeUtil {
     fun reformatDartCode(element: PsiElement) {
@@ -14,4 +15,24 @@ object CodeUtil {
             logger<CodeUtil>().error("reformat code failed", e)
         }
     }
+
+    fun toCamelCase(pageName: String): String {
+        if (pageName.length < 2) {
+            return pageName.toLowerCase()
+        }
+        return pageName[0].toLowerCase() + pageName.substring(1)
+    }
+
+    fun toFileName(pageName: String): String{
+        val result = StringBuilder()
+        for (i in pageName.indices) {
+            val v = pageName[i];
+            if (v.isUpperCase() && result.isNotEmpty()) {
+                result.append("_")
+            }
+            result.append(v.toLowerCase())
+        }
+
+        return result.toString()
+    }
 }

+ 18 - 8
src/main/kotlin/util/FlutterUtil.kt

@@ -1,17 +1,18 @@
 package util
 
-import com.intellij.openapi.module.Module
-import com.intellij.openapi.module.ModuleUtil
+import com.intellij.openapi.command.WriteCommandAction
 import com.intellij.openapi.project.Project
-import com.intellij.openapi.roots.ModuleRootManager
+import com.intellij.openapi.vfs.VfsUtil
+import com.intellij.openapi.vfs.VirtualFile
 import com.intellij.psi.PsiDirectory
 import com.intellij.psi.PsiElement
+import com.intellij.psi.impl.file.PsiDirectoryFactory
 import com.intellij.psi.search.FilenameIndex
 import com.intellij.psi.search.GlobalSearchScope
 import constant.Constants
 
 object FlutterUtil {
-    fun isValidAction(project: Project, psiElement: PsiElement?): Boolean {
+    fun isValidAction(project: Project, psiElement: PsiElement?, rootPath: String): Boolean {
         // 检查是否为Flutter应用
         var exist = false
         for (pubspec in FilenameIndex.getFilesByName(
@@ -27,14 +28,23 @@ object FlutterUtil {
         // 检查是否在文件夹下操作及是否在lib子目录下执行
         var inLib = false
         if (psiElement != null && psiElement is PsiDirectory) {
-            val module: Module? = ModuleUtil.findModuleForFile(project.projectFile!!, project)
-            val moduleRootPath = ModuleRootManager.getInstance(module!!).contentRoots[0].path
-
-            if (psiElement.virtualFile.path.startsWith("${moduleRootPath}/lib")) {
+            if (psiElement.virtualFile.path.startsWith("${rootPath}/lib")) {
                 inLib = true
             }
         }
 
         return exist && project.name == Constants.projectName && inLib
     }
+
+    fun writePage(project: Project, dir: String, fileName: String, content: String) {
+        WriteCommandAction.runWriteCommandAction(project) {
+            var dirVirtualFile: VirtualFile? = null
+            dirVirtualFile = VfsUtil.createDirectoryIfMissing(dir)
+            val dirPsiDirectory = PsiDirectoryFactory.getInstance(project).createDirectory(dirVirtualFile!!)
+            val filePsiFile = dirPsiDirectory.createFile(fileName)
+            filePsiFile.virtualFile.setBinaryContent(content.toByteArray())
+//            CodeUtil.reformatDartCode(filePsiFile)
+            filePsiFile.navigate(true)
+        }
+    }
 }

+ 16 - 0
src/main/kotlin/util/PathUtil.kt

@@ -0,0 +1,16 @@
+package util
+
+import com.intellij.openapi.module.Module
+import com.intellij.openapi.module.ModuleUtil
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.roots.ModuleRootManager
+
+object PathUtil {
+    fun getRootPath(project: Project): String {
+        val module: Module? = ModuleUtil.findModuleForFile(project.workspaceFile!!, project)
+
+        return ModuleRootManager.getInstance(module!!).contentRoots[0].path
+    }
+
+
+}

+ 1 - 6
src/main/resources/META-INF/plugin.xml

@@ -1,7 +1,7 @@
 <idea-plugin>
     <id>com.i2edu.i2_code_genrate</id>
     <name>i2 code generator</name>
-    <vendor email="974815768@qq.com" url="http://www.i2edu.com">i2edu</vendor>
+    <vendor email="974815768@qq.com" url="http://www.i2edu.com">i2edu·Andy</vendor>
 
     <description><![CDATA[
     generator for i2 project<br>
@@ -21,11 +21,6 @@
 
     <actions>
         <!-- Add your actions here -->
-<!--        <action id="i2school.generate.route" class="RouterGenerateAction" text="GenerateRouter"-->
-<!--                description="auto generate router">-->
-<!--            <add-to-group group-id="BuildMenu" anchor="first"/>-->
-<!--            <keyboard-shortcut keymap="$default" first-keystroke="alt R"/>-->
-<!--        </action>-->
         <group id="i2 code generate" text="i2 code generate" popup="true">
             <add-to-group group-id="ProjectViewPopupMenu" anchor="first"/>
         </group>