andrud 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +69 -83
  2. package/dist/__tests__/context.test.d.ts +5 -0
  3. package/dist/__tests__/context.test.d.ts.map +1 -0
  4. package/dist/__tests__/context.test.js +86 -0
  5. package/dist/__tests__/context.test.js.map +1 -0
  6. package/dist/__tests__/generator.test.d.ts +5 -0
  7. package/dist/__tests__/generator.test.d.ts.map +1 -0
  8. package/dist/__tests__/generator.test.js +83 -0
  9. package/dist/__tests__/generator.test.js.map +1 -0
  10. package/dist/__tests__/validation.test.d.ts +5 -0
  11. package/dist/__tests__/validation.test.d.ts.map +1 -0
  12. package/dist/__tests__/validation.test.js +81 -0
  13. package/dist/__tests__/validation.test.js.map +1 -0
  14. package/dist/cli/commands/create.d.ts +10 -0
  15. package/dist/cli/commands/create.d.ts.map +1 -0
  16. package/dist/cli/commands/create.js +203 -0
  17. package/dist/cli/commands/create.js.map +1 -0
  18. package/dist/cli/commands/info.d.ts +13 -0
  19. package/dist/cli/commands/info.d.ts.map +1 -0
  20. package/dist/cli/commands/info.js +153 -0
  21. package/dist/cli/commands/info.js.map +1 -0
  22. package/dist/cli/commands/init.d.ts +15 -0
  23. package/dist/cli/commands/init.d.ts.map +1 -0
  24. package/dist/cli/commands/init.js +141 -0
  25. package/dist/cli/commands/init.js.map +1 -0
  26. package/dist/cli/commands/list.d.ts +18 -0
  27. package/dist/cli/commands/list.d.ts.map +1 -0
  28. package/dist/cli/commands/list.js +122 -0
  29. package/dist/cli/commands/list.js.map +1 -0
  30. package/dist/cli/commands/new.d.ts +22 -0
  31. package/dist/cli/commands/new.d.ts.map +1 -0
  32. package/dist/cli/commands/new.js +245 -0
  33. package/dist/cli/commands/new.js.map +1 -0
  34. package/dist/cli/index.d.ts +5 -0
  35. package/dist/cli/index.d.ts.map +1 -0
  36. package/dist/cli/index.js +99 -0
  37. package/dist/cli/index.js.map +1 -0
  38. package/dist/core/config.d.ts +89 -0
  39. package/dist/core/config.d.ts.map +1 -0
  40. package/dist/core/config.js +151 -0
  41. package/dist/core/config.js.map +1 -0
  42. package/dist/core/context.d.ts +47 -0
  43. package/dist/core/context.d.ts.map +1 -0
  44. package/dist/core/context.js +175 -0
  45. package/dist/core/context.js.map +1 -0
  46. package/dist/core/generator.d.ts +44 -0
  47. package/dist/core/generator.d.ts.map +1 -0
  48. package/{src/core/generator.ts → dist/core/generator.js} +394 -484
  49. package/dist/core/generator.js.map +1 -0
  50. package/dist/core/types.d.ts +125 -0
  51. package/dist/core/types.d.ts.map +1 -0
  52. package/dist/core/types.js +22 -0
  53. package/dist/core/types.js.map +1 -0
  54. package/dist/templates/index.d.ts +36 -0
  55. package/dist/templates/index.d.ts.map +1 -0
  56. package/dist/templates/index.js +141 -0
  57. package/dist/templates/index.js.map +1 -0
  58. package/dist/ui/colors.d.ts +40 -0
  59. package/dist/ui/colors.d.ts.map +1 -0
  60. package/dist/ui/colors.js +117 -0
  61. package/dist/ui/colors.js.map +1 -0
  62. package/dist/ui/output.d.ts +69 -0
  63. package/dist/ui/output.d.ts.map +1 -0
  64. package/dist/ui/output.js +199 -0
  65. package/dist/ui/output.js.map +1 -0
  66. package/dist/ui/prompts.d.ts +20 -0
  67. package/dist/ui/prompts.d.ts.map +1 -0
  68. package/dist/ui/prompts.js +118 -0
  69. package/dist/ui/prompts.js.map +1 -0
  70. package/dist/ui/spinners.d.ts +30 -0
  71. package/dist/ui/spinners.d.ts.map +1 -0
  72. package/dist/ui/spinners.js +74 -0
  73. package/dist/ui/spinners.js.map +1 -0
  74. package/dist/ui/types.d.ts +35 -0
  75. package/dist/ui/types.d.ts.map +1 -0
  76. package/dist/ui/types.js +5 -0
  77. package/dist/ui/types.js.map +1 -0
  78. package/dist/utils/filesystem.d.ts +38 -0
  79. package/dist/utils/filesystem.d.ts.map +1 -0
  80. package/dist/utils/filesystem.js +181 -0
  81. package/dist/utils/filesystem.js.map +1 -0
  82. package/dist/utils/logger.d.ts +27 -0
  83. package/dist/utils/logger.d.ts.map +1 -0
  84. package/dist/utils/logger.js +52 -0
  85. package/dist/utils/logger.js.map +1 -0
  86. package/dist/utils/object.d.ts +140 -0
  87. package/dist/utils/object.d.ts.map +1 -0
  88. package/dist/utils/object.js +385 -0
  89. package/dist/utils/object.js.map +1 -0
  90. package/dist/utils/validation.d.ts +35 -0
  91. package/dist/utils/validation.d.ts.map +1 -0
  92. package/dist/utils/validation.js +270 -0
  93. package/dist/utils/validation.js.map +1 -0
  94. package/package.json +8 -19
  95. package/CHANGELOG.md +0 -70
  96. package/CODE_REVIEW_ANALYSIS.md +0 -177
  97. package/CONTRIBUTING.md +0 -132
  98. package/FIXES_IMPLEMENTED.md +0 -546
  99. package/src/__tests__/context.test.ts +0 -133
  100. package/src/__tests__/generator.test.ts +0 -107
  101. package/src/__tests__/validation.test.ts +0 -105
  102. package/src/cli/commands/create.ts +0 -252
  103. package/src/cli/commands/info.ts +0 -178
  104. package/src/cli/commands/init.ts +0 -186
  105. package/src/cli/commands/list.ts +0 -156
  106. package/src/cli/commands/new.ts +0 -316
  107. package/src/cli/index.ts +0 -116
  108. package/src/core/config.ts +0 -172
  109. package/src/core/context.ts +0 -212
  110. package/src/core/types.ts +0 -184
  111. package/src/templates/index.ts +0 -162
  112. package/src/types/gradient-string.d.ts +0 -25
  113. package/src/ui/colors.ts +0 -139
  114. package/src/ui/output.ts +0 -230
  115. package/src/ui/prompts.ts +0 -170
  116. package/src/ui/spinners.ts +0 -95
  117. package/src/ui/types.ts +0 -41
  118. package/src/utils/filesystem.ts +0 -222
  119. package/src/utils/logger.ts +0 -67
  120. package/src/utils/object.ts +0 -456
  121. package/src/utils/validation.ts +0 -345
  122. package/tsconfig.json +0 -25
