Skip to content

Commit a9da787

Browse files
author
Murat
committed
feat(task): add main activity task support
close #8
1 parent 31ca994 commit a9da787

File tree

10 files changed

+1070
-19
lines changed

10 files changed

+1070
-19
lines changed

src/__tests__/unit/tasks/mainActivityTask.spec.ts

Lines changed: 716 additions & 0 deletions
Large diffs are not rendered by default.

src/__tests__/unit/utils/runTask.spec.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ const mocks = {
1717
main_application: {
1818
runTask: jest.fn(),
1919
},
20+
main_activity: {
21+
runTask: jest.fn(),
22+
},
2023
xcode: {
2124
runTask: jest.fn(),
2225
},
@@ -38,6 +41,7 @@ jest.mock('../../../tasks/plistTask', () => mocks.plist);
3841
jest.mock('../../../tasks/buildGradleTask', () => mocks.build_gradle);
3942
jest.mock('../../../tasks/settingsGradleTask', () => mocks.settings_gradle);
4043
jest.mock('../../../tasks/mainApplicationTask', () => mocks.main_application);
44+
jest.mock('../../../tasks/mainActivityTask', () => mocks.main_activity);
4145
jest.mock('../../../tasks/xcode/xcodeTask', () => mocks.xcode);
4246
jest.mock('../../../tasks/androidManifestTask', () => mocks.android_manifest);
4347
jest.mock('../../../tasks/podFileTask', () => mocks.podfile);

src/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ export const Constants = {
1616
SETTINGS_GRADLE_FILE_NAME: 'settings.gradle',
1717
MAIN_APPLICATION_JAVA_FILE_NAME: 'MainApplication.java',
1818
MAIN_APPLICATION_KT_FILE_NAME: 'MainApplication.kt',
19+
MAIN_ACTIVITY_JAVA_FILE_NAME: 'MainActivity.java',
20+
MAIN_ACTIVITY_KT_FILE_NAME: 'MainActivity.kt',
1921
POD_FILE_NAME: 'Podfile',
2022
GITIGNORE_FILE_NAME: '.gitignore',
2123
XCODEPROJ_EXT: '.xcodeproj',

src/schema/integrate.schema.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,44 @@
489489
],
490490
"type": "object"
491491
},
492+
"MainActivityTaskType": {
493+
"additionalProperties": false,
494+
"properties": {
495+
"actions": {
496+
"items": {
497+
"$ref": "#/definitions/ContentModifierType<string>"
498+
},
499+
"type": "array"
500+
},
501+
"label": {
502+
"type": "string"
503+
},
504+
"lang": {
505+
"$ref": "#/definitions/AndroidCodeType"
506+
},
507+
"name": {
508+
"type": "string"
509+
},
510+
"postInfo": {
511+
"$ref": "#/definitions/TextOrTitleMessage"
512+
},
513+
"preInfo": {
514+
"$ref": "#/definitions/TextOrTitleMessage"
515+
},
516+
"type": {
517+
"const": "main_activity",
518+
"type": "string"
519+
},
520+
"when": {
521+
"$ref": "#/definitions/AnyObject"
522+
}
523+
},
524+
"required": [
525+
"actions",
526+
"type"
527+
],
528+
"type": "object"
529+
},
492530
"MainApplicationTaskType": {
493531
"additionalProperties": false,
494532
"properties": {
@@ -553,6 +591,9 @@
553591
{
554592
"$ref": "#/definitions/MainApplicationTaskType"
555593
},
594+
{
595+
"$ref": "#/definitions/MainActivityTaskType"
596+
},
556597
{
557598
"$ref": "#/definitions/AndroidManifestTaskType"
558599
},

src/schema/upgrade.schema.json

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,44 @@
489489
],
490490
"type": "object"
491491
},
492+
"MainActivityTaskType": {
493+
"additionalProperties": false,
494+
"properties": {
495+
"actions": {
496+
"items": {
497+
"$ref": "#/definitions/ContentModifierType<string>"
498+
},
499+
"type": "array"
500+
},
501+
"label": {
502+
"type": "string"
503+
},
504+
"lang": {
505+
"$ref": "#/definitions/AndroidCodeType"
506+
},
507+
"name": {
508+
"type": "string"
509+
},
510+
"postInfo": {
511+
"$ref": "#/definitions/TextOrTitleMessage"
512+
},
513+
"preInfo": {
514+
"$ref": "#/definitions/TextOrTitleMessage"
515+
},
516+
"type": {
517+
"const": "main_activity",
518+
"type": "string"
519+
},
520+
"when": {
521+
"$ref": "#/definitions/AnyObject"
522+
}
523+
},
524+
"required": [
525+
"actions",
526+
"type"
527+
],
528+
"type": "object"
529+
},
492530
"MainApplicationTaskType": {
493531
"additionalProperties": false,
494532
"properties": {
@@ -553,6 +591,9 @@
553591
{
554592
"$ref": "#/definitions/MainApplicationTaskType"
555593
},
594+
{
595+
"$ref": "#/definitions/MainActivityTaskType"
596+
},
556597
{
557598
"$ref": "#/definitions/AndroidManifestTaskType"
558599
},

src/tasks/mainActivityTask.ts

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import fs from 'fs';
2+
import { globSync } from 'glob';
3+
import { Constants } from '../constants';
4+
import {
5+
AndroidCodeType,
6+
BlockContentType,
7+
MainActivityTaskType,
8+
} from '../types/mod.types';
9+
import { applyContentModification } from '../utils/applyContentModification';
10+
import { findClosingTagIndex } from '../utils/findClosingTagIndex';
11+
import { getErrMessage } from '../utils/getErrMessage';
12+
import { getProjectPath } from '../utils/getProjectPath';
13+
import { satisfies } from '../utils/satisfies';
14+
import { setState } from '../utils/setState';
15+
import { stringSplice } from '../utils/stringSplice';
16+
import { variables } from '../variables';
17+
18+
export async function mainActivityTask(args: {
19+
configPath: string;
20+
packageName: string;
21+
content: string;
22+
task: MainActivityTaskType;
23+
}): Promise<string> {
24+
let { content } = args;
25+
const { task, configPath, packageName } = args;
26+
27+
for (const action of task.actions) {
28+
variables.set('CONTENT', content);
29+
if (action.when && !satisfies(variables.getStore(), action.when)) {
30+
setState(action.name, {
31+
state: 'skipped',
32+
reason: 'when',
33+
error: false,
34+
});
35+
continue;
36+
}
37+
38+
setState(action.name, {
39+
state: 'progress',
40+
error: false,
41+
});
42+
try {
43+
content = await applyContentModification({
44+
action,
45+
findOrCreateBlock,
46+
configPath,
47+
packageName,
48+
content,
49+
indentation: 2,
50+
});
51+
52+
setState(action.name, {
53+
state: 'done',
54+
error: false,
55+
});
56+
} catch (e) {
57+
setState(action.name, {
58+
state: 'error',
59+
reason: getErrMessage(e),
60+
error: true,
61+
});
62+
throw e;
63+
}
64+
}
65+
66+
return content;
67+
}
68+
69+
function findOrCreateBlock(
70+
content: string,
71+
block: string
72+
): {
73+
blockContent: BlockContentType;
74+
content: string;
75+
} {
76+
let blockContent = {
77+
start: 0,
78+
end: content.length,
79+
match: content,
80+
space: '',
81+
justCreated: false,
82+
};
83+
84+
const blockPath = block.split('.');
85+
let contentOffset = 0;
86+
87+
for (let i = 0; i < blockPath.length; i++) {
88+
const matcherRegex = new RegExp(`^((\\s+)?)${blockPath[i]}\\s+\\{`, 'ms');
89+
let blockStart = matcherRegex.exec(blockContent.match);
90+
91+
const justCreated = !blockStart;
92+
if (!blockStart) {
93+
const blockName = blockPath[i];
94+
// create block in block
95+
const space = ' '.repeat(2 * i);
96+
const previousSpace = ' '.repeat(Math.max(0, 2 * (i - 1)));
97+
const newBlock = `${space}${blockName} {}`;
98+
const codeToInsert = `
99+
${newBlock}
100+
${previousSpace}`;
101+
const contentLengthBeforeInsert = content.length;
102+
content = stringSplice(content, blockContent.end, 0, codeToInsert);
103+
if (codeToInsert.length && contentLengthBeforeInsert < content.length) {
104+
blockContent.match += codeToInsert;
105+
blockContent.end += codeToInsert.length;
106+
blockStart = matcherRegex.exec(blockContent.match);
107+
}
108+
}
109+
if (!blockStart) {
110+
throw new Error('block could not be inserted, something wrong?');
111+
}
112+
113+
const blockEndIndex = findClosingTagIndex(
114+
content,
115+
contentOffset + blockStart.index + blockStart[0].length
116+
);
117+
const blockBody = content.substring(
118+
contentOffset + blockStart.index + blockStart[0].length,
119+
blockEndIndex
120+
);
121+
blockContent = {
122+
start: contentOffset + blockStart.index + blockStart[0].length,
123+
end: blockEndIndex,
124+
match: blockBody,
125+
justCreated,
126+
space: ' '.repeat(2 * i),
127+
};
128+
contentOffset += blockStart.index + blockStart[0].length;
129+
}
130+
131+
return {
132+
blockContent,
133+
content,
134+
};
135+
}
136+
137+
function getMainActivityPath(lang?: AndroidCodeType) {
138+
const projectPath = getProjectPath();
139+
140+
const mainActivityPath = globSync(
141+
[
142+
projectPath,
143+
'android',
144+
'app',
145+
'src',
146+
'main',
147+
'java',
148+
'**',
149+
lang === 'kotlin'
150+
? Constants.MAIN_ACTIVITY_KT_FILE_NAME
151+
: Constants.MAIN_ACTIVITY_JAVA_FILE_NAME,
152+
].join('/'),
153+
{ nodir: true }
154+
)[0];
155+
if (!mainActivityPath)
156+
throw new Error(
157+
`MainActivity.${lang === 'kotlin' ? 'kt' : 'java'} file not found`
158+
);
159+
return mainActivityPath;
160+
}
161+
162+
function readMainActivityContent(lang?: AndroidCodeType) {
163+
const mainActivityPath = getMainActivityPath(lang);
164+
return fs.readFileSync(mainActivityPath, 'utf-8');
165+
}
166+
167+
function writeAppDelegateContent(
168+
content: string,
169+
lang?: AndroidCodeType
170+
): void {
171+
const mainActivityPath = getMainActivityPath(lang);
172+
return fs.writeFileSync(mainActivityPath, content, 'utf-8');
173+
}
174+
175+
export async function runTask(args: {
176+
configPath: string;
177+
packageName: string;
178+
task: MainActivityTaskType;
179+
}): Promise<void> {
180+
let content = readMainActivityContent(args.task.lang);
181+
182+
content = await mainActivityTask({
183+
...args,
184+
content,
185+
});
186+
187+
writeAppDelegateContent(content, args.task.lang);
188+
}
189+
190+
export const summary = 'MainActivity modification';

src/types/mod.types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,14 @@ export type MainApplicationTaskType = ModTaskBase &
177177

178178
export type AndroidCodeType = 'java' | 'kotlin';
179179

180+
// main activity
181+
182+
export type MainActivityTaskType = ModTaskBase &
183+
ActionsType<ContentModifierType> & {
184+
type: 'main_activity';
185+
lang?: AndroidCodeType;
186+
};
187+
180188
// android manifest task
181189

182190
export type AndroidManifestTaskType = ModTaskBase &
@@ -397,6 +405,7 @@ export type ModTask =
397405
| BuildGradleTaskType
398406
| SettingsGradleTaskType
399407
| MainApplicationTaskType
408+
| MainActivityTaskType
400409
| AndroidManifestTaskType
401410
| StringsXmlTaskType
402411
| NotificationServiceTaskType

src/utils/taskManager.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import * as prompt from '../tasks/promptTask';
1212
import * as notification_service from '../tasks/notificationServiceTask';
1313
import * as notification_view_controller from '../tasks/notificationViewControllerTask';
1414
import * as main_application from '../tasks/mainApplicationTask';
15+
import * as main_activity from '../tasks/mainActivityTask';
1516
import * as settings_gradle from '../tasks/settingsGradleTask';
1617
import * as shell from '../tasks/shellTask';
1718
import { ModTask } from '../types/mod.types';
@@ -30,6 +31,7 @@ const task: Record<string, TaskExports> = {
3031
notification_service,
3132
notification_view_controller,
3233
main_application,
34+
main_activity,
3335
settings_gradle,
3436
strings_xml,
3537
shell,

0 commit comments

Comments
 (0)