From 898794e887f6aec6f4a439a66bdba42ee34980ca Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sat, 28 Feb 2026 20:12:29 +0200 Subject: [PATCH 1/3] Add advanced CSS editing mode in Initializr theme settings --- .../com/codename1/initializr/Initializr.java | 85 ++++++++++++++++++- .../initializr/model/ProjectOptions.java | 16 ++++ .../initializr/ui/TemplatePreviewPanel.java | 26 ++++++ 3 files changed, 123 insertions(+), 4 deletions(-) diff --git a/scripts/initializr/common/src/main/java/com/codename1/initializr/Initializr.java b/scripts/initializr/common/src/main/java/com/codename1/initializr/Initializr.java index 8092772f86..90c033edf6 100644 --- a/scripts/initializr/common/src/main/java/com/codename1/initializr/Initializr.java +++ b/scripts/initializr/common/src/main/java/com/codename1/initializr/Initializr.java @@ -24,6 +24,7 @@ import com.codename1.ui.Label; import com.codename1.ui.RadioButton; import com.codename1.ui.TextField; +import com.codename1.ui.TextArea; import com.codename1.ui.layouts.BorderLayout; import com.codename1.ui.layouts.BoxLayout; import com.codename1.ui.layouts.GridLayout; @@ -46,8 +47,10 @@ public void runApp() { final Template[] selectedTemplate = new Template[]{Template.BAREBONES}; final IDE[] selectedIde = new IDE[]{IDE.INTELLIJ}; final ProjectOptions.ThemeMode[] selectedThemeMode = new ProjectOptions.ThemeMode[]{ProjectOptions.ThemeMode.LIGHT}; + final ProjectOptions.ThemeEditorMode[] selectedThemeEditorMode = new ProjectOptions.ThemeEditorMode[]{ProjectOptions.ThemeEditorMode.SIMPLE}; final ProjectOptions.Accent[] selectedAccent = new ProjectOptions.Accent[]{ProjectOptions.Accent.DEFAULT}; final boolean[] roundedButtons = new boolean[]{true}; + final String[] customThemeCss = new String[]{defaultAdvancedCss()}; final boolean[] includeLocalizationBundles = new boolean[]{true}; final ProjectOptions.PreviewLanguage[] previewLanguage = new ProjectOptions.PreviewLanguage[]{ProjectOptions.PreviewLanguage.ENGLISH}; final RadioButton[] templateButtons = new RadioButton[Template.values().length]; @@ -69,7 +72,8 @@ public void runApp() { public void run() { ProjectOptions options = new ProjectOptions( selectedThemeMode[0], selectedAccent[0], roundedButtons[0], - includeLocalizationBundles[0], previewLanguage[0] + includeLocalizationBundles[0], previewLanguage[0], + selectedThemeEditorMode[0], customThemeCss[0] ); previewPanel.setTemplate(selectedTemplate[0]); previewPanel.setOptions(options); @@ -97,7 +101,8 @@ public void run() { createTemplateSelector(selectedTemplate, templateButtons, refresh) ); final Container idePanel = createIdeSelectorPanel(selectedIde, refresh); - final Container themePanel = createThemeOptionsPanel(selectedThemeMode, selectedAccent, roundedButtons, refresh); + final Container themePanel = createThemeOptionsPanel(selectedThemeMode, selectedThemeEditorMode, + selectedAccent, roundedButtons, customThemeCss, refresh); final Container localizationPanel = createLocalizationPanel(includeLocalizationBundles, previewLanguage, refresh, previewPanel); themePanelRef[0] = themePanel; final Container settingsPanel = BoxLayout.encloseY(summaryLabel); @@ -133,7 +138,8 @@ public void run() { String packageName = packageField.getText() == null ? "" : packageField.getText().trim(); ProjectOptions options = new ProjectOptions( selectedThemeMode[0], selectedAccent[0], roundedButtons[0], - includeLocalizationBundles[0], previewLanguage[0] + includeLocalizationBundles[0], previewLanguage[0], + selectedThemeEditorMode[0], customThemeCss[0] ); GeneratorModel.create(selectedIde[0], selectedTemplate[0], appName, packageName, options).generate(); }); @@ -256,9 +262,31 @@ private Container createIdeSelectorPanel(IDE[] selectedIde, Runnable onSelection } private Container createThemeOptionsPanel(ProjectOptions.ThemeMode[] selectedThemeMode, + ProjectOptions.ThemeEditorMode[] selectedThemeEditorMode, ProjectOptions.Accent[] selectedAccent, boolean[] roundedButtons, + String[] customThemeCss, Runnable onSelectionChanged) { + Container editorModeRow = new Container(new GridLayout(1, 2)); + editorModeRow.setUIID("InitializrChoicesGrid"); + ButtonGroup editorModeGroup = new ButtonGroup(); + for (ProjectOptions.ThemeEditorMode editorMode : ProjectOptions.ThemeEditorMode.values()) { + RadioButton rb = new RadioButton(formatEnumLabel(editorMode.name())); + rb.setToggle(true); + rb.setUIID("InitializrChoice"); + editorModeGroup.add(rb); + editorModeRow.add(rb); + if (editorMode == selectedThemeEditorMode[0]) { + rb.setSelected(true); + } + rb.addActionListener(e -> { + if (rb.isSelected()) { + selectedThemeEditorMode[0] = editorMode; + onSelectionChanged.run(); + } + }); + } + Container modeRow = new Container(new GridLayout(1, 2)); modeRow.setUIID("InitializrChoicesGrid"); ButtonGroup modeGroup = new ButtonGroup(); @@ -307,11 +335,59 @@ private Container createThemeOptionsPanel(ProjectOptions.ThemeMode[] selectedThe onSelectionChanged.run(); }); - return BoxLayout.encloseY( + TextArea cssEditor = new TextArea(customThemeCss[0], 8, 30); + cssEditor.setUIID("InitializrField"); + cssEditor.setGrowByContent(true); + cssEditor.addDataChangedListener((type, index) -> { + customThemeCss[0] = cssEditor.getText(); + onSelectionChanged.run(); + }); + + Container simpleControls = BoxLayout.encloseY( labeledField("Mode", modeRow), labeledField("Accent", accentRow), rounded ); + Container advancedControls = labeledField("Theme CSS", cssEditor); + + Runnable updateThemeEditorVisibility = () -> { + boolean advanced = selectedThemeEditorMode[0] == ProjectOptions.ThemeEditorMode.ADVANCED; + simpleControls.setHidden(advanced); + simpleControls.setVisible(!advanced); + advancedControls.setHidden(!advanced); + advancedControls.setVisible(advanced); + }; + updateThemeEditorVisibility.run(); + for (int i = 0; i < editorModeRow.getComponentCount(); i++) { + Component c = editorModeRow.getComponentAt(i); + if (c instanceof RadioButton) { + ((RadioButton)c).addActionListener(e -> updateThemeEditorVisibility.run()); + } + } + + return BoxLayout.encloseY( + labeledField("Editor", editorModeRow), + simpleControls, + advancedControls + ); + } + + private String defaultAdvancedCss() { + return ":root {\n" + + " --primary: #1976d2;\n" + + "}\n\n" + + "Toolbar {\n" + + " background-color: #f2f5fa;\n" + + " color: #1f2933;\n" + + "}\n\n" + + "Title {\n" + + " color: #1f2933;\n" + + "}\n\n" + + "Button {\n" + + " background-color: var(--primary);\n" + + " color: #ffffff;\n" + + " padding: 3px 6px;\n" + + "}\n"; } private Container createTemplateSelector(Template[] selectedTemplate, RadioButton[] templateButtons, Runnable onSelectionChanged) { @@ -505,6 +581,7 @@ private String createSummary(String appName, String packageName, Template templa + "Template: " + template.name() + "\n" + "IDE: " + ide.name() + "\n" + "Theme: " + options.themeMode.name() + "\n" + + "Theme Editor: " + options.themeEditorMode.name() + "\n" + "Accent: " + options.accent.name() + "\n" + "Rounded Buttons: " + (options.roundedButtons ? "Yes" : "No") + "\n" + "Localization Bundles: " + (options.includeLocalizationBundles ? "Yes" : "No") + "\n" diff --git a/scripts/initializr/common/src/main/java/com/codename1/initializr/model/ProjectOptions.java b/scripts/initializr/common/src/main/java/com/codename1/initializr/model/ProjectOptions.java index 7595fa1fc3..4dcfad6926 100644 --- a/scripts/initializr/common/src/main/java/com/codename1/initializr/model/ProjectOptions.java +++ b/scripts/initializr/common/src/main/java/com/codename1/initializr/model/ProjectOptions.java @@ -36,6 +36,11 @@ public enum ThemeMode { DARK } + public enum ThemeEditorMode { + SIMPLE, + ADVANCED + } + public enum Accent { DEFAULT, TEAL, @@ -48,14 +53,25 @@ public enum Accent { public final boolean roundedButtons; public final boolean includeLocalizationBundles; public final PreviewLanguage previewLanguage; + public final ThemeEditorMode themeEditorMode; + public final String customCss; public ProjectOptions(ThemeMode themeMode, Accent accent, boolean roundedButtons, boolean includeLocalizationBundles, PreviewLanguage previewLanguage) { + this(themeMode, accent, roundedButtons, includeLocalizationBundles, previewLanguage, + ThemeEditorMode.SIMPLE, null); + } + + public ProjectOptions(ThemeMode themeMode, Accent accent, boolean roundedButtons, + boolean includeLocalizationBundles, PreviewLanguage previewLanguage, + ThemeEditorMode themeEditorMode, String customCss) { this.themeMode = themeMode; this.accent = accent; this.roundedButtons = roundedButtons; this.includeLocalizationBundles = includeLocalizationBundles; this.previewLanguage = previewLanguage == null ? PreviewLanguage.ENGLISH : previewLanguage; + this.themeEditorMode = themeEditorMode == null ? ThemeEditorMode.SIMPLE : themeEditorMode; + this.customCss = customCss; } public static ProjectOptions defaults() { diff --git a/scripts/initializr/common/src/main/java/com/codename1/initializr/ui/TemplatePreviewPanel.java b/scripts/initializr/common/src/main/java/com/codename1/initializr/ui/TemplatePreviewPanel.java index 647e1ebdc6..20cbf7d677 100644 --- a/scripts/initializr/common/src/main/java/com/codename1/initializr/ui/TemplatePreviewPanel.java +++ b/scripts/initializr/common/src/main/java/com/codename1/initializr/ui/TemplatePreviewPanel.java @@ -13,9 +13,11 @@ import com.codename1.ui.Form; import com.codename1.ui.InterFormContainer; import com.codename1.ui.Label; +import com.codename1.ui.css.CSSThemeCompiler; import com.codename1.ui.layouts.BorderLayout; import com.codename1.ui.layouts.BoxLayout; import com.codename1.ui.plaf.UIManager; +import com.codename1.ui.util.MutableResource; import com.codename1.ui.util.Resources; import java.io.InputStream; @@ -29,6 +31,7 @@ public class TemplatePreviewPanel { private final ImageViewer staticPreview; private final Label staticPreviewFallback; private InterFormContainer liveFormPreview; + private final Hashtable baseTheme; private Template template; private ProjectOptions options = ProjectOptions.defaults(); @@ -46,6 +49,8 @@ public TemplatePreviewPanel(Template template) { root = new Container(new BorderLayout()); root.setUIID("InitializrCard"); root.add(BorderLayout.CENTER, previewHolder); + String[] themeNames = Resources.getGlobalResources().getThemeResourceNames(); + baseTheme = themeNames.length > 0 ? Resources.getGlobalResources().getTheme(themeNames[0]) : new Hashtable(); updateMode(); } @@ -76,6 +81,7 @@ public void showUpdatedLivePreview() { private Form createBarebonesPreviewForm(ProjectOptions options) { installBundle(options); + applyThemeOptions(options); Form form = new Form("Hi World", BoxLayout.y()); Button helloButton = new Button("Hello World"); helloButton.setUIID("Button"); @@ -87,6 +93,26 @@ private Form createBarebonesPreviewForm(ProjectOptions options) { return form; } + private void applyThemeOptions(ProjectOptions options) { + UIManager.getInstance().setThemeProps(baseTheme); + if (options.themeEditorMode != ProjectOptions.ThemeEditorMode.ADVANCED) { + return; + } + if (options.customCss == null || options.customCss.trim().length() == 0) { + return; + } + try { + MutableResource resources = new MutableResource(); + new CSSThemeCompiler().compile(options.customCss, resources, "Theme"); + Hashtable parsedTheme = resources.getTheme("Theme"); + if (parsedTheme != null) { + UIManager.getInstance().addThemeProps(parsedTheme); + } + } catch (RuntimeException ex) { + Log.e(ex); + } + } + private void installBundle(ProjectOptions options) { if (!options.includeLocalizationBundles) { UIManager.getInstance().setBundle(null); From 709169792016c1e794f86cfc49e4a98f69fa2717 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sat, 28 Feb 2026 20:55:46 +0200 Subject: [PATCH 2/3] Refine advanced CSS editor UX in Initializr --- .../com/codename1/initializr/Initializr.java | 38 ++++++++++++++----- .../initializr/ui/TemplatePreviewPanel.java | 22 +++++++++++ 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/scripts/initializr/common/src/main/java/com/codename1/initializr/Initializr.java b/scripts/initializr/common/src/main/java/com/codename1/initializr/Initializr.java index 90c033edf6..431234453a 100644 --- a/scripts/initializr/common/src/main/java/com/codename1/initializr/Initializr.java +++ b/scripts/initializr/common/src/main/java/com/codename1/initializr/Initializr.java @@ -57,6 +57,7 @@ public void runApp() { final SpanLabel summaryLabel = new SpanLabel(); final TemplatePreviewPanel previewPanel = new TemplatePreviewPanel(selectedTemplate[0]); final Container[] themePanelRef = new Container[1]; + final UITimer[] cssRefreshTimer = new UITimer[1]; appNameField.setUIID("InitializrField"); packageField.setUIID("InitializrField"); @@ -92,6 +93,15 @@ public void run() { form.revalidate(); } }; + final Runnable scheduleCssRefresh = () -> { + if (cssRefreshTimer[0] != null) { + cssRefreshTimer[0].cancel(); + } + cssRefreshTimer[0] = UITimer.timer(500, false, form, () -> { + cssRefreshTimer[0] = null; + refresh.run(); + }); + }; final Container essentialsCard = createEssentialsCard( appNameField, @@ -102,7 +112,7 @@ public void run() { ); final Container idePanel = createIdeSelectorPanel(selectedIde, refresh); final Container themePanel = createThemeOptionsPanel(selectedThemeMode, selectedThemeEditorMode, - selectedAccent, roundedButtons, customThemeCss, refresh); + selectedAccent, roundedButtons, customThemeCss, refresh, scheduleCssRefresh); final Container localizationPanel = createLocalizationPanel(includeLocalizationBundles, previewLanguage, refresh, previewPanel); themePanelRef[0] = themePanel; final Container settingsPanel = BoxLayout.encloseY(summaryLabel); @@ -266,7 +276,8 @@ private Container createThemeOptionsPanel(ProjectOptions.ThemeMode[] selectedThe ProjectOptions.Accent[] selectedAccent, boolean[] roundedButtons, String[] customThemeCss, - Runnable onSelectionChanged) { + Runnable onSelectionChanged, + Runnable onCssChanged) { Container editorModeRow = new Container(new GridLayout(1, 2)); editorModeRow.setUIID("InitializrChoicesGrid"); ButtonGroup editorModeGroup = new ButtonGroup(); @@ -337,10 +348,10 @@ private Container createThemeOptionsPanel(ProjectOptions.ThemeMode[] selectedThe TextArea cssEditor = new TextArea(customThemeCss[0], 8, 30); cssEditor.setUIID("InitializrField"); - cssEditor.setGrowByContent(true); + cssEditor.setGrowByContent(false); cssEditor.addDataChangedListener((type, index) -> { customThemeCss[0] = cssEditor.getText(); - onSelectionChanged.run(); + onCssChanged.run(); }); Container simpleControls = BoxLayout.encloseY( @@ -373,20 +384,29 @@ private Container createThemeOptionsPanel(ProjectOptions.ThemeMode[] selectedThe } private String defaultAdvancedCss() { - return ":root {\n" + return "@constants {\n" + + " includeNativeBool: true;\n" + + " defaultSourceDPIInt: \"0\";\n" + + "}\n\n" + + ":root {\n" + " --primary: #1976d2;\n" + + " --surface: #f3f6fb;\n" + + " --text: #1f2937;\n" + + "}\n\n" + + "Container {\n" + + " background-color: var(--surface);\n" + "}\n\n" + "Toolbar {\n" - + " background-color: #f2f5fa;\n" - + " color: #1f2933;\n" + + " background-color: #eaf2ff;\n" + + " color: var(--text);\n" + "}\n\n" + "Title {\n" - + " color: #1f2933;\n" + + " color: var(--text);\n" + "}\n\n" + "Button {\n" + " background-color: var(--primary);\n" + " color: #ffffff;\n" - + " padding: 3px 6px;\n" + + " padding: 2px 4px;\n" + "}\n"; } diff --git a/scripts/initializr/common/src/main/java/com/codename1/initializr/ui/TemplatePreviewPanel.java b/scripts/initializr/common/src/main/java/com/codename1/initializr/ui/TemplatePreviewPanel.java index 20cbf7d677..991f32bb88 100644 --- a/scripts/initializr/common/src/main/java/com/codename1/initializr/ui/TemplatePreviewPanel.java +++ b/scripts/initializr/common/src/main/java/com/codename1/initializr/ui/TemplatePreviewPanel.java @@ -3,6 +3,7 @@ import com.codename1.components.ImageViewer; import com.codename1.initializr.model.ProjectOptions; import com.codename1.initializr.model.Template; +import com.codename1.components.ToastBar; import com.codename1.io.Log; import com.codename1.io.Properties; import com.codename1.ui.Button; @@ -32,6 +33,7 @@ public class TemplatePreviewPanel { private final Label staticPreviewFallback; private InterFormContainer liveFormPreview; private final Hashtable baseTheme; + private String lastCssError; private Template template; private ProjectOptions options = ProjectOptions.defaults(); @@ -108,7 +110,16 @@ private void applyThemeOptions(ProjectOptions options) { if (parsedTheme != null) { UIManager.getInstance().addThemeProps(parsedTheme); } + lastCssError = null; } catch (RuntimeException ex) { + String errorMessage = ex.getMessage(); + if (errorMessage == null || errorMessage.length() == 0) { + errorMessage = ex.toString(); + } + if (lastCssError == null || !lastCssError.equals(errorMessage)) { + ToastBar.showErrorMessage("CSS Error: " + errorMessage); + lastCssError = errorMessage; + } Log.e(ex); } } @@ -192,6 +203,17 @@ private void updateMode() { } private void applyLivePreviewOptions(Form form, Button button, Button menuButton, ProjectOptions options) { + if (options.themeEditorMode == ProjectOptions.ThemeEditorMode.ADVANCED) { + form.getContentPane().setUIID("Container"); + form.getToolbar().setUIID("Toolbar"); + form.getToolbar().getTitleComponent().setUIID("Title"); + if (menuButton != null) { + menuButton.setUIID("Command"); + } + button.setUIID("Button"); + return; + } + String mode = options.themeMode == ProjectOptions.ThemeMode.DARK ? "Dark" : "Light"; String accent = accentName(options.accent); boolean clean = options.accent == ProjectOptions.Accent.DEFAULT; From 3391ab04c24ad599d6dbec45ed2968cca58ce9e8 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sat, 28 Feb 2026 21:37:42 +0200 Subject: [PATCH 3/3] Fix advanced CSS editor visibility and typing issues --- .../initializr/common/src/main/css/theme.css | 20 +++++++++++++++ .../com/codename1/initializr/Initializr.java | 25 +++---------------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/scripts/initializr/common/src/main/css/theme.css b/scripts/initializr/common/src/main/css/theme.css index 5c8a96d9e4..7777bf8f6a 100644 --- a/scripts/initializr/common/src/main/css/theme.css +++ b/scripts/initializr/common/src/main/css/theme.css @@ -167,6 +167,26 @@ InitializrFieldDark, InitializrFieldHintDark { margin: 0 0 1.4mm 0; } +InitializrCssEditor { + color: #0f172a; + font-family: "native:MainRegular"; + font-size: 2.6mm; + background-color: #ffffff; + border: 1px solid #9fb6d5; + padding: 1.1mm; + margin: 0 0 1.4mm 0; +} + +InitializrCssEditorDark { + color: #f8fafc; + font-family: "native:MainRegular"; + font-size: 2.6mm; + background-color: #0b1220; + border: 1px solid #64748b; + padding: 1.1mm; + margin: 0 0 1.4mm 0; +} + InitializrChoicesGrid { margin: 0 0 1.2mm 0; } diff --git a/scripts/initializr/common/src/main/java/com/codename1/initializr/Initializr.java b/scripts/initializr/common/src/main/java/com/codename1/initializr/Initializr.java index 431234453a..3c0bffb9c9 100644 --- a/scripts/initializr/common/src/main/java/com/codename1/initializr/Initializr.java +++ b/scripts/initializr/common/src/main/java/com/codename1/initializr/Initializr.java @@ -56,7 +56,6 @@ public void runApp() { final RadioButton[] templateButtons = new RadioButton[Template.values().length]; final SpanLabel summaryLabel = new SpanLabel(); final TemplatePreviewPanel previewPanel = new TemplatePreviewPanel(selectedTemplate[0]); - final Container[] themePanelRef = new Container[1]; final UITimer[] cssRefreshTimer = new UITimer[1]; appNameField.setUIID("InitializrField"); @@ -78,10 +77,6 @@ public void run() { ); previewPanel.setTemplate(selectedTemplate[0]); previewPanel.setOptions(options); - boolean canCustomizeTheme = supportsLivePreview(selectedTemplate[0]); - if (themePanelRef[0] != null) { - setEnabledRecursive(themePanelRef[0], canCustomizeTheme); - } summaryLabel.setText(createSummary( appNameField.getText(), packageField.getText(), @@ -114,7 +109,6 @@ public void run() { final Container themePanel = createThemeOptionsPanel(selectedThemeMode, selectedThemeEditorMode, selectedAccent, roundedButtons, customThemeCss, refresh, scheduleCssRefresh); final Container localizationPanel = createLocalizationPanel(includeLocalizationBundles, previewLanguage, refresh, previewPanel); - themePanelRef[0] = themePanel; final Container settingsPanel = BoxLayout.encloseY(summaryLabel); Accordion advancedAccordion = new Accordion(); @@ -347,7 +341,8 @@ private Container createThemeOptionsPanel(ProjectOptions.ThemeMode[] selectedThe }); TextArea cssEditor = new TextArea(customThemeCss[0], 8, 30); - cssEditor.setUIID("InitializrField"); + cssEditor.setUIID("InitializrCssEditor"); + cssEditor.setEditable(true); cssEditor.setGrowByContent(false); cssEditor.addDataChangedListener((type, index) -> { customThemeCss[0] = cssEditor.getText(); @@ -484,10 +479,6 @@ private String formatEnumLabel(String text) { return StringUtil.replaceAll(text, "_", " "); } - private boolean supportsLivePreview(Template template) { - return template == Template.BAREBONES || template == Template.KOTLIN; - } - private void initWebsiteThemeSync(Form form) { WebsiteThemeNative websiteThemeNative = NativeLookup.create(WebsiteThemeNative.class); if (websiteThemeNative == null || !websiteThemeNative.isSupported()) { @@ -539,6 +530,7 @@ private String themedUiid(String uiid, boolean dark) { case "InitializrFieldLabel": case "InitializrField": case "InitializrFieldHint": + case "InitializrCssEditor": case "InitializrChoice": case "InitializrSummary": case "InitializrTip": @@ -568,6 +560,7 @@ private String themedUiid(String uiid, boolean dark) { case "InitializrFieldLabel": case "InitializrField": case "InitializrFieldHint": + case "InitializrCssEditor": case "InitializrChoice": case "InitializrSummary": case "InitializrTip": @@ -583,16 +576,6 @@ private String themedUiid(String uiid, boolean dark) { } } - private void setEnabledRecursive(Component component, boolean enabled) { - component.setEnabled(enabled); - if (component instanceof Container) { - Container cnt = (Container) component; - for (int i = 0; i < cnt.getComponentCount(); i++) { - setEnabledRecursive(cnt.getComponentAt(i), enabled); - } - } - } - private String createSummary(String appName, String packageName, Template template, IDE ide, ProjectOptions options) { String safeApp = appName == null ? "" : appName.trim(); String safePackage = packageName == null ? "" : packageName.trim();