@@ -1,242 +1,204 @@
1
1
  /**
2
2
  * Project generator - creates Android project structure and files
3
3
  */
4
-
5
4
  import { exists, writeFile, createDirectory, isDirectory } from '../utils/filesystem.js';
6
- import type { TemplateContext, GenerationResult, GeneratedFile } from './types.js';
7
- import { buildTemplateContext, buildDefaultProjectContext } from './context.js';
8
5
  import { GRADLE_VERSIONS } from './config.js';
9
6
  import pc from 'picocolors';
10
7
  import { join } from 'path';
11
-
12
- export interface GeneratorOptions {
13
- overwrite?: boolean;
14
- skipInstall?: boolean;
15
- dryRun?: boolean;
16
- verbose?: boolean;
17
- }
18
-
19
8
  /**
20
9
  * Validate project directory can be used
21
10
  */
22
- export async function validateProjectDirectory(
23
- projectPath: string,
24
- options: { overwrite: boolean } = { overwrite: false }
25
- ): Promise<{ valid: boolean; error?: string; existingFiles?: string[] }> {
26
- const pathExists = await exists(projectPath);
27
-
28
- if (pathExists) {
29
- const isDir = await isDirectory(projectPath);
30
- if (!isDir) {
31
- return { valid: false, error: 'Project path exists but is not a directory' };
32
- }
33
-
34
- const dirContent = await getDirectoryContents(projectPath);
35
- if (dirContent.length > 0 && !options.overwrite) {
36
- return {
37
- valid: false,
38
- error: 'Directory is not empty. Use --force to overwrite existing files.',
39
- existingFiles: dirContent
40
- };
11
+ export async function validateProjectDirectory(projectPath, options = { overwrite: false }) {
12
+ const pathExists = await exists(projectPath);
13
+ if (pathExists) {
14
+ const isDir = await isDirectory(projectPath);
15
+ if (!isDir) {
16
+ return { valid: false, error: 'Project path exists but is not a directory' };
17
+ }
18
+ const dirContent = await getDirectoryContents(projectPath);
19
+ if (dirContent.length > 0 && !options.overwrite) {
20
+ return {
21
+ valid: false,
22
+ error: 'Directory is not empty. Use --force to overwrite existing files.',
23
+ existingFiles: dirContent
24
+ };
25
+ }
41
26
  }
42
- }
43
-
44
- return { valid: true };
27
+ return { valid: true };
45
28
  }
46
-
47
29
  /**
48
30
  * Validate context has all required fields
49
31
  */
50
- export function validateContext(context: Partial<TemplateContext>): { valid: boolean; errors: string[] } {
51
- const errors: string[] = [];
52
-
53
- if (!context.appName) errors.push('appName is required');
54
- if (!context.packageName) errors.push('packageName is required');
55
- if (!context.projectDirectory) errors.push('projectDirectory is required');
56
- if (!context.template) errors.push('template is required');
57
- if (!context.language) errors.push('language is required');
58
- if (!context.uiFramework) errors.push('uiFramework is required');
59
-
60
- return { valid: errors.length === 0, errors };
32
+ export function validateContext(context) {
33
+ const errors = [];
34
+ if (!context.appName)
35
+ errors.push('appName is required');
36
+ if (!context.packageName)
37
+ errors.push('packageName is required');
38
+ if (!context.projectDirectory)
39
+ errors.push('projectDirectory is required');
40
+ if (!context.template)
41
+ errors.push('template is required');
42
+ if (!context.language)
43
+ errors.push('language is required');
44
+ if (!context.uiFramework)
45
+ errors.push('uiFramework is required');
46
+ return { valid: errors.length === 0, errors };
61
47
  }
62
-
63
48
  /**
64
49
  * Prepare project directory structure
65
50
  */
66
- export async function prepareProjectStructure(
67
- projectPath: string,
68
- context: TemplateContext
69
- ): Promise<{ success: boolean; createdPaths: string[]; errors: string[] }> {
70
- const createdPaths: string[] = [];
71
- const errors: string[] = [];
72
-
73
- const directories = [
74
- '',
75
- 'gradle/wrapper',
76
- 'app/src/main/java',
77
- 'app/src/main/res/layout',
78
- 'app/src/main/res/values',
79
- 'app/src/main/res/values-night',
80
- 'app/src/main/res/drawable',
81
- 'app/src/main/res/xml',
82
- 'app/src/main/res/mipmap-anydpi-v26',
83
- 'app/src/main/res/mipmap-hdpi',
84
- 'app/src/main/res/mipmap-mdpi',
85
- 'app/src/main/res/mipmap-xhdpi',
86
- 'app/src/main/res/mipmap-xxhdpi',
87
- 'app/src/main/res/mipmap-xxxhdpi',
88
- 'app/src/test/java',
89
- 'app/src/androidTest/java',
90
- context.language === 'kotlin' ? 'app/src/main/kotlin' : '',
91
- context.template === 'native-cpp' ? 'app/src/main/cpp' : ''
92
- ].filter(d => d !== '');
93
-
94
- const packagePath = context.packageName.replace(/\./g, '/');
95
- directories.push(`app/src/main/java/${packagePath}`);
96
-
97
- if (context.language === 'kotlin') {
98
- directories.push(`app/src/main/kotlin/${packagePath}`);
99
- }
100
-
101
- // Add UI theme directories for Jetpack Compose projects
102
- if (context.uiFramework === 'compose' && context.language === 'kotlin') {
103
- directories.push(`app/src/main/kotlin/${packagePath}/ui`);
104
- directories.push(`app/src/main/kotlin/${packagePath}/ui/theme`);
105
- }
106
-
107
- // Add native cpp directories
108
- if (context.template === 'native-cpp') {
109
- directories.push(`app/src/main/cpp`);
110
- directories.push(`app/src/main/jni`);
111
- }
112
-
113
- for (const dir of directories) {
114
- const fullPath = join(projectPath, dir);
115
- try {
116
- await createDirectory(fullPath);
117
- createdPaths.push(dir);
118
- } catch (error) {
119
- errors.push(`Failed to create directory ${dir}: ${(error as Error).message}`);
51
+ export async function prepareProjectStructure(projectPath, context) {
52
+ const createdPaths = [];
53
+ const errors = [];
54
+ const directories = [
55
+ '',
56
+ 'gradle/wrapper',
57
+ 'app/src/main/java',
58
+ 'app/src/main/res/layout',
59
+ 'app/src/main/res/values',
60
+ 'app/src/main/res/values-night',
61
+ 'app/src/main/res/drawable',
62
+ 'app/src/main/res/xml',
63
+ 'app/src/main/res/mipmap-anydpi-v26',
64
+ 'app/src/main/res/mipmap-hdpi',
65
+ 'app/src/main/res/mipmap-mdpi',
66
+ 'app/src/main/res/mipmap-xhdpi',
67
+ 'app/src/main/res/mipmap-xxhdpi',
68
+ 'app/src/main/res/mipmap-xxxhdpi',
69
+ 'app/src/test/java',
70
+ 'app/src/androidTest/java',
71
+ context.language === 'kotlin' ? 'app/src/main/kotlin' : '',
72
+ context.template === 'native-cpp' ? 'app/src/main/cpp' : ''
73
+ ].filter(d => d !== '');
74
+ const packagePath = context.packageName.replace(/\./g, '/');
75
+ directories.push(`app/src/main/java/${packagePath}`);
76
+ if (context.language === 'kotlin') {
77
+ directories.push(`app/src/main/kotlin/${packagePath}`);
120
78
  }
121
- }
122
-
123
- return { success: errors.length === 0, createdPaths, errors };
79
+ // Add UI theme directories for Jetpack Compose projects
80
+ if (context.uiFramework === 'compose' && context.language === 'kotlin') {
81
+ directories.push(`app/src/main/kotlin/${packagePath}/ui`);
82
+ directories.push(`app/src/main/kotlin/${packagePath}/ui/theme`);
83
+ }
84
+ // Add native cpp directories
85
+ if (context.template === 'native-cpp') {
86
+ directories.push(`app/src/main/cpp`);
87
+ directories.push(`app/src/main/jni`);
88
+ }
89
+ for (const dir of directories) {
90
+ const fullPath = join(projectPath, dir);
91
+ try {
92
+ await createDirectory(fullPath);
93
+ createdPaths.push(dir);
94
+ }
95
+ catch (error) {
96
+ errors.push(`Failed to create directory ${dir}: ${error.message}`);
97
+ }
98
+ }
99
+ return { success: errors.length === 0, createdPaths, errors };
124
100
  }
125
-
126
101
  /**
127
102
  * Generate all project files
128
103
  */
129
- export async function generateProject(
130
- context: TemplateContext,
131
- options: GeneratorOptions = {}
132
- ): Promise<GenerationResult> {
133
- const startTime = Date.now();
134
- const generatedFiles: string[] = [];
135
- const skippedFiles: string[] = [];
136
- const errors: Array<{ file?: string; message: string; code?: string }> = [];
137
- const warnings: string[] = [];
138
- const projectPath = context.projectDirectory;
139
-
140
- const contextValidation = validateContext(context);
141
- if (!contextValidation.valid) {
142
- return {
143
- success: false,
144
- projectPath,
145
- generatedFiles: [],
146
- skippedFiles: [],
147
- errors: contextValidation.errors.map(msg => ({ message: msg })),
148
- warnings,
149
- duration: Date.now() - startTime
150
- };
151
- }
152
-
153
- const dirValidation = await validateProjectDirectory(projectPath, { overwrite: options.overwrite ?? false });
154
- if (!dirValidation.valid) {
155
- return {
156
- success: false,
157
- projectPath,
158
- generatedFiles: [],
159
- skippedFiles: [],
160
- errors: [{ message: dirValidation.error!, code: 'DIR_VALIDATION_ERROR' }],
161
- warnings,
162
- duration: Date.now() - startTime
163
- };
164
- }
165
-
166
- const prepResult = await prepareProjectStructure(projectPath, context);
167
- if (!prepResult.success) {
168
- errors.push(...prepResult.errors.map(msg => ({ message: msg, code: 'DIR_CREATE_ERROR' })));
169
- }
170
- generatedFiles.push(...prepResult.createdPaths);
171
-
172
- const filesToGenerate: GeneratedFile[] = [
173
- generateSettingsGradle(context),
174
- generateRootBuildGradle(context),
175
- generateGradleProperties(context),
176
- generateGitIgnore(context),
177
- generateReadme(context),
178
- generateGradleWrapperProperties(context),
179
- generateGradlewBat(context),
180
- generateGradlewUnix(context),
181
- generateAppBuildGradle(context),
182
- generateAppProguardRules(context),
183
- generateAppManifest(context),
184
- generateApplicationClass(context),
185
- generateMainActivity(context),
186
- generateStrings(context),
187
- generateColors(context),
188
- generateThemes(context),
189
- generateAppIcon(context),
190
- generateActivityLayout(context),
191
- ...generateSourceSetFiles(context)
192
- ].filter((f): f is GeneratedFile => f !== null && typeof f === 'object' && 'path' in f);
193
-
194
- for (const file of filesToGenerate) {
195
- try {
196
- const filePath = join(projectPath, file.path);
197
- const fileExists = await exists(filePath);
198
-
199
- if (fileExists && !options.overwrite && file.overwrite !== true) {
200
- skippedFiles.push(file.path);
201
- if (options.verbose) {
202
- console.log(pc.yellow(`Skipped: ${file.path} (already exists)`));
104
+ export async function generateProject(context, options = {}) {
105
+ const startTime = Date.now();
106
+ const generatedFiles = [];
107
+ const skippedFiles = [];
108
+ const errors = [];
109
+ const warnings = [];
110
+ const projectPath = context.projectDirectory;
111
+ const contextValidation = validateContext(context);
112
+ if (!contextValidation.valid) {
113
+ return {
114
+ success: false,
115
+ projectPath,
116
+ generatedFiles: [],
117
+ skippedFiles: [],
118
+ errors: contextValidation.errors.map(msg => ({ message: msg })),
119
+ warnings,
120
+ duration: Date.now() - startTime
121
+ };
122
+ }
123
+ const dirValidation = await validateProjectDirectory(projectPath, { overwrite: options.overwrite ?? false });
124
+ if (!dirValidation.valid) {
125
+ return {
126
+ success: false,
127
+ projectPath,
128
+ generatedFiles: [],
129
+ skippedFiles: [],
130
+ errors: [{ message: dirValidation.error, code: 'DIR_VALIDATION_ERROR' }],
131
+ warnings,
132
+ duration: Date.now() - startTime
133
+ };
134
+ }
135
+ const prepResult = await prepareProjectStructure(projectPath, context);
136
+ if (!prepResult.success) {
137
+ errors.push(...prepResult.errors.map(msg => ({ message: msg, code: 'DIR_CREATE_ERROR' })));
138
+ }
139
+ generatedFiles.push(...prepResult.createdPaths);
140
+ const filesToGenerate = [
141
+ generateSettingsGradle(context),
142
+ generateRootBuildGradle(context),
143
+ generateGradleProperties(context),
144
+ generateGitIgnore(context),
145
+ generateReadme(context),
146
+ generateGradleWrapperProperties(context),
147
+ generateGradlewBat(context),
148
+ generateGradlewUnix(context),
149
+ generateAppBuildGradle(context),
150
+ generateAppProguardRules(context),
151
+ generateAppManifest(context),
152
+ generateApplicationClass(context),
153
+ generateMainActivity(context),
154
+ generateStrings(context),
155
+ generateColors(context),
156
+ generateThemes(context),
157
+ generateAppIcon(context),
158
+ generateActivityLayout(context),
159
+ ...generateSourceSetFiles(context)
160
+ ].filter((f) => f !== null && typeof f === 'object' && 'path' in f);
161
+ for (const file of filesToGenerate) {
162
+ try {
163
+ const filePath = join(projectPath, file.path);
164
+ const fileExists = await exists(filePath);
165
+ if (fileExists && !options.overwrite && file.overwrite !== true) {
166
+ skippedFiles.push(file.path);
167
+ if (options.verbose) {
168
+ console.log(pc.yellow(`Skipped: ${file.path} (already exists)`));
169
+ }
170
+ continue;
171
+ }
172
+ await writeFile(filePath, file.content);
173
+ generatedFiles.push(file.path);
174
+ if (options.verbose) {
175
+ console.log(pc.green(`Generated: ${file.path}`));
176
+ }
177
+ }
178
+ catch (error) {
179
+ errors.push({
180
+ file: file.path,
181
+ message: error.message,
182
+ code: 'WRITE_ERROR'
183
+ });
203
184
  }
204
- continue;
205
- }
206
-
207
- await writeFile(filePath, file.content);
208
- generatedFiles.push(file.path);
209
-
210
- if (options.verbose) {
211
- console.log(pc.green(`Generated: ${file.path}`));
212
- }
213
- } catch (error) {
214
- errors.push({
215
- file: file.path,
216
- message: (error as Error).message,
217
- code: 'WRITE_ERROR'
218
- });
219
185
  }
220
- }
221
-
222
- const duration = Date.now() - startTime;
223
- const success = errors.length === 0;
224
-
225
- return {
226
- success,
227
- projectPath,
228
- generatedFiles,
229
- skippedFiles,
230
- errors,
231
- warnings,
232
- duration
233
- };
186
+ const duration = Date.now() - startTime;
187
+ const success = errors.length === 0;
188
+ return {
189
+ success,
190
+ projectPath,
191
+ generatedFiles,
192
+ skippedFiles,
193
+ errors,
194
+ warnings,
195
+ duration
196
+ };
234
197
  }
235
-
236
- function generateSettingsGradle(ctx: TemplateContext): GeneratedFile {
237
- return {
238
- path: 'settings.gradle.kts',
239
- content: `pluginManagement {
198
+ function generateSettingsGradle(ctx) {
199
+ return {
200
+ path: 'settings.gradle.kts',
201
+ content: `pluginManagement {
240
202
  repositories {
241
203
  google()
242
204
  mavenCentral()
@@ -255,32 +217,27 @@ dependencyResolutionManagement {
255
217
  rootProject.name = "${ctx.appName}"
256
218
  include(":app")
257
219
  `
258
- };
220
+ };
259
221
  }
260
-
261
- function generateRootBuildGradle(ctx: TemplateContext): GeneratedFile {
262
- const kotlinPlugin = ctx.language === 'kotlin' ? `
222
+ function generateRootBuildGradle(ctx) {
223
+ const kotlinPlugin = ctx.language === 'kotlin' ? `
263
224
  id("org.jetbrains.kotlin.android") version "${ctx.gradle.kotlinVersion || GRADLE_VERSIONS.KOTLIN}" apply false` : '';
264
-
265
- const composePlugin = ctx.uiFramework === 'compose' ? `
225
+ const composePlugin = ctx.uiFramework === 'compose' ? `
266
226
  id("org.jetbrains.kotlin.plugin.compose") version "${ctx.gradle.kotlinVersion || GRADLE_VERSIONS.KOTLIN}" apply false` : '';
267
-
268
- const kaptPlugin = ctx.language === 'kotlin' ? `
227
+ const kaptPlugin = ctx.language === 'kotlin' ? `
269
228
  id("org.jetbrains.kotlin.kapt") version "${ctx.gradle.kotlinVersion || GRADLE_VERSIONS.KOTLIN}" apply false` : '';
270
-
271
- return {
272
- path: 'build.gradle.kts',
273
- content: `plugins {
229
+ return {
230
+ path: 'build.gradle.kts',
231
+ content: `plugins {
274
232
  id("com.android.application") version "${ctx.gradle.agpVersion}" apply false${kotlinPlugin}${composePlugin}${kaptPlugin}
275
233
  }
276
234
  `
277
- };
235
+ };
278
236
  }
279
-
280
- function generateGradleProperties(_ctx: TemplateContext): GeneratedFile {
281
- return {
282
- path: 'gradle.properties',
283
- content: `# Project-wide Gradle settings
237
+ function generateGradleProperties(_ctx) {
238
+ return {
239
+ path: 'gradle.properties',
240
+ content: `# Project-wide Gradle settings
284
241
  org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
285
242
  org.gradle.parallel=true
286
243
  org.gradle.caching=true
@@ -294,13 +251,12 @@ android.suppressUnsupportedCompileSdk=36
294
251
  # Kotlin settings
295
252
  kotlin.code.style=official
296
253
  `
297
- };
254
+ };
298
255
  }
299
-
300
- function generateGitIgnore(_ctx: TemplateContext): GeneratedFile {
301
- return {
302
- path: '.gitignore',
303
- content: `# Built application files
256
+ function generateGitIgnore(_ctx) {
257
+ return {
258
+ path: '.gitignore',
259
+ content: `# Built application files
304
260
  *.apk
305
261
  *.ap_
306
262
  *.aab
@@ -325,16 +281,14 @@ captures/
325
281
  google-services.json
326
282
  vcs.xml
327
283
  `
328
- };
284
+ };
329
285
  }
330
-
331
- function generateReadme(ctx: TemplateContext): GeneratedFile {
332
- const lang = ctx.language === 'kotlin' ? 'Kotlin' : 'Java';
333
- const ui = ctx.uiFramework === 'compose' ? 'Jetpack Compose' : 'XML Layouts';
334
-
335
- return {
336
- path: 'README.md',
337
- content: `# ${ctx.appName}
286
+ function generateReadme(ctx) {
287
+ const lang = ctx.language === 'kotlin' ? 'Kotlin' : 'Java';
288
+ const ui = ctx.uiFramework === 'compose' ? 'Jetpack Compose' : 'XML Layouts';
289
+ return {
290
+ path: 'README.md',
291
+ content: `# ${ctx.appName}
338
292
 
339
293
  An Android application built with ${lang} using ${ui}.
340
294
 
@@ -352,13 +306,12 @@ An Android application built with ${lang} using ${ui}.
352
306
  ## License
353
307
  MIT License
354
308
  `
355
- };
309
+ };
356
310
  }
357
-
358
- function generateGradleWrapperProperties(ctx: TemplateContext): GeneratedFile {
359
- return {
360
- path: 'gradle/wrapper/gradle-wrapper.properties',
361
- content: `distributionBase=GRADLE_USER_HOME
311
+ function generateGradleWrapperProperties(ctx) {
312
+ return {
313
+ path: 'gradle/wrapper/gradle-wrapper.properties',
314
+ content: `distributionBase=GRADLE_USER_HOME
362
315
  distributionPath=wrapper/dists
363
316
  distributionUrl=https\\://services.gradle.org/distributions/gradle-${ctx.gradle.gradleVersion}-bin.zip
364
317
  networkTimeout=10000
@@ -366,13 +319,12 @@ validateDistributionUrl=true
366
319
  zipStoreBase=GRADLE_USER_HOME
367
320
  zipStorePath=wrapper/dists
368
321
  `
369
- };
322
+ };
370
323
  }
371
-
372
- function generateGradlewBat(_ctx: TemplateContext): GeneratedFile {
373
- return {
374
- path: 'gradlew.bat',
375
- content: `@echo off
324
+ function generateGradlewBat(_ctx) {
325
+ return {
326
+ path: 'gradlew.bat',
327
+ content: `@echo off
376
328
  setlocal enabledelayedexpansion
377
329
  set DIRNAME=%~dp0
378
330
  if "%DIRNAME%"=="" set DIRNAME=.
@@ -395,13 +347,12 @@ exit /b 1
395
347
  :mainEnd
396
348
  endlocal
397
349
  `
398
- };
350
+ };
399
351
  }
400
-
401
- function generateGradlewUnix(_ctx: TemplateContext): GeneratedFile {
402
- return {
403
- path: 'gradlew',
404
- content: `#!/bin/sh
352
+ function generateGradlewUnix(_ctx) {
353
+ return {
354
+ path: 'gradlew',
355
+ content: `#!/bin/sh
405
356
 
406
357
  APP_HOME=$(dirname "$(cd "$(dirname "$0")" && pwd)")
407
358
  CLASSPATH="$APP_HOME/gradle/wrapper/gradle-wrapper.jar"
@@ -421,23 +372,20 @@ DEFAULT_JVM_OPTS="-Xmx64m -Xms64m"
421
372
 
422
373
  exec "$JAVACMD" $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "-Dorg.gradle.appname=$(basename "$0")" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
423
374
  `
424
- };
375
+ };
425
376
  }
426
-
427
- function generateAppBuildGradle(ctx: TemplateContext): GeneratedFile {
428
- const isCompose = ctx.uiFramework === 'compose';
429
- const isKotlin = ctx.language === 'kotlin';
430
-
431
- let plugins = 'plugins {\n id("com.android.application")\n';
432
- if (isKotlin) {
433
- plugins += ' id("org.jetbrains.kotlin.android")\n';
434
- if (isCompose) {
435
- plugins += ' id("org.jetbrains.kotlin.plugin.compose")\n';
377
+ function generateAppBuildGradle(ctx) {
378
+ const isCompose = ctx.uiFramework === 'compose';
379
+ const isKotlin = ctx.language === 'kotlin';
380
+ let plugins = 'plugins {\n id("com.android.application")\n';
381
+ if (isKotlin) {
382
+ plugins += ' id("org.jetbrains.kotlin.android")\n';
383
+ if (isCompose) {
384
+ plugins += ' id("org.jetbrains.kotlin.plugin.compose")\n';
385
+ }
436
386
  }
437
- }
438
- plugins += '}\n';
439
-
440
- let config = `android {
387
+ plugins += '}\n';
388
+ let config = `android {
441
389
  namespace = "${ctx.packageName}"
442
390
  compileSdk = ${ctx.android.compileSdk}
443
391
 
@@ -449,14 +397,13 @@ function generateAppBuildGradle(ctx: TemplateContext): GeneratedFile {
449
397
  versionName = "1.0.0"
450
398
  testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
451
399
  `;
452
-
453
- if (isCompose) {
454
- config += ` vectorDrawables {
400
+ if (isCompose) {
401
+ config += ` vectorDrawables {
455
402
  useSupportLibrary = true
456
403
  }
457
404
  `;
458
- }
459
- config += ` }
405
+ }
406
+ config += ` }
460
407
 
461
408
  buildTypes {
462
409
  release {
@@ -473,22 +420,19 @@ function generateAppBuildGradle(ctx: TemplateContext): GeneratedFile {
473
420
  targetCompatibility = JavaVersion.VERSION_17
474
421
  }
475
422
  `;
476
-
477
- if (isKotlin) {
478
- config += ` kotlinOptions {
423
+ if (isKotlin) {
424
+ config += ` kotlinOptions {
479
425
  jvmTarget = "17"
480
426
  }
481
427
  `;
482
- }
483
-
484
- if (isCompose) {
485
- config += ` buildFeatures {
428
+ }
429
+ if (isCompose) {
430
+ config += ` buildFeatures {
486
431
  compose = true
487
432
  }
488
433
  `;
489
- }
490
-
491
- config += ` packaging {
434
+ }
435
+ config += ` packaging {
492
436
  resources {
493
437
  excludes += "/META-INF/{AL2.0,LGPL2.1}"
494
438
  }
@@ -501,9 +445,8 @@ dependencies {
501
445
  implementation("com.google.android.material:material:1.12.0")
502
446
  implementation("androidx.constraintlayout:constraintlayout:2.1.4")
503
447
  `;
504
-
505
- if (isCompose) {
506
- config += ` implementation(platform("androidx.compose:compose-bom:2025.01.00"))
448
+ if (isCompose) {
449
+ config += ` implementation(platform("androidx.compose:compose-bom:2025.01.00"))
507
450
  implementation("androidx.compose.ui:ui")
508
451
  implementation("androidx.compose.ui:ui-graphics")
509
452
  implementation("androidx.compose.ui:ui-tooling-preview")
@@ -515,21 +458,18 @@ dependencies {
515
458
  debugImplementation("androidx.compose.ui:ui-tooling")
516
459
  debugImplementation("androidx.compose.ui:ui-test-manifest")
517
460
  `;
518
- } else {
519
- config += ` implementation("androidx.activity:activity-ktx:1.9.2")
461
+ }
462
+ else {
463
+ config += ` implementation("androidx.activity:activity-ktx:1.9.2")
520
464
  implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.5")
521
465
  implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.5")
522
466
  `;
523
- }
524
-
525
- // Add native C++ configuration if needed
526
- if (ctx.template === 'native-cpp') {
527
- const ndkVersion = ctx.nativeCpp?.ndkVersion ?? '28.2.13676358';
528
- const abiFilters = ctx.nativeCpp?.abiFilters?.join(', ') ?? '"armeabi-v7a", "arm64-v8a", "x86", "x86_64"';
529
-
530
- config = config.replace(
531
- 'kotlinOptions {',
532
- `externalNativeBuild {
467
+ }
468
+ // Add native C++ configuration if needed
469
+ if (ctx.template === 'native-cpp') {
470
+ const ndkVersion = ctx.nativeCpp?.ndkVersion ?? '28.2.13676358';
471
+ const abiFilters = ctx.nativeCpp?.abiFilters?.join(', ') ?? '"armeabi-v7a", "arm64-v8a", "x86", "x86_64"';
472
+ config = config.replace('kotlinOptions {', `externalNativeBuild {
533
473
  cmake {
534
474
  cppFlags += "-std=c++17"
535
475
  arguments += "-DANDROID_STL=c++_static"
@@ -537,29 +477,25 @@ dependencies {
537
477
  }
538
478
 
539
479
  ndk {
540
- abiFilters += [${abiFilters.split(', ').map((a: string) => `"${a.replace(/"/g, '')}"`).join(', ')}]
480
+ abiFilters += [${abiFilters.split(', ').map((a) => `"${a.replace(/"/g, '')}"`).join(', ')}]
541
481
  }
542
482
 
543
- kotlinOptions {`
544
- );
545
- }
546
-
547
- config += ` testImplementation("junit:junit:4.13.2")
483
+ kotlinOptions {`);
484
+ }
485
+ config += ` testImplementation("junit:junit:4.13.2")
548
486
  androidTestImplementation("androidx.test.ext:junit:1.2.1")
549
487
  androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
550
488
  }
551
489
  `;
552
-
553
- return {
554
- path: 'app/build.gradle.kts',
555
- content: plugins + config
556
- };
490
+ return {
491
+ path: 'app/build.gradle.kts',
492
+ content: plugins + config
493
+ };
557
494
  }
558
-
559
- function generateAppProguardRules(_ctx: TemplateContext): GeneratedFile {
560
- return {
561
- path: 'app/proguard-rules.pro',
562
- content: `# ProGuard rules for Android
495
+ function generateAppProguardRules(_ctx) {
496
+ return {
497
+ path: 'app/proguard-rules.pro',
498
+ content: `# ProGuard rules for Android
563
499
  -keepattributes SourceFile,LineNumberTable
564
500
  -renamesourcefileattribute SourceFile
565
501
  -keep class kotlin.** { *; }
@@ -568,15 +504,13 @@ function generateAppProguardRules(_ctx: TemplateContext): GeneratedFile {
568
504
  -keep class androidx.** { *; }
569
505
  -keep interface androidx.** { *; }
570
506
  `
571
- };
507
+ };
572
508
  }
573
-
574
- function generateAppManifest(ctx: TemplateContext): GeneratedFile {
575
- const activityClass = ctx.language === 'kotlin' ? 'MainActivity' : '.MainActivity';
576
-
577
- return {
578
- path: 'app/src/main/AndroidManifest.xml',
579
- content: `<?xml version="1.0" encoding="utf-8"?>
509
+ function generateAppManifest(ctx) {
510
+ const activityClass = ctx.language === 'kotlin' ? 'MainActivity' : '.MainActivity';
511
+ return {
512
+ path: 'app/src/main/AndroidManifest.xml',
513
+ content: `<?xml version="1.0" encoding="utf-8"?>
580
514
  <manifest xmlns:android="http://schemas.android.com/apk/res/android">
581
515
 
582
516
  <application
@@ -601,17 +535,15 @@ function generateAppManifest(ctx: TemplateContext): GeneratedFile {
601
535
 
602
536
  </manifest>
603
537
  `
604
- };
538
+ };
605
539
  }
606
-
607
- function generateApplicationClass(ctx: TemplateContext): GeneratedFile {
608
- const packagePath = ctx.packagePath;
609
- const className = `${ctx.appNamePascal}Application`;
610
-
611
- if (ctx.language === 'kotlin') {
612
- return {
613
- path: `app/src/main/kotlin/${packagePath}/${className}.kt`,
614
- content: `package ${ctx.packageName}
540
+ function generateApplicationClass(ctx) {
541
+ const packagePath = ctx.packagePath;
542
+ const className = `${ctx.appNamePascal}Application`;
543
+ if (ctx.language === 'kotlin') {
544
+ return {
545
+ path: `app/src/main/kotlin/${packagePath}/${className}.kt`,
546
+ content: `package ${ctx.packageName}
615
547
 
616
548
  import android.app.Application
617
549
 
@@ -621,11 +553,12 @@ class ${className} : Application() {
621
553
  }
622
554
  }
623
555
  `
624
- };
625
- } else {
626
- return {
627
- path: `app/src/main/java/${packagePath}/${className}.java`,
628
- content: `package ${ctx.packageName};
556
+ };
557
+ }
558
+ else {
559
+ return {
560
+ path: `app/src/main/java/${packagePath}/${className}.java`,
561
+ content: `package ${ctx.packageName};
629
562
 
630
563
  import android.app.Application;
631
564
 
@@ -636,17 +569,15 @@ public class ${className} extends Application {
636
569
  }
637
570
  }
638
571
  `
639
- };
640
- }
572
+ };
573
+ }
641
574
  }
642
-
643
- function generateMainActivity(ctx: TemplateContext): GeneratedFile {
644
- const packagePath = ctx.packagePath;
645
-
646
- if (ctx.uiFramework === 'compose' && ctx.language === 'kotlin') {
647
- return {
648
- path: `app/src/main/kotlin/${packagePath}/MainActivity.kt`,
649
- content: `package ${ctx.packageName}
575
+ function generateMainActivity(ctx) {
576
+ const packagePath = ctx.packagePath;
577
+ if (ctx.uiFramework === 'compose' && ctx.language === 'kotlin') {
578
+ return {
579
+ path: `app/src/main/kotlin/${packagePath}/MainActivity.kt`,
580
+ content: `package ${ctx.packageName}
650
581
 
651
582
  import android.os.Bundle
652
583
  import androidx.activity.ComponentActivity
@@ -752,13 +683,12 @@ fun MainScreen() {
752
683
  }
753
684
  }
754
685
  `
755
- };
756
- }
757
-
758
- if (ctx.language === 'kotlin') {
759
- return {
760
- path: `app/src/main/kotlin/${packagePath}/MainActivity.kt`,
761
- content: `package ${ctx.packageName}
686
+ };
687
+ }
688
+ if (ctx.language === 'kotlin') {
689
+ return {
690
+ path: `app/src/main/kotlin/${packagePath}/MainActivity.kt`,
691
+ content: `package ${ctx.packageName}
762
692
 
763
693
  import android.os.Bundle
764
694
  import androidx.appcompat.app.AppCompatActivity
@@ -789,12 +719,11 @@ class MainActivity : AppCompatActivity() {
789
719
  }
790
720
  }
791
721
  `
792
- };
793
- }
794
-
795
- return {
796
- path: `app/src/main/java/${packagePath}/MainActivity.java`,
797
- content: `package ${ctx.packageName};
722
+ };
723
+ }
724
+ return {
725
+ path: `app/src/main/java/${packagePath}/MainActivity.java`,
726
+ content: `package ${ctx.packageName};
798
727
 
799
728
  import android.os.Bundle;
800
729
  import androidx.appcompat.app.AppCompatActivity;
@@ -823,28 +752,25 @@ public class MainActivity extends AppCompatActivity {
823
752
  }
824
753
  }
825
754
  `
826
- };
755
+ };
827
756
  }
828
-
829
- function generateStrings(ctx: TemplateContext): GeneratedFile {
830
- const displayName = ctx.appName.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
831
-
832
- return {
833
- path: 'app/src/main/res/values/strings.xml',
834
- content: `<?xml version="1.0" encoding="utf-8"?>
757
+ function generateStrings(ctx) {
758
+ const displayName = ctx.appName.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
759
+ return {
760
+ path: 'app/src/main/res/values/strings.xml',
761
+ content: `<?xml version="1.0" encoding="utf-8"?>
835
762
  <resources>
836
763
  <string name="app_name">${displayName}</string>
837
764
  <string name="app_name_short">${ctx.appNamePascal}</string>
838
765
  <string name="content_description_app_icon">Application icon</string>
839
766
  </resources>
840
767
  `
841
- };
768
+ };
842
769
  }
843
-
844
- function generateColors(_ctx: TemplateContext): GeneratedFile {
845
- return {
846
- path: 'app/src/main/res/values/colors.xml',
847
- content: `<?xml version="1.0" encoding="utf-8"?>
770
+ function generateColors(_ctx) {
771
+ return {
772
+ path: 'app/src/main/res/values/colors.xml',
773
+ content: `<?xml version="1.0" encoding="utf-8"?>
848
774
  <resources>
849
775
  <!-- Primary Colors -->
850
776
  <color name="primary">#6750A4</color>
@@ -875,16 +801,14 @@ function generateColors(_ctx: TemplateContext): GeneratedFile {
875
801
  <color name="ic_launcher_background">#6750A4</color>
876
802
  </resources>
877
803
  `
878
- };
804
+ };
879
805
  }
880
-
881
- function generateThemes(ctx: TemplateContext): GeneratedFile {
882
- const themeName = `Theme.${ctx.appNamePascal}`;
883
-
884
- if (ctx.uiFramework === 'compose') {
885
- return {
886
- path: 'app/src/main/res/values/themes.xml',
887
- content: `<?xml version="1.0" encoding="utf-8"?>
806
+ function generateThemes(ctx) {
807
+ const themeName = `Theme.${ctx.appNamePascal}`;
808
+ if (ctx.uiFramework === 'compose') {
809
+ return {
810
+ path: 'app/src/main/res/values/themes.xml',
811
+ content: `<?xml version="1.0" encoding="utf-8"?>
888
812
  <resources>
889
813
  <style name="${themeName}" parent="Theme.Material3.Light.NoActionBar">
890
814
  <item name="android:statusBarColor">@android:color/transparent</item>
@@ -894,12 +818,11 @@ function generateThemes(ctx: TemplateContext): GeneratedFile {
894
818
  </style>
895
819
  </resources>
896
820
  `
897
- };
898
- }
899
-
900
- return {
901
- path: 'app/src/main/res/values/themes.xml',
902
- content: `<?xml version="1.0" encoding="utf-8"?>
821
+ };
822
+ }
823
+ return {
824
+ path: 'app/src/main/res/values/themes.xml',
825
+ content: `<?xml version="1.0" encoding="utf-8"?>
903
826
  <resources>
904
827
  <style name="${themeName}" parent="Theme.Material3.Light.NoActionBar">
905
828
  <item name="colorPrimary">@color/primary</item>
@@ -923,26 +846,24 @@ function generateThemes(ctx: TemplateContext): GeneratedFile {
923
846
  </style>
924
847
  </resources>
925
848
  `
926
- };
849
+ };
927
850
  }
928
-
929
- function generateAppIcon(_ctx: TemplateContext): GeneratedFile {
930
- return {
931
- path: 'app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml',
932
- content: `<?xml version="1.0" encoding="utf-8"?>
851
+ function generateAppIcon(_ctx) {
852
+ return {
853
+ path: 'app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml',
854
+ content: `<?xml version="1.0" encoding="utf-8"?>
933
855
  <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
934
856
  <background android:drawable="@drawable/ic_launcher_background"/>
935
857
  <foreground android:drawable="@drawable/ic_launcher_foreground"/>
936
858
  </adaptive-icon>
937
859
  `
938
- };
860
+ };
939
861
  }
940
-
941
- function generateActivityLayout(ctx: TemplateContext): GeneratedFile {
942
- if (ctx.uiFramework === 'compose') {
943
- return {
944
- path: 'app/src/main/res/layout/activity_main.xml',
945
- content: `<?xml version="1.0" encoding="utf-8"?>
862
+ function generateActivityLayout(ctx) {
863
+ if (ctx.uiFramework === 'compose') {
864
+ return {
865
+ path: 'app/src/main/res/layout/activity_main.xml',
866
+ content: `<?xml version="1.0" encoding="utf-8"?>
946
867
  <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
947
868
  android:layout_width="match_parent"
948
869
  android:layout_height="match_parent"
@@ -959,12 +880,11 @@ function generateActivityLayout(ctx: TemplateContext): GeneratedFile {
959
880
 
960
881
  </FrameLayout>
961
882
  `
962
- };
963
- }
964
-
965
- return {
966
- path: 'app/src/main/res/layout/activity_main.xml',
967
- content: `<?xml version="1.0" encoding="utf-8"?>
883
+ };
884
+ }
885
+ return {
886
+ path: 'app/src/main/res/layout/activity_main.xml',
887
+ content: `<?xml version="1.0" encoding="utf-8"?>
968
888
  <androidx.constraintlayout.widget.ConstraintLayout
969
889
  xmlns:android="http://schemas.android.com/apk/res/android"
970
890
  xmlns:app="http://schemas.android.com/apk/res-auto"
@@ -999,17 +919,15 @@ function generateActivityLayout(ctx: TemplateContext): GeneratedFile {
999
919
 
1000
920
  </androidx.constraintlayout.widget.ConstraintLayout>
1001
921
  `
1002
- };
922
+ };
1003
923
  }
1004
-
1005
- function generateSourceSetFiles(ctx: TemplateContext): GeneratedFile[] {
1006
- const files: GeneratedFile[] = [];
1007
- const packagePath = ctx.packagePath;
1008
-
1009
- // Professional adaptive icon background
1010
- files.push({
1011
- path: 'app/src/main/res/drawable/ic_launcher_background.xml',
1012
- content: `<?xml version="1.0" encoding="utf-8"?>
924
+ function generateSourceSetFiles(ctx) {
925
+ const files = [];
926
+ const packagePath = ctx.packagePath;
927
+ // Professional adaptive icon background
928
+ files.push({
929
+ path: 'app/src/main/res/drawable/ic_launcher_background.xml',
930
+ content: `<?xml version="1.0" encoding="utf-8"?>
1013
931
  <vector xmlns:android="http://schemas.android.com/apk/res/android"
1014
932
  android:width="108dp"
1015
933
  android:height="108dp"
@@ -1020,12 +938,11 @@ function generateSourceSetFiles(ctx: TemplateContext): GeneratedFile[] {
1020
938
  android:pathData="M0,0h108v108h-108z"/>
1021
939
  </vector>
1022
940
  `
1023
- });
1024
-
1025
- // Professional icon foreground - Android robot stylized "A"
1026
- files.push({
1027
- path: 'app/src/main/res/drawable/ic_launcher_foreground.xml',
1028
- content: `<?xml version="1.0" encoding="utf-8"?>
941
+ });
942
+ // Professional icon foreground - Android robot stylized "A"
943
+ files.push({
944
+ path: 'app/src/main/res/drawable/ic_launcher_foreground.xml',
945
+ content: `<?xml version="1.0" encoding="utf-8"?>
1029
946
  <vector xmlns:android="http://schemas.android.com/apk/res/android"
1030
947
  android:width="108dp"
1031
948
  android:height="108dp"
@@ -1053,22 +970,20 @@ function generateSourceSetFiles(ctx: TemplateContext): GeneratedFile[] {
1053
970
  </group>
1054
971
  </vector>
1055
972
  `
1056
- });
1057
-
1058
- files.push({
1059
- path: 'app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml',
1060
- content: `<?xml version="1.0" encoding="utf-8"?>
973
+ });
974
+ files.push({
975
+ path: 'app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml',
976
+ content: `<?xml version="1.0" encoding="utf-8"?>
1061
977
  <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
1062
978
  <background android:drawable="@drawable/ic_launcher_background"/>
1063
979
  <foreground android:drawable="@drawable/ic_launcher_foreground"/>
1064
980
  </adaptive-icon>
1065
981
  `
1066
- });
1067
-
1068
- // Add icon for FAB
1069
- files.push({
1070
- path: 'app/src/main/res/drawable/ic_add.xml',
1071
- content: `<?xml version="1.0" encoding="utf-8"?>
982
+ });
983
+ // Add icon for FAB
984
+ files.push({
985
+ path: 'app/src/main/res/drawable/ic_add.xml',
986
+ content: `<?xml version="1.0" encoding="utf-8"?>
1072
987
  <vector xmlns:android="http://schemas.android.com/apk/res/android"
1073
988
  android:width="24dp"
1074
989
  android:height="24dp"
@@ -1079,12 +994,11 @@ function generateSourceSetFiles(ctx: TemplateContext): GeneratedFile[] {
1079
994
  android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
1080
995
  </vector>
1081
996
  `
1082
- });
1083
-
1084
- if (ctx.uiFramework === 'compose') {
1085
- files.push({
1086
- path: `app/src/main/kotlin/${packagePath}/ui/theme/Color.kt`,
1087
- content: `package ${ctx.packageName}.ui.theme
997
+ });
998
+ if (ctx.uiFramework === 'compose') {
999
+ files.push({
1000
+ path: `app/src/main/kotlin/${packagePath}/ui/theme/Color.kt`,
1001
+ content: `package ${ctx.packageName}.ui.theme
1088
1002
 
1089
1003
  import androidx.compose.ui.graphics.Color
1090
1004
 
@@ -1102,11 +1016,10 @@ val Pink80 = Color(0xFFEFB8C8)
1102
1016
  val Teal40 = Color(0xFF006B5B)
1103
1017
  val Teal80 = Color(0xFF8BD8CE)
1104
1018
  `
1105
- });
1106
-
1107
- files.push({
1108
- path: `app/src/main/kotlin/${packagePath}/ui/theme/Theme.kt`,
1109
- content: `package ${ctx.packageName}.ui.theme
1019
+ });
1020
+ files.push({
1021
+ path: `app/src/main/kotlin/${packagePath}/ui/theme/Theme.kt`,
1022
+ content: `package ${ctx.packageName}.ui.theme
1110
1023
 
1111
1024
  import android.app.Activity
1112
1025
  import android.os.Build
@@ -1199,11 +1112,10 @@ fun ${ctx.appNamePascal}Theme(
1199
1112
  )
1200
1113
  }
1201
1114
  `
1202
- });
1203
-
1204
- files.push({
1205
- path: `app/src/main/kotlin/${packagePath}/ui/theme/Type.kt`,
1206
- content: `package ${ctx.packageName}.ui.theme
1115
+ });
1116
+ files.push({
1117
+ path: `app/src/main/kotlin/${packagePath}/ui/theme/Type.kt`,
1118
+ content: `package ${ctx.packageName}.ui.theme
1207
1119
 
1208
1120
  import androidx.compose.material3.Typography
1209
1121
  import androidx.compose.ui.text.TextStyle
@@ -1319,32 +1231,30 @@ val Typography = Typography(
1319
1231
  )
1320
1232
  )
1321
1233
  `
1322
- });
1323
- }
1324
-
1325
- return files;
1234
+ });
1235
+ }
1236
+ return files;
1326
1237
  }
1327
-
1328
- function isKotlinActivity(ctx: TemplateContext): boolean {
1329
- return ctx.language === 'kotlin';
1238
+ function isKotlinActivity(ctx) {
1239
+ return ctx.language === 'kotlin';
1330
1240
  }
1331
-
1332
- function getAndroidVersionName(apiLevel: number): string {
1333
- const versions: Record<number, string> = {
1334
- 35: '15', 34: '14', 33: '13', 32: '12L', 31: '12',
1335
- 30: '11', 29: '10', 28: '9', 27: '8.1', 26: '8.0', 24: '7.0', 21: '5.0'
1336
- };
1337
- return versions[apiLevel] || 'Unknown';
1241
+ function getAndroidVersionName(apiLevel) {
1242
+ const versions = {
1243
+ 35: '15', 34: '14', 33: '13', 32: '12L', 31: '12',
1244
+ 30: '11', 29: '10', 28: '9', 27: '8.1', 26: '8.0', 24: '7.0', 21: '5.0'
1245
+ };
1246
+ return versions[apiLevel] || 'Unknown';
1338
1247
  }
1339
-
1340
1248
  /**
1341
1249
  * Get directory contents
1342
1250
  */
1343
- export async function getDirectoryContents(path: string): Promise<string[]> {
1344
- try {
1345
- const items = await import('fs-extra').then(fse => fse.default.readdir(path));
1346
- return items as string[];
1347
- } catch (error) {
1348
- return [];
1349
- }
1350
- }
1251
+ export async function getDirectoryContents(path) {
1252
+ try {
1253
+ const items = await import('fs-extra').then(fse => fse.default.readdir(path));
1254
+ return items;
1255
+ }
1256
+ catch (error) {
1257
+ return [];
1258
+ }
1259
+ }
1260
+ //# sourceMappingURL=generator.js.map