From 5c547229d4ebffec18b228b71c57ba8d66b420fb Mon Sep 17 00:00:00 2001 From: Akash Yadav Date: Mon, 2 May 2022 20:19:55 +0530 Subject: [PATCH] Removed unneccessary legacy project and task models --- .../com/itsaky/androidide/EditorActivity.java | 122 ++--- .../com/itsaky/androidide/MainActivity.java | 515 +++++++++--------- .../actions/editor/SelectAllAction.kt | 2 - .../adapters/ProjectsListAdapter.java | 171 ------ .../fragments/FileTreeFragment.java | 173 +++--- .../preferences/EditorPreferences.java | 2 +- .../handlers/FileOptionsHandler.java | 24 +- .../androidide/handlers/IDEHandler.java | 32 +- .../androidide/language/xml/XMLAnalyzer.java | 1 - .../androidide/language/xml/XMLLanguage.java | 2 +- .../androidide/lsp/IDELanguageClientImpl.java | 2 +- .../androidide/projects/AndroidProject.java | 225 -------- .../itsaky/androidide/projects/IDEModule.java | 68 --- .../androidide/projects/IDEProject.java | 96 ---- .../itsaky/androidide/projects/IDETask.java | 44 -- .../projects/ProjectFileObserver.java | 38 -- .../androidide/projects/ProjectManager.kt | 71 ++- .../services/builder/BuildListener.java | 83 --- .../services/builder/IDEService.java | 493 ----------------- .../builder/MainThreadBuildListener.java | 83 --- .../androidide/tasks/BaseGradleTask.java | 46 -- .../itsaky/androidide/tasks/GradleTask.java | 68 --- .../tasks/gradle/BaseGradleTasks.java | 49 -- .../tasks/gradle/build/ApkGeneratingTask.java | 153 ------ .../tasks/gradle/build/AssembleDebug.java | 69 --- .../tasks/gradle/build/AssembleRelease.java | 72 --- .../androidide/tasks/gradle/build/Build.java | 73 --- .../androidide/tasks/gradle/build/Bundle.java | 63 --- .../androidide/tasks/gradle/build/Clean.java | 63 --- .../tasks/gradle/build/CleanBuild.java | 63 --- .../androidide/tasks/gradle/lint/Lint.java | 62 --- .../tasks/gradle/lint/LintDebug.java | 62 --- .../tasks/gradle/lint/LintRelease.java | 62 --- .../gradle/plugin/InitializeIDEProject.java | 60 -- .../DatabindingGenBaseClassesDebug.java | 64 --- .../resources/ProcessDebugResources.java | 65 --- .../resources/UpdateResourceClassesTask.java | 82 --- .../androidide/utils/EditorActivityActions.kt | 2 +- .../androidide/utils/ProjectFinder.java | 201 ------- .../androidide/viewmodel/EditorViewModel.java | 51 +- .../views/editor/CodeEditorView.java | 10 +- .../test/test-home/.androidide/init/model.jar | Bin 76023 -> 76023 bytes 42 files changed, 454 insertions(+), 3233 deletions(-) delete mode 100755 app/src/main/java/com/itsaky/androidide/adapters/ProjectsListAdapter.java delete mode 100644 app/src/main/java/com/itsaky/androidide/projects/AndroidProject.java delete mode 100644 app/src/main/java/com/itsaky/androidide/projects/IDEModule.java delete mode 100644 app/src/main/java/com/itsaky/androidide/projects/IDEProject.java delete mode 100644 app/src/main/java/com/itsaky/androidide/projects/IDETask.java delete mode 100644 app/src/main/java/com/itsaky/androidide/projects/ProjectFileObserver.java delete mode 100755 app/src/main/java/com/itsaky/androidide/services/builder/BuildListener.java delete mode 100755 app/src/main/java/com/itsaky/androidide/services/builder/IDEService.java delete mode 100755 app/src/main/java/com/itsaky/androidide/services/builder/MainThreadBuildListener.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/BaseGradleTask.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/GradleTask.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/gradle/BaseGradleTasks.java delete mode 100644 app/src/main/java/com/itsaky/androidide/tasks/gradle/build/ApkGeneratingTask.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/gradle/build/AssembleDebug.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/gradle/build/AssembleRelease.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/gradle/build/Build.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/gradle/build/Bundle.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/gradle/build/Clean.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/gradle/build/CleanBuild.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/Lint.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/LintDebug.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/LintRelease.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/gradle/plugin/InitializeIDEProject.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/gradle/resources/DatabindingGenBaseClassesDebug.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/gradle/resources/ProcessDebugResources.java delete mode 100755 app/src/main/java/com/itsaky/androidide/tasks/gradle/resources/UpdateResourceClassesTask.java delete mode 100755 app/src/main/java/com/itsaky/androidide/utils/ProjectFinder.java diff --git a/app/src/main/java/com/itsaky/androidide/EditorActivity.java b/app/src/main/java/com/itsaky/androidide/EditorActivity.java index cda57ff4f..391b1121f 100755 --- a/app/src/main/java/com/itsaky/androidide/EditorActivity.java +++ b/app/src/main/java/com/itsaky/androidide/EditorActivity.java @@ -99,8 +99,6 @@ import com.itsaky.androidide.models.LogLine; import com.itsaky.androidide.models.SaveResult; import com.itsaky.androidide.models.SearchResult; import com.itsaky.androidide.models.SheetOption; -import com.itsaky.androidide.projects.AndroidProject; -import com.itsaky.androidide.projects.IDEProject; import com.itsaky.androidide.projects.ProjectManager; import com.itsaky.androidide.services.GradleBuildService; import com.itsaky.androidide.services.LogReceiver; @@ -159,7 +157,7 @@ public class EditorActivity extends StudioActivity EditorActivityProvider, OptionsListFragment.OnOptionsClickListener { - public static final String EXTRA_PROJECT = "project"; + public static final String EXTRA_PROJECT_PATH = "project_path"; public static final String KEY_BOTTOM_SHEET_SHOWN = "editor_bottomSheetShown"; private static final String TAG_FILE_OPTIONS_FRAGMENT = "file_options_fragment"; private static final int ACTION_ID_CLOSE = 100; @@ -283,34 +281,6 @@ public class EditorActivity extends StudioActivity return this; } - @Override - public AndroidProject provideAndroidProject() { - return getAndroidProject(); - } - - @Override - public IDEProject provideIDEProject() { - return getIDEProject(); - } - - @Nullable - private IDEProject getIDEProject() { - if (mViewModel == null) { - return null; - } - - return mViewModel.getIDEProject(); - } - - @Nullable - private AndroidProject getAndroidProject() { - if (mViewModel == null) { - return null; - } - - return mViewModel.getAndroidProject(); - } - public void handleSearchResults(Map> results) { setSearchResultAdapter( new com.itsaky.androidide.adapters.SearchListAdapter( @@ -344,7 +314,7 @@ public class EditorActivity extends StudioActivity shell.bgAppend( String.format( "cd '%s' && sh gradlew --status", - Objects.requireNonNull(getAndroidProject()).getProjectPath())); + Objects.requireNonNull(ProjectManager.INSTANCE.getProjectDir()))); if (!getDaemonStatusFragment().isShowing()) { getDaemonStatusFragment().show(getSupportFragmentManager(), "daemon_status"); } @@ -808,7 +778,8 @@ public class EditorActivity extends StudioActivity intent.putExtra( DesignerActivity.KEY_LAYOUT_PATH, getCurrentEditor().getFile().getAbsolutePath()); - intent.putStringArrayListExtra(DesignerActivity.KEY_RES_DIRS, getResourceDirectories()); + intent.putStringArrayListExtra( + DesignerActivity.KEY_RES_DIRS, (ArrayList) getResourceDirectories()); LOG.info("Launching UI Designer..."); mUIDesignerLauncher.launch(intent); } catch (Throwable th) { @@ -822,21 +793,13 @@ public class EditorActivity extends StudioActivity } @NonNull - private ArrayList getResourceDirectories() { - final var dirs = new ArrayList(); - if (getAndroidProject() != null - && getAndroidProject().getModulePaths() != null - && !getAndroidProject().getModulePaths().isEmpty()) { - for (String path : getAndroidProject().getModulePaths()) { - if (path != null && new File(path).exists()) { - File res = new File(path, "src/main/res"); - if (res.exists()) { - dirs.add(res.getAbsolutePath()); - } - } - } + private List getResourceDirectories() { + final var dirs = ProjectManager.INSTANCE.getApplicationResDirectories(); + if (dirs == null) { + return Collections.emptyList(); } - return dirs; + + return dirs.stream().map(File::getAbsolutePath).collect(Collectors.toList()); } public boolean saveAll(boolean notify, boolean canProcessResources) { @@ -1049,10 +1012,6 @@ public class EditorActivity extends StudioActivity execTasks(null, "clean", "build"); } - ///////////////////////////////////////////////// - ////////////// PRIVATE APIS ///////////////////// - ///////////////////////////////////////////////// - public AlertDialog getFindInProjectDialog() { return mFindInProjectDialog == null ? createFindInProjectDialog() : mFindInProjectDialog; } @@ -1064,6 +1023,10 @@ public class EditorActivity extends StudioActivity } } + ///////////////////////////////////////////////// + ////////////// PRIVATE APIS ///////////////////// + ///////////////////////////////////////////////// + public GradleBuildService getBuildService() { return mBuildService; } @@ -1076,7 +1039,7 @@ public class EditorActivity extends StudioActivity mViewModel = new ViewModelProvider(this).get(EditorViewModel.class); getProjectFromIntent(); - mFileTreeFragment = FileTreeFragment.newInstance(this.getAndroidProject()); + mFileTreeFragment = FileTreeFragment.newInstance(); mDaemonStatusFragment = new TextSheetFragment().setTextSelectable(true); setupDrawerToggle(); @@ -1260,13 +1223,13 @@ public class EditorActivity extends StudioActivity private void initializeProject() { // TODO Do not create unnecessary models. Instead, just keep a reference to the root // directory of the project. - final var androidProject = getAndroidProject(); - if (androidProject == null) { + final var projectPath = ProjectManager.INSTANCE.getProjectDir(); + if (projectPath == null) { LOG.error("Cannot initialize project. Project model is null."); return; } - final var projectDir = new File(androidProject.getProjectPath()); + final var projectDir = new File(projectPath); if (!projectDir.exists()) { LOG.error("Project directory does not exist. Cannot initialize project"); return; @@ -1462,25 +1425,21 @@ public class EditorActivity extends StudioActivity final Intent intent = new Intent(this, TerminalActivity.class); intent.putExtra( TerminalActivity.KEY_WORKING_DIRECTORY, - Objects.requireNonNull(getAndroidProject()).getProjectPath()); + Objects.requireNonNull(ProjectManager.INSTANCE.getProjectDir())); startActivity(intent); } private void getProjectFromIntent() { - final var project = (AndroidProject) getIntent().getParcelableExtra(EXTRA_PROJECT); - if (mViewModel != null) { - mViewModel.setAndroidProject(project); - } else { - LOG.error("ViewModel is null. Cannot set project."); - } + final var project = getIntent().getStringExtra(EXTRA_PROJECT_PATH); + ProjectManager.INSTANCE.setProjectPath(project); + getApp().getPrefManager() - .setOpenedProject( - Objects.requireNonNull(this.getAndroidProject()).getProjectPath()); + .setOpenedProject(Objects.requireNonNull(ProjectManager.INSTANCE.getProjectDir())); try { //noinspection ConstantConditions getSupportActionBar() - .setSubtitle(new File(getAndroidProject().getProjectPath()).getName()); + .setSubtitle(new File(ProjectManager.INSTANCE.getProjectDir()).getName()); } catch (Throwable th) { // ignored } @@ -1536,7 +1495,7 @@ public class EditorActivity extends StudioActivity final var javaLanguageServer = getApp().getJavaLanguageServer(); final var workspaceRoots = new HashSet(); workspaceRoots.add( - new File(Objects.requireNonNull(getAndroidProject()).getProjectPath()).toPath()); + new File(Objects.requireNonNull(ProjectManager.INSTANCE.getProjectDir())).toPath()); workspaceRoots.add(Environment.HOME.toPath().resolve("logsender")); final var params = new InitializeParams(workspaceRoots); @@ -1607,28 +1566,35 @@ public class EditorActivity extends StudioActivity builder.show(); } - @Nullable + @NonNull private AlertDialog createFindInProjectDialog() { - if (getAndroidProject() == null - || getAndroidProject().getModulePaths() == null - || getAndroidProject().getModulePaths().size() <= 0) { - getApp().toast(R.string.msg_no_modules, Toaster.Type.ERROR); - return null; + List moduleDirs = null; + final var rootProject = ProjectManager.INSTANCE.getRootProject(); + if (rootProject == null) { + LOG.warn("No root project model found. Is the project initialized?"); + moduleDirs = new ArrayList<>(0); } - final List modules = getAndroidProject().getModulePaths(); + + if (moduleDirs == null) { + moduleDirs = + rootProject.getModules().stream() + .map(IdeGradleProject::getProjectDir) + .collect(Collectors.toList()); + } + final List srcDirs = new ArrayList<>(); final LayoutSearchProjectBinding binding = LayoutSearchProjectBinding.inflate(getLayoutInflater()); binding.modulesContainer.removeAllViews(); - for (int i = 0; i < modules.size(); i++) { - final File file = new File(modules.get(i)); - final File src = new File(file, "src"); - if (!file.exists() || !file.isDirectory() || !src.exists() || !src.isDirectory()) { + for (int i = 0; i < moduleDirs.size(); i++) { + final File module = moduleDirs.get(i); + final File src = new File(module, "src"); + if (!module.exists() || !module.isDirectory() || !src.exists() || !src.isDirectory()) { continue; } CheckBox check = new CheckBox(this); - check.setText(file.getName()); + check.setText(module.getName()); check.setChecked(true); LinearLayout.MarginLayoutParams params = new LinearLayout.MarginLayoutParams(-2, -2); diff --git a/app/src/main/java/com/itsaky/androidide/MainActivity.java b/app/src/main/java/com/itsaky/androidide/MainActivity.java index 497bace4d..b6b3e71a9 100755 --- a/app/src/main/java/com/itsaky/androidide/MainActivity.java +++ b/app/src/main/java/com/itsaky/androidide/MainActivity.java @@ -39,18 +39,15 @@ import com.itsaky.androidide.managers.PreferenceManager; import com.itsaky.androidide.models.ConstantsBridge; import com.itsaky.androidide.models.NewProjectDetails; import com.itsaky.androidide.models.ProjectTemplate; -import com.itsaky.androidide.projects.AndroidProject; import com.itsaky.androidide.tasks.TaskExecutor; import com.itsaky.androidide.tasks.callables.ProjectCreatorCallable; import com.itsaky.androidide.utils.DialogUtils; -import com.itsaky.androidide.utils.ProjectFinder; import com.itsaky.androidide.utils.TransformUtils; import com.itsaky.toaster.Toaster; import java.io.File; import java.util.ArrayList; import java.util.Objects; -import java.util.concurrent.Callable; import abhishekti7.unicorn.filepicker.UnicornFilePicker; @@ -68,11 +65,213 @@ public class MainActivity extends StudioActivity private int currentTemplateIndex = 0; @Override - protected View bindLayout() { - binding = ActivityMainBinding.inflate(getLayoutInflater()); - createBinding = binding.createLayout; - createLayoutBinding = createBinding.createProjectContent; - return binding.getRoot(); + public void onClick(View p1) { + if (p1.getId() == binding.createProject.getId()) { + showCreateProject(); + } else if (p1.getId() == createBinding.createprojectClose.getId()) { + hideCreateProject(); + } else if (p1.getId() == createLayoutBinding.nextCard.getId()) { + currentTemplateIndex++; + if (currentTemplateIndex >= mTemplates.size()) { + currentTemplateIndex = 0; + } + showTemplate(currentTemplateIndex); + } else if (p1.getId() == createLayoutBinding.previousCard.getId()) { + currentTemplateIndex--; + if (currentTemplateIndex < 0) { + currentTemplateIndex = mTemplates.size() - 1; + } + showTemplate(currentTemplateIndex); + } else if (p1.getId() == createLayoutBinding.createprojectCreate.getId()) { + createNewProject(); + } else if (p1.getId() == binding.gotoPreferences.getId()) { + gotoSettings(); + } else if (p1.getId() == binding.openProject.getId()) { + pickProject(); + } else if (p1.getId() == binding.openTerminal.getId()) { + startActivity(new Intent(this, TerminalActivity.class)); + } + } + + private void showCreateProject() { + MaterialContainerTransform transform = + TransformUtils.createContainerTransformFor( + binding.createProject, binding.createNewCard, binding.realContainer); + TransitionManager.beginDelayedTransition(binding.getRoot(), transform); + binding.createNewCard.setVisibility(View.VISIBLE); + } + + private void hideCreateProject() { + MaterialContainerTransform transform = + TransformUtils.createContainerTransformFor( + binding.createNewCard, binding.createProject, binding.realContainer); + TransitionManager.beginDelayedTransition(binding.getRoot(), transform); + binding.createNewCard.setVisibility(View.GONE); + } + + private void showTemplate(int index) { + if (index < 0 || index >= mTemplates.size()) { + return; + } + final ProjectTemplate template = mTemplates.get(index); + createLayoutBinding.createprojectTemplateLabel.setText(template.getName()); + createLayoutBinding.createprojectTemplateDescription.setText(template.getDescription()); + createLayoutBinding.createprojectTemplateImage.setImageResource(template.getImageId()); + } + + private void createNewProject() { + final String appName = + Objects.requireNonNull(createLayoutBinding.createprojectTextAppName.getEditText()) + .getText() + .toString() + .trim(); + final String packageName = + Objects.requireNonNull( + createLayoutBinding.createprojectTextPackageName.getEditText()) + .getText() + .toString() + .trim(); + final int minSdk = getMinSdk(); + final int targetSdk = getTargetSdk(); + + if (!isValid(appName, packageName, minSdk, targetSdk)) { + getApp().toast(R.string.invalid_values, Toaster.Type.ERROR); + return; + } + + createProject(appName, packageName, minSdk, targetSdk); + } + + private void gotoSettings() { + startActivity(new Intent(this, PreferencesActivity.class)); + } + + private void pickProject() { + UnicornFilePicker.from(this) + .addConfigBuilder() + .addItemDivider(false) + .selectMultipleFiles(false) + .setRootDirectory(Environment.getExternalStorageDirectory().getAbsolutePath()) + .showHiddenFiles(true) + .showOnlyDirectory(true) + .theme(R.style.AppTheme_FilePicker) + .build() + .forResult(abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE); + } + + private int getMinSdk() { + try { + return Integer.parseInt( + Objects.requireNonNull( + createLayoutBinding.createprojectTextMinSdk.getEditText()) + .getText() + .toString()); + } catch (Exception e) { + getApp().toast(e.getMessage(), Toaster.Type.ERROR); + } + return -1; + } + + private int getTargetSdk() { + try { + return Integer.parseInt( + Objects.requireNonNull( + createLayoutBinding.createprojectTextTargetSdk.getEditText()) + .getText() + .toString()); + } catch (Exception e) { + getApp().toast(e.getMessage(), Toaster.Type.ERROR); + } + return -1; + } + + private boolean isValid(String appName, String packageName, int minSdk, int targetSdk) { + return appName != null + && appName.length() > 0 + && packageName != null + && packageName.length() > 0 + && minSdk > 1 + && minSdk < 99 + && targetSdk > 1 + && targetSdk < 99; + } + + private void createProject(String appName, String packageName, int minSdk, int targetSdk) { + new TaskExecutor() + .executeAsync( + new ProjectCreatorCallable( + mTemplates.get(currentTemplateIndex), + new NewProjectDetails(appName, packageName, minSdk, targetSdk), + this), + r -> {}); + } + + @Override + public void beforeBegin() { + if (mProgressSheet == null) { + createProgressSheet(); + } + + setMessage(R.string.msg_begin_project_write); + } + + @Override + public void onProcessTask(String taskName) { + setMessage(taskName); + } + + @Override + public void onSuccess(File root) { + if (mProgressSheet == null) { + createProgressSheet(); + } + + if (mProgressSheet.isShowing()) { + mProgressSheet.dismiss(); + } + getApp().toast(R.string.project_created_successfully, Toaster.Type.SUCCESS); + + openProject(root); + } + + @Override + public void onFailed(String reason) { + if (mProgressSheet == null) { + createProgressSheet(); + } + + if (mProgressSheet.isShowing()) { + mProgressSheet.dismiss(); + } + getApp().toast(reason, Toaster.Type.ERROR); + } + + private void openProject(File root) { + final var intent = new Intent(this, EditorActivity.class); + intent.putExtra(EditorActivity.EXTRA_PROJECT_PATH, root.getAbsolutePath()); + startActivity(intent); + } + + private void createProgressSheet() { + mProgressSheet = new ProgressSheet(); + mProgressSheet.setShowShadow(false); + } + + private void setMessage(int msg) { + setMessage(getString(msg)); + } + + private void setMessage(String msg) { + mProgressSheet.setMessage(msg); + } + + @Override + public void onBackPressed() { + if (binding.createNewCard.getVisibility() == View.VISIBLE) { + hideCreateProject(); + } else { + super.onBackPressed(); + } } @Override @@ -127,20 +326,6 @@ public class MainActivity extends StudioActivity }); } - private void askProjectOpenPermission(File root) { - final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(this); - builder.setTitle(R.string.title_confirm_open_project); - builder.setMessage(getString(R.string.msg_confirm_open_project, root.getAbsolutePath())); - builder.setCancelable(false); - builder.setPositiveButton(R.string.yes, (d, w) -> openProject(root)); - builder.setNegativeButton(R.string.no, null); - builder.show(); - } - - private void gotoSettings() { - startActivity(new Intent(this, PreferencesActivity.class)); - } - @Override protected void onStorageGranted() {} @@ -151,120 +336,11 @@ public class MainActivity extends StudioActivity } @Override - public void onClick(View p1) { - if (p1.getId() == binding.createProject.getId()) { - showCreateProject(); - } else if (p1.getId() == createBinding.createprojectClose.getId()) { - hideCreateProject(); - } else if (p1.getId() == createLayoutBinding.nextCard.getId()) { - currentTemplateIndex++; - if (currentTemplateIndex >= mTemplates.size()) { - currentTemplateIndex = 0; - } - showTemplate(currentTemplateIndex); - } else if (p1.getId() == createLayoutBinding.previousCard.getId()) { - currentTemplateIndex--; - if (currentTemplateIndex < 0) { - currentTemplateIndex = mTemplates.size() - 1; - } - showTemplate(currentTemplateIndex); - } else if (p1.getId() == createLayoutBinding.createprojectCreate.getId()) { - createNewProject(); - } else if (p1.getId() == binding.gotoPreferences.getId()) { - gotoSettings(); - } else if (p1.getId() == binding.openProject.getId()) { - pickProject(); - } else if (p1.getId() == binding.openTerminal.getId()) { - startActivity(new Intent(this, TerminalActivity.class)); - } - } - - @Override - public void beforeBegin() { - if (mProgressSheet == null) { - createProgressSheet(); - } - - setMessage(R.string.msg_begin_project_write); - } - - @Override - public void onProcessTask(String taskName) { - setMessage(taskName); - } - - @Override - public void onSuccess(File root) { - if (mProgressSheet == null) { - createProgressSheet(); - } - - if (mProgressSheet.isShowing()) { - mProgressSheet.dismiss(); - } - getApp().toast(R.string.project_created_successfully, Toaster.Type.SUCCESS); - - openProject(root); - } - - @Override - public void onFailed(String reason) { - if (mProgressSheet == null) { - createProgressSheet(); - } - - if (mProgressSheet.isShowing()) { - mProgressSheet.dismiss(); - } - getApp().toast(reason, Toaster.Type.ERROR); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (requestCode == abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE - && resultCode == RESULT_OK) { - ArrayList files = data.getStringArrayListExtra("filePaths"); - if (files != null) { - if (files.size() == 1) { - File choseDir = new File(files.get(0)); - if (choseDir.exists() && choseDir.isDirectory()) { - openProject(choseDir); - } else { - getApp().toast(R.string.msg_picked_isnt_dir, Toaster.Type.ERROR); - } - } else { - getApp().toast(R.string.msg_pick_single_file, Toaster.Type.ERROR); - } - } - } - } - - @Override - public void onBackPressed() { - if (binding.createNewCard.getVisibility() == View.VISIBLE) { - hideCreateProject(); - } else { - super.onBackPressed(); - } - } - - @Override - protected void onResume() { - super.onResume(); - if (mProgressSheet != null && mProgressSheet.isShowing()) { - mProgressSheet.dismiss(); - } - } - - private void showTemplate(int index) { - if (index < 0 || index >= mTemplates.size()) { - return; - } - final ProjectTemplate template = mTemplates.get(index); - createLayoutBinding.createprojectTemplateLabel.setText(template.getName()); - createLayoutBinding.createprojectTemplateDescription.setText(template.getDescription()); - createLayoutBinding.createprojectTemplateImage.setImageResource(template.getImageId()); + protected View bindLayout() { + binding = ActivityMainBinding.inflate(getLayoutInflater()); + createBinding = binding.createLayout; + createLayoutBinding = createBinding.createProjectContent; + return binding.getRoot(); } /** Must be called in/after onViewCreated */ @@ -310,147 +386,42 @@ public class MainActivity extends StudioActivity mTemplates.add(libgdx); } - private void createProgressSheet() { - mProgressSheet = new ProgressSheet(); - mProgressSheet.setShowShadow(false); + private void askProjectOpenPermission(File root) { + final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(this); + builder.setTitle(R.string.title_confirm_open_project); + builder.setMessage(getString(R.string.msg_confirm_open_project, root.getAbsolutePath())); + builder.setCancelable(false); + builder.setPositiveButton(R.string.yes, (d, w) -> openProject(root)); + builder.setNegativeButton(R.string.no, null); + builder.show(); } - private void setMessage(int msg) { - setMessage(getString(msg)); - } - - private void setMessage(String msg) { - mProgressSheet.setMessage(msg); - } - - private void openProject(File root) { - setMessage(R.string.msg_opening_project); - mProgressSheet.setCancelable(false); - mProgressSheet.show(getSupportFragmentManager(), "opening_project"); - - new TaskExecutor().executeAsync(new ProjectReader(root), this::openEditor); - } - - private void pickProject() { - UnicornFilePicker.from(this) - .addConfigBuilder() - .addItemDivider(false) - .selectMultipleFiles(false) - .setRootDirectory(Environment.getExternalStorageDirectory().getAbsolutePath()) - .showHiddenFiles(true) - .showOnlyDirectory(true) - .theme(R.style.AppTheme_FilePicker) - .build() - .forResult(abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE); - } - - private void openEditor(AndroidProject project) { - if (project == null) { - getApp().toast(R.string.msg_invalid_project, Toaster.Type.ERROR); - } else { - startActivity( - new Intent(this, EditorActivity.class) - .putExtra(EditorActivity.EXTRA_PROJECT, project)); + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE + && resultCode == RESULT_OK) { + ArrayList files = data.getStringArrayListExtra("filePaths"); + if (files != null) { + if (files.size() == 1) { + File choseDir = new File(files.get(0)); + if (choseDir.exists() && choseDir.isDirectory()) { + openProject(choseDir); + } else { + getApp().toast(R.string.msg_picked_isnt_dir, Toaster.Type.ERROR); + } + } else { + getApp().toast(R.string.msg_pick_single_file, Toaster.Type.ERROR); + } + } } } - private void createNewProject() { - final String appName = - Objects.requireNonNull(createLayoutBinding.createprojectTextAppName.getEditText()) - .getText() - .toString() - .trim(); - final String packageName = - Objects.requireNonNull( - createLayoutBinding.createprojectTextPackageName.getEditText()) - .getText() - .toString() - .trim(); - final int minSdk = getMinSdk(); - final int targetSdk = getTargetSdk(); - - if (!isValid(appName, packageName, minSdk, targetSdk)) { - getApp().toast(R.string.invalid_values, Toaster.Type.ERROR); - return; - } - - createProject(appName, packageName, minSdk, targetSdk); - } - - private void createProject(String appName, String packageName, int minSdk, int targetSdk) { - new TaskExecutor() - .executeAsync( - new ProjectCreatorCallable( - mTemplates.get(currentTemplateIndex), - new NewProjectDetails(appName, packageName, minSdk, targetSdk), - this), - r -> {}); - } - - private boolean isValid(String appName, String packageName, int minSdk, int targetSdk) { - return appName != null - && appName.length() > 0 - && packageName != null - && packageName.length() > 0 - && minSdk > 1 - && minSdk < 99 - && targetSdk > 1 - && targetSdk < 99; - } - - private int getMinSdk() { - try { - return Integer.parseInt( - Objects.requireNonNull( - createLayoutBinding.createprojectTextMinSdk.getEditText()) - .getText() - .toString()); - } catch (Exception e) { - getApp().toast(e.getMessage(), Toaster.Type.ERROR); - } - return -1; - } - - private int getTargetSdk() { - try { - return Integer.parseInt( - Objects.requireNonNull( - createLayoutBinding.createprojectTextTargetSdk.getEditText()) - .getText() - .toString()); - } catch (Exception e) { - getApp().toast(e.getMessage(), Toaster.Type.ERROR); - } - return -1; - } - - private void showCreateProject() { - MaterialContainerTransform transform = - TransformUtils.createContainerTransformFor( - binding.createProject, binding.createNewCard, binding.realContainer); - TransitionManager.beginDelayedTransition(binding.getRoot(), transform); - binding.createNewCard.setVisibility(View.VISIBLE); - } - - private void hideCreateProject() { - MaterialContainerTransform transform = - TransformUtils.createContainerTransformFor( - binding.createNewCard, binding.createProject, binding.realContainer); - TransitionManager.beginDelayedTransition(binding.getRoot(), transform); - binding.createNewCard.setVisibility(View.GONE); - } - - private static final class ProjectReader implements Callable { - - private final File root; - - public ProjectReader(File root) { - this.root = root; - } - - @Override - public AndroidProject call() throws Exception { - return ProjectFinder.fromFolder(root); + @Override + protected void onResume() { + super.onResume(); + if (mProgressSheet != null && mProgressSheet.isShowing()) { + mProgressSheet.dismiss(); } } } diff --git a/app/src/main/java/com/itsaky/androidide/actions/editor/SelectAllAction.kt b/app/src/main/java/com/itsaky/androidide/actions/editor/SelectAllAction.kt index 7aeed99f3..28c774af2 100644 --- a/app/src/main/java/com/itsaky/androidide/actions/editor/SelectAllAction.kt +++ b/app/src/main/java/com/itsaky/androidide/actions/editor/SelectAllAction.kt @@ -18,8 +18,6 @@ package com.itsaky.androidide.actions.editor import android.content.Context -import android.content.res.TypedArray -import androidx.core.content.ContextCompat import com.itsaky.androidide.R import com.itsaky.androidide.actions.ActionData import com.itsaky.androidide.actions.BaseEditorAction diff --git a/app/src/main/java/com/itsaky/androidide/adapters/ProjectsListAdapter.java b/app/src/main/java/com/itsaky/androidide/adapters/ProjectsListAdapter.java deleted file mode 100755 index 1e5322e26..000000000 --- a/app/src/main/java/com/itsaky/androidide/adapters/ProjectsListAdapter.java +++ /dev/null @@ -1,171 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.adapters; - -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.recyclerview.widget.RecyclerView; -import androidx.transition.ChangeBounds; -import androidx.transition.TransitionManager; - -import com.blankj.utilcode.util.FileUtils; -import com.bumptech.glide.Glide; -import com.itsaky.androidide.R; -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.databinding.LayoutProjectsItemBinding; -import com.itsaky.androidide.projects.AndroidProject; -import com.itsaky.androidide.tasks.TaskExecutor; -import com.itsaky.toaster.Toaster; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; - -public class ProjectsListAdapter extends RecyclerView.Adapter { - private ArrayList mProjects; - private OnProjectClickListener listener; - - private final Comparator PROJECTS_SORTER = - new Comparator() { - - @Override - public int compare(AndroidProject p1, AndroidProject p2) { - return p1.getAppName().compareTo(p2.getAppName()); - } - }; - - public ProjectsListAdapter( - ArrayList mProjects, OnProjectClickListener listener) { - this.mProjects = mProjects; - this.listener = listener; - Collections.sort(this.mProjects, PROJECTS_SORTER); - } - - @Override - public ProjectsListAdapter.VH onCreateViewHolder(ViewGroup p1, int p2) { - return new VH( - LayoutProjectsItemBinding.inflate(LayoutInflater.from(p1.getContext()), p1, false)); - } - - @Override - public void onBindViewHolder(ProjectsListAdapter.VH holder, int p2) { - final AndroidProject project = mProjects.get(p2); - holder.binding.projecsitemName.setText(project.getAppName()); - holder.binding.projecsitemPkgName.setText(project.getPackageName()); - holder.binding.deleteMsg.setText( - holder.binding - .deleteMsg - .getContext() - .getString(R.string.msg_confirm_delete, project.getAppName())); - if (!TextUtils.isEmpty(project.getIconPath())) - Glide.with(holder.itemView.getContext().getApplicationContext()) - .load(new File(project.getIconPath())) - .into(holder.binding.projecsitemIcon); - else holder.binding.projecsitemIcon.setImageResource(R.drawable.ic_android); - - holder.binding.projectsitemClickableContainer.setOnClickListener( - v -> sendClickEvent(project)); - holder.binding.projectsitemClickableContainer.setOnLongClickListener( - v -> holder.toggleDelete()); - holder.binding.delete.setOnClickListener(v -> holder.showConfirmDelete()); - holder.binding.deleteCancel.setOnClickListener(v -> holder.hideAllDelete()); - holder.binding.deleteOk.setOnClickListener(v -> deleteProject(project, p2)); - } - - private void deleteProject(AndroidProject project, int index) { - index = index >= mProjects.size() ? mProjects.size() - 1 : index; - if (index < 0) return; - mProjects.remove(index); - notifyItemRemoved(index); - - new TaskExecutor() - .executeAsync( - () -> FileUtils.delete(project.getProjectPath()), - __ -> { - StudioApp.getInstance() - .toast( - __ - ? R.string.msg_project_deleted - : R.string.msg_project_delete_failed, - Toaster.Type.SUCCESS); - }); - } - - private void sendClickEvent(AndroidProject project) { - if (listener != null) listener.onProjectClick(project); - } - - @Override - public int getItemCount() { - return mProjects.size(); - } - - public class VH extends RecyclerView.ViewHolder { - LayoutProjectsItemBinding binding; - - public VH(LayoutProjectsItemBinding binding) { - super(binding.getRoot()); - this.binding = binding; - } - - public void showConfirmDelete() { - binding.confirmDeleteContainer.setEnabled(true); - TransitionManager.beginDelayedTransition( - binding.getRoot(), new ChangeBounds().setDuration(85)); - binding.confirmDeleteContainer.setVisibility(View.VISIBLE); - } - - public void hideAllDelete() { - hideDelete(); - hideConfirmDelete(); - } - - public boolean toggleDelete() { - binding.delete.setEnabled(!binding.delete.isEnabled()); - TransitionManager.beginDelayedTransition( - binding.getRoot(), new ChangeBounds().setDuration(85)); - binding.delete.setVisibility(binding.delete.isEnabled() ? View.VISIBLE : View.GONE); - return true; - } - - public void hideDelete() { - binding.delete.setEnabled(false); - TransitionManager.beginDelayedTransition( - binding.getRoot(), new ChangeBounds().setDuration(85)); - binding.delete.setVisibility(View.GONE); - } - - public void hideConfirmDelete() { - binding.confirmDeleteContainer.setEnabled(false); - TransitionManager.beginDelayedTransition( - binding.getRoot(), new ChangeBounds().setDuration(85)); - binding.confirmDeleteContainer.setVisibility(View.GONE); - } - } - - public interface OnProjectClickListener { - public void onProjectClick(AndroidProject project); - } -} diff --git a/app/src/main/java/com/itsaky/androidide/fragments/FileTreeFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/FileTreeFragment.java index 7982ee9f4..d898030ff 100755 --- a/app/src/main/java/com/itsaky/androidide/fragments/FileTreeFragment.java +++ b/app/src/main/java/com/itsaky/androidide/fragments/FileTreeFragment.java @@ -40,7 +40,7 @@ import com.itsaky.androidide.R; import com.itsaky.androidide.adapters.viewholders.FileTreeViewHolder; import com.itsaky.androidide.app.StudioApp; import com.itsaky.androidide.databinding.LayoutEditorFileTreeBinding; -import com.itsaky.androidide.projects.AndroidProject; +import com.itsaky.androidide.projects.ProjectManager; import com.itsaky.androidide.tasks.TaskExecutor; import com.itsaky.androidide.tasks.callables.FileTreeCallable; import com.itsaky.androidide.utils.Environment; @@ -63,19 +63,27 @@ public class FileTreeFragment extends BottomSheetDialogFragment private LayoutEditorFileTreeBinding binding; private AndroidTreeView mFileTreeView; private FileActionListener mFileActionListener; - private AndroidProject mProject; private TreeNode mRoot; private String mTreeState; public FileTreeFragment() {} @NonNull - public static FileTreeFragment newInstance(AndroidProject project) { - Bundle bundle = new Bundle(); - bundle.putParcelable("project", project); - FileTreeFragment frag = new FileTreeFragment(); - frag.setArguments(bundle); - return frag; + public static FileTreeFragment newInstance() { + return new FileTreeFragment(); + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + mFileActionListener = (FileActionListener) context; + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + saveTreeState(); + outState.putString(KEY_STORED_TREE_STATE, mTreeState); } public void saveTreeState() { @@ -87,49 +95,6 @@ public class FileTreeFragment extends BottomSheetDialogFragment } } - private void tryRestoreState() { - tryRestoreState(mTreeState); - } - - private void tryRestoreState(String state) { - if (!TextUtils.isEmpty(state) && mFileTreeView != null) { - - LOG.debug("Restoring tree view state:", "'" + state + "'"); - - mFileTreeView.collapseAll(); - final var openNodesArray = state.split(NODES_PATH_SEPARATOR); - final var openNodes = new HashSet<>(Arrays.asList(openNodesArray)); - restoreNodeState(mRoot, openNodes); - } else { - LOG.error( - "Unable to restore tree state", - "treeState=" + state, - "treeView=" + mFileTreeView); - } - } - - private void restoreNodeState(@NonNull TreeNode root, Set openNodes) { - final var children = root.getChildren(); - for (int i = 0, childrenSize = children.size(); i < childrenSize; i++) { - final var node = children.get(i); - if (openNodes.contains(node.getPath())) { - listNode( - node, - () -> { - updateChevron(node); - expandNode(node); - restoreNodeState(node, openNodes); - }); - } - } - } - - @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); - mFileActionListener = (FileActionListener) context; - } - @Override public View onCreateView( @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -140,7 +105,6 @@ public class FileTreeFragment extends BottomSheetDialogFragment @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - mProject = requireArguments().getParcelable("project"); if (savedInstanceState != null && savedInstanceState.containsKey(KEY_STORED_TREE_STATE)) { mTreeState = savedInstanceState.getString(KEY_STORED_TREE_STATE, null); @@ -188,11 +152,28 @@ public class FileTreeFragment extends BottomSheetDialogFragment } } - @Override - public void onSaveInstanceState(@NonNull Bundle outState) { - super.onSaveInstanceState(outState); - saveTreeState(); - outState.putString(KEY_STORED_TREE_STATE, mTreeState); + public void collapseNode(TreeNode node) { + if (mFileTreeView == null) { + return; + } + + TransitionManager.beginDelayedTransition(binding.getRoot(), new ChangeBounds()); + mFileTreeView.collapseNode(node); + } + + public void expandNode(TreeNode node) { + if (mFileTreeView == null) { + return; + } + + TransitionManager.beginDelayedTransition(binding.getRoot(), new ChangeBounds()); + mFileTreeView.expandNode(node); + } + + private void setLoading(@NonNull TreeNode node) { + if (node.getViewHolder() instanceof FileTreeViewHolder) { + ((FileTreeViewHolder) node.getViewHolder()).setLoading(); + } } private void listNode(@NonNull TreeNode node, Runnable whenDone) { @@ -222,6 +203,12 @@ public class FileTreeFragment extends BottomSheetDialogFragment __ -> finalWhenDone.run()); } + private void updateChevron(@NonNull TreeNode node) { + if (node.getViewHolder() instanceof FileTreeViewHolder) { + ((FileTreeViewHolder) node.getViewHolder()).updateChevron(!node.isExpanded()); + } + } + private void getNodeFromFiles(File[] files, TreeNode parent) { Arrays.sort(files, new FileTreeCallable.SortFileName()); Arrays.sort(files, new FileTreeCallable.SortFolder()); @@ -232,18 +219,6 @@ public class FileTreeFragment extends BottomSheetDialogFragment } } - private void setLoading(@NonNull TreeNode node) { - if (node.getViewHolder() instanceof FileTreeViewHolder) { - ((FileTreeViewHolder) node.getViewHolder()).setLoading(); - } - } - - private void updateChevron(@NonNull TreeNode node) { - if (node.getViewHolder() instanceof FileTreeViewHolder) { - ((FileTreeViewHolder) node.getViewHolder()).updateChevron(!node.isExpanded()); - } - } - @Override public boolean onLongClick(TreeNode node, Object value) { if (mFileActionListener != null) { @@ -252,32 +227,15 @@ public class FileTreeFragment extends BottomSheetDialogFragment return true; } - public void expandNode(TreeNode node) { - if (mFileTreeView == null) { - return; - } - - TransitionManager.beginDelayedTransition(binding.getRoot(), new ChangeBounds()); - mFileTreeView.expandNode(node); - } - - public void collapseNode(TreeNode node) { - if (mFileTreeView == null) { - return; - } - - TransitionManager.beginDelayedTransition(binding.getRoot(), new ChangeBounds()); - mFileTreeView.collapseNode(node); - } - public void listProjectFiles() { - if (mProject == null) { + final var projectDirPath = ProjectManager.INSTANCE.getProjectDir(); + if (projectDirPath == null) { return; } final File gradleProps = Environment.GRADLE_PROPS; final File gradleHome = Environment.GRADLE_USER_HOME; - File projectDir = new File(mProject.getProjectPath()); + File projectDir = new File(projectDirPath); mRoot = TreeNode.root(projectDir); if (gradleHome.exists() && gradleHome.isDirectory()) { if (!gradleProps.exists()) { @@ -342,6 +300,43 @@ public class FileTreeFragment extends BottomSheetDialogFragment return binding.fileTreeLoadingProgress; } + private void tryRestoreState() { + tryRestoreState(mTreeState); + } + + private void tryRestoreState(String state) { + if (!TextUtils.isEmpty(state) && mFileTreeView != null) { + + LOG.debug("Restoring tree view state:", "'" + state + "'"); + + mFileTreeView.collapseAll(); + final var openNodesArray = state.split(NODES_PATH_SEPARATOR); + final var openNodes = new HashSet<>(Arrays.asList(openNodesArray)); + restoreNodeState(mRoot, openNodes); + } else { + LOG.error( + "Unable to restore tree state", + "treeState=" + state, + "treeView=" + mFileTreeView); + } + } + + private void restoreNodeState(@NonNull TreeNode root, Set openNodes) { + final var children = root.getChildren(); + for (int i = 0, childrenSize = children.size(); i < childrenSize; i++) { + final var node = children.get(i); + if (openNodes.contains(node.getPath())) { + listNode( + node, + () -> { + updateChevron(node); + expandNode(node); + restoreNodeState(node, openNodes); + }); + } + } + } + public interface FileActionListener { CodeEditorView openFile(File file); diff --git a/app/src/main/java/com/itsaky/androidide/fragments/preferences/EditorPreferences.java b/app/src/main/java/com/itsaky/androidide/fragments/preferences/EditorPreferences.java index 952a7e790..18478a92c 100755 --- a/app/src/main/java/com/itsaky/androidide/fragments/preferences/EditorPreferences.java +++ b/app/src/main/java/com/itsaky/androidide/fragments/preferences/EditorPreferences.java @@ -17,7 +17,6 @@ */ package com.itsaky.androidide.fragments.preferences; -import com.itsaky.androidide.managers.PreferenceManager; import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_AUTO_SAVE; import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_DRAW_HEX; import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FLAG_LINE_BREAK; @@ -44,6 +43,7 @@ import androidx.preference.SwitchPreference; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.itsaky.androidide.R; import com.itsaky.androidide.databinding.LayoutTextSizeSliderBinding; +import com.itsaky.androidide.managers.PreferenceManager; import com.itsaky.androidide.models.ConstantsBridge; import com.itsaky.androidide.utils.DialogUtils; diff --git a/app/src/main/java/com/itsaky/androidide/handlers/FileOptionsHandler.java b/app/src/main/java/com/itsaky/androidide/handlers/FileOptionsHandler.java index bdc0035da..cca9a5622 100755 --- a/app/src/main/java/com/itsaky/androidide/handlers/FileOptionsHandler.java +++ b/app/src/main/java/com/itsaky/androidide/handlers/FileOptionsHandler.java @@ -29,6 +29,7 @@ import com.itsaky.androidide.databinding.LayoutCreateFileJavaBinding; import com.itsaky.androidide.databinding.LayoutDialogTextInputBinding; import com.itsaky.androidide.fragments.sheets.OptionsListFragment; import com.itsaky.androidide.models.SheetOption; +import com.itsaky.androidide.projects.ProjectManager; import com.itsaky.androidide.utils.DialogUtils; import com.itsaky.androidide.utils.Environment; import com.itsaky.androidide.utils.ProjectWriter; @@ -93,34 +94,27 @@ public class FileOptionsHandler extends IDEHandler if (forceUnknownType) { createNewEmptyFile(f); } else { + final var projectDir = ProjectManager.INSTANCE.getProjectDir(); + Objects.requireNonNull(projectDir); + final boolean isJava = - Pattern.compile( - Pattern.quote(androidProject().getProjectPath()) - + JAVA_PATH_REGEX) + Pattern.compile(Pattern.quote(projectDir) + JAVA_PATH_REGEX) .matcher(f.getAbsolutePath()) .find(); final boolean isRes = - Pattern.compile( - Pattern.quote(androidProject().getProjectPath()) - + RES_PATH_REGEX) + Pattern.compile(Pattern.quote(projectDir) + RES_PATH_REGEX) .matcher(f.getAbsolutePath()) .find(); final boolean isLayoutRes = - Pattern.compile( - Pattern.quote(androidProject().getProjectPath()) - + LAYOUT_RES_PATH_REGEX) + Pattern.compile(Pattern.quote(projectDir) + LAYOUT_RES_PATH_REGEX) .matcher(f.getAbsolutePath()) .find(); final boolean isMenuRes = - Pattern.compile( - Pattern.quote(androidProject().getProjectPath()) - + MENU_RES_PATH_REGEX) + Pattern.compile(Pattern.quote(projectDir) + MENU_RES_PATH_REGEX) .matcher(f.getAbsolutePath()) .find(); final boolean isDrawableRes = - Pattern.compile( - Pattern.quote(androidProject().getProjectPath()) - + DRAWABLE_RES_PATH_REGEX) + Pattern.compile(Pattern.quote(projectDir) + DRAWABLE_RES_PATH_REGEX) .matcher(f.getAbsolutePath()) .find(); if (isJava) { diff --git a/app/src/main/java/com/itsaky/androidide/handlers/IDEHandler.java b/app/src/main/java/com/itsaky/androidide/handlers/IDEHandler.java index f08331b79..1772e80c8 100755 --- a/app/src/main/java/com/itsaky/androidide/handlers/IDEHandler.java +++ b/app/src/main/java/com/itsaky/androidide/handlers/IDEHandler.java @@ -18,8 +18,6 @@ package com.itsaky.androidide.handlers; import com.itsaky.androidide.EditorActivity; -import com.itsaky.androidide.projects.AndroidProject; -import com.itsaky.androidide.projects.IDEProject; import com.itsaky.androidide.utils.ILogger; /** @@ -36,22 +34,14 @@ public abstract class IDEHandler { this.provider = provider; } - protected EditorActivity activity() { - return provider.provideEditorActivity(); - } - - protected AndroidProject androidProject() { - return provider.provideAndroidProject(); - } - - protected IDEProject ideProject() { - return provider.provideIDEProject(); - } - public abstract void start(); public abstract void stop(); + protected EditorActivity activity() { + return provider.provideEditorActivity(); + } + /** An interface to communicate between a handler and its client */ public interface Provider { @@ -61,19 +51,5 @@ public abstract class IDEHandler { * @throws NullPointerException is this is required */ EditorActivity provideEditorActivity(); - - /** - * Called by handler to get a reference of the current {@link AndroidProject} - * - * @throws NullPointerException is this is required - */ - AndroidProject provideAndroidProject(); - - /** - * Called by handler to get a reference of the current {@link IDEProject} - * - * @throws NullPointerException is this is required - */ - IDEProject provideIDEProject(); } } diff --git a/app/src/main/java/com/itsaky/androidide/language/xml/XMLAnalyzer.java b/app/src/main/java/com/itsaky/androidide/language/xml/XMLAnalyzer.java index e00bf5d83..52f740468 100755 --- a/app/src/main/java/com/itsaky/androidide/language/xml/XMLAnalyzer.java +++ b/app/src/main/java/com/itsaky/androidide/language/xml/XMLAnalyzer.java @@ -18,7 +18,6 @@ package com.itsaky.androidide.language.xml; import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.OPERATOR; -import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.TEXT_SELECTED; import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.forComment; import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.get; import static io.github.rosemoe.sora.widget.schemes.EditorColorScheme.LITERAL; diff --git a/app/src/main/java/com/itsaky/androidide/language/xml/XMLLanguage.java b/app/src/main/java/com/itsaky/androidide/language/xml/XMLLanguage.java index 4dc8f663e..6454c974b 100755 --- a/app/src/main/java/com/itsaky/androidide/language/xml/XMLLanguage.java +++ b/app/src/main/java/com/itsaky/androidide/language/xml/XMLLanguage.java @@ -25,8 +25,8 @@ import com.itsaky.androidide.app.StudioApp; import com.itsaky.androidide.language.CommonCompletionProvider; import com.itsaky.androidide.language.IDELanguage; import com.itsaky.androidide.lexers.xml.XMLLexer; -import com.itsaky.androidide.utils.JavaCharacter; import com.itsaky.androidide.utils.ILogger; +import com.itsaky.androidide.utils.JavaCharacter; import com.itsaky.androidide.views.editor.IDEEditor; import com.itsaky.lsp.api.ILanguageServer; diff --git a/app/src/main/java/com/itsaky/androidide/lsp/IDELanguageClientImpl.java b/app/src/main/java/com/itsaky/androidide/lsp/IDELanguageClientImpl.java index 6a9d8af6e..7fe89c917 100755 --- a/app/src/main/java/com/itsaky/androidide/lsp/IDELanguageClientImpl.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/IDELanguageClientImpl.java @@ -38,8 +38,8 @@ import com.itsaky.androidide.models.DiagnosticGroup; import com.itsaky.androidide.models.SearchResult; import com.itsaky.androidide.tasks.TaskExecutor; import com.itsaky.androidide.utils.DialogUtils; -import com.itsaky.androidide.utils.LSPUtils; import com.itsaky.androidide.utils.ILogger; +import com.itsaky.androidide.utils.LSPUtils; import com.itsaky.androidide.views.editor.CodeEditorView; import com.itsaky.androidide.views.editor.IDEEditor; import com.itsaky.lsp.api.ILanguageClient; diff --git a/app/src/main/java/com/itsaky/androidide/projects/AndroidProject.java b/app/src/main/java/com/itsaky/androidide/projects/AndroidProject.java deleted file mode 100644 index b39d34b98..000000000 --- a/app/src/main/java/com/itsaky/androidide/projects/AndroidProject.java +++ /dev/null @@ -1,225 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.projects; - -import android.os.Parcel; -import android.os.Parcelable; - -import com.itsaky.androidide.app.StudioApp; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -public class AndroidProject implements Parcelable { - - private String appName; - private String packageName; - private String iconPath; - private String projectPath; - private String mainModule; - private String mainSourcePath; - - private List modulePaths = new ArrayList<>(); - private List sourcePaths = new ArrayList<>(); - private List classPaths = new ArrayList<>(); - - public AndroidProject() { - addSource(StudioApp.getInstance().getLogSenderDir().getAbsolutePath()); - } - - protected AndroidProject(Parcel in) { - appName = in.readString(); - packageName = in.readString(); - iconPath = in.readString(); - projectPath = in.readString(); - mainModule = in.readString(); - mainSourcePath = in.readString(); - in.readList(modulePaths, String.class.getClassLoader()); - in.readList(sourcePaths, String.class.getClassLoader()); - in.readList(classPaths, String.class.getClassLoader()); - } - - public File getBuildDir() { - return new File(getMainModulePath(), "build"); - } - - public AndroidProject setMainModule(String mainModule) { - this.mainModule = mainModule; - return this; - } - - public String getMainModule() { - return mainModule; - } - - public String getMainModulePath() { - return new File(getProjectPath(), getMainModule()).getAbsolutePath(); - } - - public AndroidProject setMainSourcePath(String mainModulePath) { - this.mainSourcePath = mainModulePath; - return this; - } - - public String getMainSourcePath() { - return mainSourcePath; - } - - public AndroidProject setModulePaths(List modulePaths) { - this.modulePaths = modulePaths; - return this; - } - - public List getModulePaths() { - if (modulePaths == null) modulePaths = new ArrayList<>(); - return modulePaths; - } - - public AndroidProject addModule(String path) { - if (!getModulePaths().contains(path)) getModulePaths().add(path); - return this; - } - - public AndroidProject setSourcePaths(List sourcePaths) { - this.sourcePaths = sourcePaths; - return this; - } - - public List getSourcePaths() { - if (sourcePaths == null) sourcePaths = new ArrayList<>(); - return sourcePaths; - } - - public AndroidProject addSource(String path) { - if (!getSourcePaths().contains(path)) getSourcePaths().add(path); - return this; - } - - public AndroidProject setClassPaths(List classPaths) { - this.classPaths = classPaths; - return this; - } - - public List getClassPaths() { - if (classPaths == null) classPaths = new ArrayList<>(); - return classPaths; - } - - public AndroidProject addClasspath(String path) { - if (!getClassPaths().contains(path)) getClassPaths().add(path); - return this; - } - - public AndroidProject setAppName(String appName) { - this.appName = appName; - return this; - } - - public String getAppName() { - return appName; - } - - public AndroidProject setPackageName(String packageName) { - this.packageName = packageName; - return this; - } - - public String getPackageName() { - return packageName; - } - - public AndroidProject setIconPath(String iconPath) { - this.iconPath = iconPath; - return this; - } - - public String getIconPath() { - return iconPath; - } - - public AndroidProject setProjectPath(String projectPath) { - this.projectPath = projectPath; - return this; - } - - public String getProjectPath() { - return projectPath; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel p1, int p2) { - p1.writeString(appName); - p1.writeString(packageName); - p1.writeString(iconPath); - p1.writeString(projectPath); - p1.writeString(mainModule); - p1.writeString(mainSourcePath); - p1.writeList(modulePaths); - p1.writeList(sourcePaths); - p1.writeList(classPaths); - } - - @Override - public String toString() { - return "[" - + "\nappName=" - + getAppName() - + "\npackageName=" - + getPackageName() - + "\niconPath=" - + getIconPath() - + "\nprojectPath=" - + getProjectPath() - + "\nmainModule=" - + getMainModule() - + "\nmainModulePath=" - + getMainModulePath() - + "\nmainModuleSourcePath=" - + getMainSourcePath() - + "\nmodules=" - + getModulePaths() - + "\nsources=" - + getSourcePaths() - + "\nclasspaths=" - + getClassPaths() - + "\n]"; - } - - public static final Creator CREATOR = - new Creator() { - - @Override - public AndroidProject createFromParcel(Parcel p1) { - return new AndroidProject(p1); - } - - @Override - public AndroidProject[] newArray(int p1) { - return new AndroidProject[p1]; - } - }; -} diff --git a/app/src/main/java/com/itsaky/androidide/projects/IDEModule.java b/app/src/main/java/com/itsaky/androidide/projects/IDEModule.java deleted file mode 100644 index b2171079a..000000000 --- a/app/src/main/java/com/itsaky/androidide/projects/IDEModule.java +++ /dev/null @@ -1,68 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ -package com.itsaky.androidide.projects; - -import com.google.gson.annotations.SerializedName; - -/** - * Represents a module (subproject) of a root project. - * - *

In Android projects, a module can either be an application project, or a library project. - */ -public class IDEModule extends IDEProject { - - /** Build tools version of this project */ - @SerializedName("buildToolsVersion") - public String buildToolsVersion; - - /** - * Compile SDK version of this project - * - *

Representation: 'android-31', 'android-30', 'android-29', etc - */ - @SerializedName("compileSdkVersion") - public String compileSdkVersion; - - /** Minimum SDK version of this project */ - @SerializedName("minSdk") - public SDK minSdk; - - /** Target SDK version of this project */ - @SerializedName("targetSdk") - public SDK targetSdk; - - /** Version code of this project */ - @SerializedName("versionCode") - public int versionCode = 0; - - /** Version name of this project */ - @SerializedName("versionName") - public String versionName = "Not defined"; - - /** Is this project an Android library project? */ - @SerializedName("isLibrary") - public boolean isLibrary = true; - - /** Does this module has viewBinding enabled? */ - @SerializedName("viewBindingEnabled") - public boolean viewBindingEnabled; - - /** Library projects don't have applicationId, application projects do. */ - @SerializedName("applicationId") - public String applicationId; -} diff --git a/app/src/main/java/com/itsaky/androidide/projects/IDEProject.java b/app/src/main/java/com/itsaky/androidide/projects/IDEProject.java deleted file mode 100644 index c00012236..000000000 --- a/app/src/main/java/com/itsaky/androidide/projects/IDEProject.java +++ /dev/null @@ -1,96 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ -package com.itsaky.androidide.projects; - -import com.google.gson.annotations.SerializedName; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -/** A model that contains data of a project currently opened in AndroidIDE */ -public class IDEProject { - - /** Name of this project */ - @SerializedName("name") - public String name = ""; - - /** Name of this project which should be displayed to user */ - @SerializedName("displayName") - public String displayName = ""; - - /** Description of this project. Maybe null. */ - @SerializedName("description") - public String description = ""; - - /** - * Path of this project. This is NOT the directory path of this project. - * - *

For example, ':app or ':module:subModule' - */ - @SerializedName("path") - public String path = ""; - - /** Path of the directory containing this project */ - @SerializedName("projectDir") - public String projectDir; - - /** File path of the application's icon We get this manually by parsing AndroidManifest.xml */ - public String iconPath; - - /** Subprojects of this project */ - @SerializedName("modules") - public List modules = new ArrayList<>(); - - /** Tasks included in this project */ - @SerializedName("tasks") - public List tasks = new ArrayList<>(); - - /** Path of jar file of dependencies of this project */ - @SerializedName("dependencies") - public List dependencies = new ArrayList<>(); - - /** - * Get the module by its path - * - * @param path Path of the module - * @return An Optional containing the IDEModule or Optional.empty() - */ - public Optional getModuleByPath(String path) { - if (modules != null && modules.size() > 0) { - for (IDEModule module : modules) { - if (module == null) continue; - if (module.path.trim().equals(path.trim())) return Optional.of(module); - } - } - return Optional.empty(); - } - - /** Stores information about a SDK. Like, • Codename • API string • API level */ - public static class SDK { - - @SerializedName("codename") - public String codename; - - @SerializedName("apiString") - public String apiString; - - @SerializedName("apiLevel") - public int apiLevel; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/projects/IDETask.java b/app/src/main/java/com/itsaky/androidide/projects/IDETask.java deleted file mode 100644 index 1d3809d33..000000000 --- a/app/src/main/java/com/itsaky/androidide/projects/IDETask.java +++ /dev/null @@ -1,44 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ -package com.itsaky.androidide.projects; - -import com.google.gson.annotations.SerializedName; - -/** Represents a Gradle task */ -public class IDETask { - - /** Name of this task */ - @SerializedName("name") - public String name; - - /** Description of this task */ - @SerializedName("description") - public String description; - - /** Name of the group that this task belongs to */ - @SerializedName("group") - public String group; - - /** - * Path of this task - * - *

For example, ':app:assembleDebug', ':app:build' - */ - @SerializedName("path") - public String path; -} diff --git a/app/src/main/java/com/itsaky/androidide/projects/ProjectFileObserver.java b/app/src/main/java/com/itsaky/androidide/projects/ProjectFileObserver.java deleted file mode 100644 index 1e2a345c8..000000000 --- a/app/src/main/java/com/itsaky/androidide/projects/ProjectFileObserver.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of AndroidIDE. - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - */ - -package com.itsaky.androidide.projects; - -import android.os.FileObserver; - -/** - * A file observer that observer files in project directories. Sub classes need to provide the file - * extensions that they want to get notified about. - * - * @author Akash Yadav - */ -public abstract class ProjectFileObserver extends FileObserver { - // Cannot use constructors that accept java.io.File - // They were added in API 29 - public ProjectFileObserver(String path) { - this(path, ALL_EVENTS); - } - - public ProjectFileObserver(String path, int mask) { - super(path, mask); - } -} diff --git a/app/src/main/java/com/itsaky/androidide/projects/ProjectManager.kt b/app/src/main/java/com/itsaky/androidide/projects/ProjectManager.kt index 2ce0f5ce1..9e663077b 100644 --- a/app/src/main/java/com/itsaky/androidide/projects/ProjectManager.kt +++ b/app/src/main/java/com/itsaky/androidide/projects/ProjectManager.kt @@ -36,16 +36,64 @@ import java.nio.file.Path object ProjectManager { private val log = com.itsaky.androidide.utils.ILogger.newInstance(javaClass.simpleName) var rootProject: IdeGradleProject? = null + var projectPath: String? = null + + fun getProjectDir(): String? = + if (rootProject == null) projectPath else rootProject!!.projectDir!!.absolutePath + + fun getApplicationModule(): IdeAndroidModule? { + if (rootProject == null) { + log.error( + "No root project instance is set. Is the project initialization process finished?") + return null + } + + val app = rootProject!!.findFirstAndroidModule() + if (app == null) { + log.error("No application module found in root project.") + return null + } + + return app + } + + fun getApplicationResDirectories(): List? { + return collectResDirectories(getApplicationModule() ?: return null) + } + + fun collectResDirectories(android: IdeAndroidModule): List { + val main = android.mainSourceSet + if (main == null) { + log.error("No main source set found in application module: ${android.name}") + return emptyList() + } + + val dirs = mutableListOf() + if (main.sourceProvider.resDirectories != null) { + dirs.addAll(main.sourceProvider.resDirectories!!) + } + + val dependencies = + collectProjectDependencies(rootProject!!, android) + .filterIsInstance(IdeAndroidModule::class.java) + + for (dependency in dependencies) { + dirs.addAll(collectResDirectories(dependency)) + } + + return dirs + } fun notifyProjectUpdate(server: JavaLanguageServer) { - val sourceDirs = collectApplicationSourceDirs(rootProject!!) - val classPaths = collectApplicationClassPaths(rootProject!!) + val sourceDirs = collectApplicationSourceDirs() + val classPaths = collectApplicationClassPaths() val configuration = JavaServerConfiguration(classPaths, sourceDirs) server.configurationChanged(configuration) } - private fun collectApplicationClassPaths(rootProject: IdeGradleProject): Set { - val app = getApplicationModule(rootProject) + private fun collectApplicationClassPaths(): Set { + val app = getApplicationModule() ?: return emptySet() + val libraries = app.variantDependencies["debug"]!!.libraries val paths = mutableSetOf() @@ -55,7 +103,8 @@ object ProjectManager { } else if (value.type == JAVA_LIBRARY) { paths.add(value.artifact!!.toPath()) } else { - val project = rootProject.findByPath(value.projectInfo!!.projectPath)!! as IdeModule + val project = + rootProject!!.findByPath(value.projectInfo!!.projectPath)!! as IdeModule paths.add(project.getGeneratedJar("debug").toPath()) if (project is IdeAndroidModule && project.projectPath != app.projectPath) { @@ -73,22 +122,16 @@ object ProjectManager { return paths } - private fun collectApplicationSourceDirs(rootProject: IdeGradleProject): Set { - val app = getApplicationModule(rootProject) + private fun collectApplicationSourceDirs(): Set { + val app = getApplicationModule() ?: return emptySet() val sources = app.mainSourceSet ?: return emptySet() val javaDirs = sources.sourceProvider.javaDirectories val sourcePaths = javaDirs.toMutableSet() - val projectSources = collectSourceDirs(collectProjectDependencies(rootProject, app)) + val projectSources = collectSourceDirs(collectProjectDependencies(rootProject!!, app)) sourcePaths.addAll(projectSources) return sourcePaths.map { it.toPath() }.toSet() } - private fun getApplicationModule(rootProject: IdeGradleProject): IdeAndroidModule { - return rootProject.findFirstAndroidModule() - ?: throw UnsupportedOperationException( - "No application module found in project ${rootProject.name} (${rootProject.projectPath})") - } - fun collectProjectDependencies( project: IdeGradleProject, app: IdeAndroidModule diff --git a/app/src/main/java/com/itsaky/androidide/services/builder/BuildListener.java b/app/src/main/java/com/itsaky/androidide/services/builder/BuildListener.java deleted file mode 100755 index fb34f6cf5..000000000 --- a/app/src/main/java/com/itsaky/androidide/services/builder/BuildListener.java +++ /dev/null @@ -1,83 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ -package com.itsaky.androidide.services.builder; - -import com.itsaky.androidide.projects.IDEModule; -import com.itsaky.androidide.projects.IDEProject; -import com.itsaky.androidide.tasks.GradleTask; - -import java.util.Optional; - -/** A client should implement this interface to get callbacks about a build */ -public interface BuildListener { - /** Called to notify the client about the modification of build/generated files */ - void onBuildModified(); - - /** - * Called when the project has been loaded and its data has been read - * - * @param project The loaded project - * @param appModule The main application module - */ - void onProjectLoaded(IDEProject project, Optional appModule); - - /** - * Called when a Gradle Daemon is being started - * - * @param task Task that is currently running - */ - void onStartingGradleDaemon(GradleTask task); - - /** - * Called when a task is started - * - * @param task Task that is currently running - * @param name Name of this task that should be shown to user - */ - void onRunTask(GradleTask task, String name); - - /** - * Notifys about a successful build - * - * @param task Task that succeeded - * @param msg Successful message - */ - void onBuildSuccessful(GradleTask task, String msg); - - /** - * Notifys about a failed build - * - * @param task Task that failed - * @param msg Failure message - */ - void onBuildFailed(GradleTask task, String msg); - - /** Called to notify client to save any opened files */ - void saveFiles(); - - /** - * Notifys the client to append the build output that should be shown to user - * - * @param task Task that is currently running - * @param text Output to append - */ - void appendOutput(GradleTask task, CharSequence text); - - /** Called to notify the client to prepare for a build */ - void prepareBuild(); -} diff --git a/app/src/main/java/com/itsaky/androidide/services/builder/IDEService.java b/app/src/main/java/com/itsaky/androidide/services/builder/IDEService.java deleted file mode 100755 index 6794b8ce9..000000000 --- a/app/src/main/java/com/itsaky/androidide/services/builder/IDEService.java +++ /dev/null @@ -1,493 +0,0 @@ -/* - * This file is part of AndroidIDE. - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - */ -package com.itsaky.androidide.services.builder; - -import static com.itsaky.androidide.managers.ToolsManager.getCommonAsset; - -import androidx.annotation.NonNull; -import androidx.annotation.StringRes; - -import com.blankj.utilcode.util.FileIOUtils; -import com.blankj.utilcode.util.FileUtils; -import com.blankj.utilcode.util.ResourceUtils; -import com.blankj.utilcode.util.ZipUtils; -import com.google.gson.Gson; -import com.itsaky.androidide.R; -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.managers.PreferenceManager; -import com.itsaky.androidide.projects.IDEModule; -import com.itsaky.androidide.projects.IDEProject; -import com.itsaky.androidide.shell.IProcessExecutor; -import com.itsaky.androidide.shell.IProcessExitListener; -import com.itsaky.androidide.shell.ProcessExecutorFactory; -import com.itsaky.androidide.shell.ProcessStreamsHolder; -import com.itsaky.androidide.tasks.GradleTask; -import com.itsaky.androidide.tasks.gradle.BaseGradleTasks; -import com.itsaky.androidide.tasks.gradle.resources.UpdateResourceClassesTask; -import com.itsaky.androidide.utils.Environment; -import com.itsaky.androidide.utils.InputStreamLineReader; -import com.itsaky.androidide.utils.ILogger; -import com.itsaky.toaster.Toaster; - -import org.jetbrains.annotations.Contract; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; - -public class IDEService { - - public static final int TASK_SHOW_DEPENDENCIES = GradleTask.TASK_SHOW_DEPENDENCIES; - public static final int TASK_ASSEMBLE_DEBUG = GradleTask.TASK_ASSEMBLE_DEBUG; - public static final int TASK_ASSEMBLE_RELEASE = GradleTask.TASK_ASSEMBLE_RELEASE; - public static final int TASK_BUILD = GradleTask.TASK_BUILD; - public static final int TASK_BUNDLE = GradleTask.TASK_BUNDLE; - public static final int TASK_CLEAN = GradleTask.TASK_CLEAN; - public static final int TASK_CLEAN_BUILD = GradleTask.TASK_CLEAN_BUILD; - public static final int TASK_DEX = GradleTask.TASK_DEX; - public static final int TASK_LINT = GradleTask.TASK_LINT; - public static final int TASK_LINT_DEBUG = GradleTask.TASK_LINT_DEBUG; - public static final int TASK_LINT_RELEASE = GradleTask.TASK_LINT_RELEASE; - public static final ILogger LOG = ILogger.newInstance("IDEService"); - private final File projectRoot; - private final IProcessExecutor processExecutor; - private BuildListener listener; - private GradleTask currentTask; - private IDEProject mIDEProject; - private IDEModule mAppModule; - private final InputStreamLineReader.OnReadListener mOutputReadListener = this::onBuildOutput; - private boolean isBuilding = false; - private final IProcessExitListener mProcessExitListener = - new IProcessExitListener() { - @Override - public void onExit(int code) { - isBuilding = false; - if (listener != null) { - final String msg = getString(R.string.msg_gradle_terminated, code); - if (code == 0) { - onBuildSuccessful(currentTask, msg); - } else { - onBuildFailed(currentTask, msg); - } - } - } - }; - - public IDEService(File projectRoot) { - this.projectRoot = projectRoot; - this.processExecutor = ProcessExecutorFactory.commonExecutor(); - } - - public IDEService setListener(final BuildListener listener) { - this.listener = listener == null ? null : new MainThreadBuildListener(listener); - return this; - } - - protected void onBuildOutput(String line) { - if (listener == null || line == null) return; - line = line.trim(); - - String PROJECT_INITIALIZED = ">>> PROJECT INITIALIZED <<<"; - if (line.contains(PROJECT_INITIALIZED)) { - readIdeProject(); - return; - } - - String text = line; - - final var app = StudioApp.getInstance(); - // Try to shorten common file paths - if (line.contains(app.getRootDir().getAbsolutePath())) { - text = line.replace(app.getRootDir().getAbsolutePath(), "HOME"); - } - if (line.contains( - Objects.requireNonNull(app.getRootDir().getParentFile()).getAbsolutePath())) { - text = line.replace(app.getRootDir().getParentFile().getAbsolutePath(), "ROOT"); - } - - listener.appendOutput(currentTask, text); - - String RUN_TASK = "> Task"; - String STARTING_DAEMON = "Starting a "; - if (line.startsWith(RUN_TASK)) { - listener.onRunTask(currentTask, line.trim()); - } else if (line.startsWith(STARTING_DAEMON)) { - listener.onStartingGradleDaemon(currentTask); - } - } - - protected void onBuildSuccessful(GradleTask task, String msg) { - if (currentTask != null && currentTask.getTaskID() != TASK_SHOW_DEPENDENCIES) { - listener.onBuildSuccessful(task, msg.trim()); - } - appendOutputSeparator(); - - if (currentTask != null && currentTask.affectsGeneratedSources()) { - notifyExternalSourceChange(); - } - } - - protected void onBuildFailed(GradleTask task, @NonNull String msg) { - isBuilding = false; - listener.onBuildFailed(task, msg.trim()); - appendOutputSeparator(); - } - - private void readIdeProject() { - // Parsing project data is meaningless if there is no one listening... - if (listener == null) { - return; - } - - final BuildListener local = listener; - new Thread( - () -> { - mIDEProject = - new Gson() - .fromJson( - FileIOUtils.readFile2String( - Environment.PROJECT_DATA_FILE), - IDEProject.class); - if (mIDEProject != null) { - Optional appModule = mIDEProject.getModuleByPath(":app"); - appModule.ifPresent(ideModule -> mAppModule = ideModule); - local.onProjectLoaded(mIDEProject, appModule); - } else { - StudioApp.getInstance() - .toast( - com.itsaky.androidide.R.string - .msg_init_project_failed, - Toaster.Type.ERROR); - } - }) - .start(); - } - - private void appendOutputSeparator() { - listener.appendOutput(currentTask, "\n\n"); - } - - public void exit() { - // Delete the tmp directory. It is not needed anymore... - FileUtils.delete(Environment.TMP_DIR); - } - - @NonNull - private String currentTime() { - String pattern = "HH:mm:ss"; - DateFormat df = new SimpleDateFormat(pattern, Locale.US); - Date today = Calendar.getInstance().getTime(); - return df.format(today); - } - - private String getString(@StringRes int id) { - return StudioApp.getInstance().getString(id); - } - - private String getString(@StringRes int id, Object... format) { - return StudioApp.getInstance().getString(id, format); - } - - private void notifyExternalSourceChange() { - // TODO Watch for file changes using a file observer - // instead of depending on the build - if (listener != null) { - listener.onBuildModified(); - } - } - - @NonNull - private String[] getArguments(List tasks) { - final PreferenceManager prefs = StudioApp.getInstance().getPrefManager(); - final List args = new ArrayList<>(); - - // 'bash' shell is always preferred - if (Environment.SHELL.exists()) { - args.add(Environment.SHELL.getAbsolutePath()); - } else { - args.add(Environment.BUSYBOX.getAbsolutePath()); - args.add("sh"); - } - - args.add(new File(projectRoot, "gradlew").getAbsolutePath()); - args.addAll(asAppTasks(tasks)); - args.add("--init-script"); - args.add(Environment.INIT_SCRIPT.getAbsolutePath()); - - if (prefs.isStackTraceEnabled()) { - args.add("--stacktrace"); - } - if (prefs.isGradleInfoEnabled()) { - args.add("--info"); - } - if (prefs.isGradleDebugEnabled()) { - args.add("--debug"); - } - if (prefs.isGradleScanEnabled()) { - args.add("--scan"); - } - if (prefs.isGradleWarningEnabled()) { - args.add("--warning-mode"); - args.add("all"); - } - if (prefs.isGradleBuildCacheEnabled()) { - args.add("--build-cache"); - } - if (prefs.isGradleOfflineModeEnabled()) { - args.add("--offline"); - } - - return args.toArray(new String[0]); - } - - private Collection asAppTasks(@NonNull List tasks) { - return tasks.stream() - .filter(Objects::nonNull) - .map(this::asAppModuleTask) - .collect(Collectors.toList()); - } - - @Contract(pure = true) - private String asAppModuleTask(@NonNull String name) { - return name.startsWith(":app:") ? name : ":app:" + name; - } - - public void execTask(GradleTask task) { - execTask(task, false); - } - - public void execTask(GradleTask task, boolean stopIfRunning) { - if (stopIfRunning && isBuilding()) { - stopAllDaemons(); - } else if (isBuilding()) { - return; - } - - execTask( - task, - isGradleWrapperAvailable() - ? CompletableFuture.completedFuture(Boolean.TRUE) - : installWrapper()); - } - - private void execTask(GradleTask task, CompletableFuture installing) { - - final Runnable taskRunner = - () -> { - if (installing != null) { - Boolean result; - String failure = ""; - try { - result = installing.get(); - } catch (Throwable th) { - result = Boolean.FALSE; - failure = th.getMessage(); - } - - if (result.equals(Boolean.FALSE)) { - if (listener != null) { - listener.appendOutput( - task, "-------------------- ERROR --------------------"); - listener.appendOutput( - task, - getString( - R.string.msg_gradlew_installation_failed, failure)); - listener.appendOutput( - task, "-----------------------------------------------"); - } - return; - } - } - - if (listener != null) { - - final ProcessStreamsHolder holder = new ProcessStreamsHolder(); - - listener.saveFiles(); - - currentTask = task; - listener.appendOutput( - task, - getString(R.string.msg_task_begin, currentTime(), task.getName())); - try { - - Environment.mkdirIfNotExits(Environment.TMP_DIR); - - processExecutor.execAsync( - holder, - mProcessExitListener, - projectRoot.getAbsolutePath(), - true, - getArguments(task.getTasks())); - isBuilding = true; - - startReading(holder.in); - - listener.prepareBuild(); - } catch (Throwable e) { - listener.onBuildFailed(task, e.getMessage()); - } - } - }; - - final Thread thread = new Thread(taskRunner, "GradleTaskExecutor"); - thread.setDaemon(true); - thread.start(); - } - - private void startReading(InputStream in) { - final Thread reader = - new Thread( - new InputStreamLineReader(in, mOutputReadListener), - "GradleProcessOutputReader"); - reader.setDaemon(true); - reader.start(); - } - - private CompletableFuture installWrapper() { - if (listener != null) { - listener.appendOutput(null, "-------------------- NOTE --------------------"); - listener.appendOutput(null, getString(R.string.msg_installing_gradlew)); - listener.appendOutput(null, "----------------------------------------------"); - } - - return CompletableFuture.supplyAsync( - () -> { - final File extracted = new File(Environment.TMP_DIR, "gradle-wrapper.zip"); - if (ResourceUtils.copyFileFromAssets( - getCommonAsset("gradle-wrapper.zip"), extracted.getAbsolutePath())) { - try { - final List files = ZipUtils.unzipFile(extracted, projectRoot); - if (files != null && !files.isEmpty()) { - return Boolean.TRUE; - } - } catch (IOException e) { - return Boolean.FALSE; - } - } - - return Boolean.FALSE; - }); - } - - public boolean isGradleWrapperAvailable() { - if (projectRoot == null || !projectRoot.exists()) { - return false; - } - final File gradlew = new File(projectRoot, "gradlew"); - final File gradleWrapperJar = new File(projectRoot, "gradle/wrapper/gradle-wrapper.jar"); - final File gradleWrapperProps = - new File(projectRoot, "gradle/wrapper/gradle-wrapper.properties"); - - return gradlew.exists() && gradleWrapperJar.exists() && gradleWrapperProps.exists(); - } - - public void assembleDebug() { - execTask(BaseGradleTasks.ASSEMBLE_DEBUG); - } - - public void assembleRelease() { - execTask(BaseGradleTasks.ASSEMBLE_RELEASE); - } - - public void build() { - execTask(BaseGradleTasks.BUILD); - } - - public void bundle() { - execTask(BaseGradleTasks.BUNDLE); - } - - public void clean() { - execTask(BaseGradleTasks.CLEAN); - } - - public void cleanAndRebuild() { - execTask(BaseGradleTasks.CLEAN_BUILD); - } - - public void stopAllDaemons() { - StudioApp.getInstance() - .newShell(null) - .bgAppend( - String.format( - Locale.US, - "cd '%s' && sh gradlew --stop", - projectRoot.getAbsolutePath())); - if (isBuilding()) { - if (listener != null) - listener.onBuildFailed(currentTask, getString(R.string.msg_daemons_stopped)); - isBuilding = false; - } - } - - public void lint() { - execTask(BaseGradleTasks.LINT); - } - - public void lintDebug() { - execTask(BaseGradleTasks.LINT_DEBUG); - } - - public void lintRelease() { - execTask(BaseGradleTasks.LINT_RELEASE); - } - - public void updateResourceClasses() { - execTask( - new UpdateResourceClassesTask(mAppModule != null && mAppModule.viewBindingEnabled)); - } - - public boolean isBuilding() { - return isBuilding; - } - - public String typeString(int type) { - switch (type) { - case TASK_ASSEMBLE_DEBUG: - return getString(R.string.build_debug); - case TASK_ASSEMBLE_RELEASE: - return getString(R.string.build_release); - case TASK_BUILD: - return getString(R.string.build); - case TASK_CLEAN_BUILD: - return getString(R.string.clean_amp_build); - case TASK_CLEAN: - return getString(R.string.clean_project); - case TASK_BUNDLE: - return getString(R.string.create_aab); - case TASK_DEX: - return getString(R.string.compiling); - default: - return ""; - } - } -} - diff --git a/app/src/main/java/com/itsaky/androidide/services/builder/MainThreadBuildListener.java b/app/src/main/java/com/itsaky/androidide/services/builder/MainThreadBuildListener.java deleted file mode 100755 index 07ebc3762..000000000 --- a/app/src/main/java/com/itsaky/androidide/services/builder/MainThreadBuildListener.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * This file is part of AndroidIDE. - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - */ -package com.itsaky.androidide.services.builder; - -import androidx.annotation.NonNull; - -import com.blankj.utilcode.util.ThreadUtils; -import com.itsaky.androidide.projects.IDEModule; -import com.itsaky.androidide.projects.IDEProject; -import com.itsaky.androidide.tasks.GradleTask; - -import java.util.Objects; -import java.util.Optional; - -class MainThreadBuildListener implements BuildListener { - - private final BuildListener listener; - - public MainThreadBuildListener(@NonNull final BuildListener listener) { - Objects.requireNonNull(listener, "Build listener cannot be null"); - this.listener = listener; - } - - @Override - public void onBuildModified() { - ThreadUtils.runOnUiThread(listener::onBuildModified); - } - - @Override - public void onProjectLoaded(IDEProject project, Optional appModule) { - ThreadUtils.runOnUiThread(() -> listener.onProjectLoaded(project, appModule)); - } - - @Override - public void onStartingGradleDaemon(GradleTask task) { - ThreadUtils.runOnUiThread(() -> listener.onStartingGradleDaemon(task)); - } - - @Override - public void onRunTask(GradleTask task, String name) { - ThreadUtils.runOnUiThread(() -> listener.onRunTask(task, name)); - } - - @Override - public void onBuildSuccessful(GradleTask task, String msg) { - ThreadUtils.runOnUiThread(() -> listener.onBuildSuccessful(task, msg)); - } - - @Override - public void onBuildFailed(GradleTask task, String msg) { - ThreadUtils.runOnUiThread(() -> listener.onBuildFailed(task, msg)); - } - - @Override - public void saveFiles() { - ThreadUtils.runOnUiThread(listener::saveFiles); - } - - @Override - public void appendOutput(GradleTask task, CharSequence text) { - ThreadUtils.runOnUiThread(() -> listener.appendOutput(task, text)); - } - - @Override - public void prepareBuild() { - ThreadUtils.runOnUiThread(listener::prepareBuild); - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/BaseGradleTask.java b/app/src/main/java/com/itsaky/androidide/tasks/BaseGradleTask.java deleted file mode 100755 index 143db5cd9..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/BaseGradleTask.java +++ /dev/null @@ -1,46 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks; - -import com.itsaky.androidide.services.builder.IDEService; - -public abstract class BaseGradleTask implements GradleTask { - - @Override - public boolean affectsGeneratedSources() { - return false; - } - - @Override - public boolean shouldSaveFiles() { - return getType() == Type.BUILD - || getType() == Type.LINT - || getTaskID() == IDEService.TASK_DEX; - } - - @Override - public boolean equals(Object obj) { - return obj != null - && obj instanceof GradleTask - && getTaskID() == ((GradleTask) obj).getTaskID() - && getType() == ((GradleTask) obj).getType(); - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/GradleTask.java b/app/src/main/java/com/itsaky/androidide/tasks/GradleTask.java deleted file mode 100755 index 1ef74b7f1..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/GradleTask.java +++ /dev/null @@ -1,68 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks; - -import java.util.List; - -public interface GradleTask { - - public String getName(); - - public String getCommands(); - - public List getTasks(); - - public int getTaskID(); - - public boolean affectsGeneratedSources(); - - public boolean shouldSaveFiles(); - - public boolean canOutput(); - - public Type getType(); - - public static enum Type { - ANDROIDIDE_PLUGIN, - BUILD, - LINT, - HELP, - OTHER - } - - public static final int TASK_SHOW_DEPENDENCIES = 0; - public static final int TASK_ASSEMBLE_DEBUG = 1; - public static final int TASK_ASSEMBLE_RELEASE = 2; - public static final int TASK_BUILD = 3; - public static final int TASK_BUNDLE = 4; - public static final int TASK_CLEAN = 5; - public static final int TASK_CLEAN_BUILD = 6; - public static final int TASK_COMPILE_JAVA = 7; - public static final int TASK_DEX = 8; - public static final int TASK_LINT = 9; - public static final int TASK_LINT_DEBUG = 10; - public static final int TASK_LINT_RELEASE = 11; - public static final int TASK_TASKS = 12; - public static final int TASK_INIT_PROJECT = 13; - public static final int TASK_PROCESS_DEBUG_RESOURCES = 14; - public static final int DATABINDING_GEN_BASE_CLASSES_DEBUG = 15; - public static final int TASK_UPDATE_RESOURCE_CLASSES = 16; -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/BaseGradleTasks.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/BaseGradleTasks.java deleted file mode 100755 index 1e59e9837..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/BaseGradleTasks.java +++ /dev/null @@ -1,49 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks.gradle; - -import com.itsaky.androidide.tasks.BaseGradleTask; -import com.itsaky.androidide.tasks.gradle.build.AssembleDebug; -import com.itsaky.androidide.tasks.gradle.build.AssembleRelease; -import com.itsaky.androidide.tasks.gradle.build.Build; -import com.itsaky.androidide.tasks.gradle.build.Bundle; -import com.itsaky.androidide.tasks.gradle.build.Clean; -import com.itsaky.androidide.tasks.gradle.build.CleanBuild; -import com.itsaky.androidide.tasks.gradle.lint.Lint; -import com.itsaky.androidide.tasks.gradle.lint.LintDebug; -import com.itsaky.androidide.tasks.gradle.lint.LintRelease; -import com.itsaky.androidide.tasks.gradle.plugin.InitializeIDEProject; -import com.itsaky.androidide.tasks.gradle.resources.ProcessDebugResources; - -public class BaseGradleTasks { - - public static final BaseGradleTask BUILD = new Build(), - ASSEMBLE_DEBUG = new AssembleDebug(), - ASSEMBLE_RELEASE = new AssembleRelease(), - BUNDLE = new Bundle(), - CLEAN = new Clean(), - CLEAN_BUILD = new CleanBuild(), - LINT = new Lint(), - LINT_DEBUG = new LintDebug(), - LINT_RELEASE = new LintRelease(), - PROCESS_DEBUG_RESOURCES = new ProcessDebugResources(), - INITIALIZE_IDE_PROJECT = new InitializeIDEProject(); -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/ApkGeneratingTask.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/ApkGeneratingTask.java deleted file mode 100644 index aab48e9f4..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/ApkGeneratingTask.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * This file is part of AndroidIDE. - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - */ - -package com.itsaky.androidide.tasks.gradle.build; - -import static com.itsaky.androidide.models.ApkMetadata.ArtifactType; -import static com.itsaky.androidide.models.ApkMetadata.Element; - -import com.blankj.utilcode.util.FileIOUtils; -import com.blankj.utilcode.util.FileUtils; -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.models.ApkMetadata; -import com.itsaky.androidide.tasks.BaseGradleTask; -import com.itsaky.androidide.utils.JSONUtility; -import com.itsaky.androidide.utils.ILogger; - -import java.io.File; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public abstract class ApkGeneratingTask extends BaseGradleTask { - - private static final ILogger LOG = ILogger.newInstance("ApkGeneratingTask"); - - /** - * Get the directories where APKs are generated. These directories must contain an - * output-metadata.json file - */ - protected abstract Set provideApkDirectories(File buildDir); - - protected Set directories(File buildDir) { - if (buildDir == null || !buildDir.exists() || !buildDir.isDirectory()) { - return Collections.emptySet(); - } - - return provideApkDirectories(buildDir); - } - - /** Get generated APKs */ - public Set getApks(File buildDir) { - final Set result = new HashSet<>(); - final Set dirs = directories(buildDir); - if (dirs == null || dirs.isEmpty()) { - LOG.error("No apk directories found. buildDir=" + buildDir); - return result; - } - - for (File dir : dirs) { - final File jsonData = new File(dir, "output-metadata.json"); - if (!jsonData.exists() || !FileUtils.isUtf8(jsonData)) { - LOG.error( - "No output-metadata.json file found in APK output directory" - + " or the file is empty. APK directory:", - dir); - continue; - } - - final String contents = FileIOUtils.readFile2String(jsonData); - - try { - final ApkMetadata metadata = JSONUtility.gson.fromJson(contents, ApkMetadata.class); - if (!isValid(metadata)) { - LOG.warn("Invalid APK metadata:", metadata); - continue; - } - - for (Element element : metadata.getElements()) { - if (element == null || element.getOutputFile() == null) { - LOG.warn("No output file specified in APK metadata element:", element); - continue; - } - - if (element.getOutputFile().endsWith(".apk")) { - final File apk = new File(dir, element.getOutputFile()); - if (apk.exists() && apk.isFile()) { - LOG.info("APK generated:", apk); - result.add(apk); - } - } - } - - } catch (Throwable th) { - LOG.error( - StudioApp.getInstance() - .getString( - com.itsaky.androidide.R.string - .err_cannot_parse_apk_metadata), - th); - } - } - return result; - } - - private boolean isValid(ApkMetadata metadata) { - - // Null checks - if (metadata == null - || metadata.getArtifactType() == null - || metadata.getArtifactType().getType() == null - || metadata.getElements() == null) { - LOG.warn("APK metadata null check failed. Metadata:", metadata); - return false; - } - - final ArtifactType type = metadata.getArtifactType(); - final List elements = metadata.getElements(); - - if (!type.getType().equals(ArtifactType.TYPE_APK)) { - LOG.warn("Artifact is not of type APK. Metadata:", metadata); - return false; - } - - if (elements.isEmpty()) { - LOG.warn("No output elements found for metadata:", metadata); - return false; - } - - boolean atLeastOneApk = false; - for (Element element : elements) { - if (element == null - || element.getOutputFile() == null - || !element.getOutputFile().endsWith(".apk")) { - LOG.warn("Skipping output element because file is not APK:", element); - continue; - } - - if (element.getOutputFile().endsWith(".apk")) { - atLeastOneApk = true; - break; - } - } - - LOG.debug("Output metadata validation succeeded"); - return atLeastOneApk; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/AssembleDebug.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/AssembleDebug.java deleted file mode 100755 index a11c5e613..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/AssembleDebug.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of AndroidIDE. - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - */ - -package com.itsaky.androidide.tasks.gradle.build; - -import com.itsaky.androidide.R; -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.services.builder.IDEService; - -import java.io.File; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public class AssembleDebug extends ApkGeneratingTask { - - @Override - public String getName() { - return StudioApp.getInstance().getString(R.string.build_debug); - } - - @Override - protected Set provideApkDirectories(File buildDir) { - final Set dirs = new HashSet<>(); - dirs.add(new File(buildDir, "outputs/apk/debug")); - return dirs; - } - - @Override - public String getCommands() { - return "assembleDebug"; - } - - @Override - public List getTasks() { - return Collections.singletonList(getCommands()); - } - - @Override - public int getTaskID() { - return IDEService.TASK_ASSEMBLE_DEBUG; - } - - @Override - public boolean canOutput() { - return true; - } - - @Override - public Type getType() { - return Type.BUILD; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/AssembleRelease.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/AssembleRelease.java deleted file mode 100755 index 76e43cc59..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/AssembleRelease.java +++ /dev/null @@ -1,72 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks.gradle.build; - -import com.itsaky.androidide.R; -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.services.builder.IDEService; -import com.itsaky.androidide.tasks.GradleTask; - -import java.io.File; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public class AssembleRelease extends ApkGeneratingTask { - - @Override - public String getName() { - return StudioApp.getInstance().getString(R.string.build_release); - } - - @Override - protected Set provideApkDirectories(File buildDir) { - final Set dirs = new HashSet<>(); - dirs.add(new File(buildDir, "outputs/apk/release")); - return dirs; - } - - @Override - public String getCommands() { - return "assembleRelease"; - } - - @Override - public List getTasks() { - return Arrays.asList(getCommands()); - } - - @Override - public int getTaskID() { - return IDEService.TASK_ASSEMBLE_RELEASE; - } - - @Override - public boolean canOutput() { - return true; - } - - @Override - public GradleTask.Type getType() { - return GradleTask.Type.BUILD; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/Build.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/Build.java deleted file mode 100755 index 57b605112..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/Build.java +++ /dev/null @@ -1,73 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks.gradle.build; - -import com.itsaky.androidide.R; -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.services.builder.IDEService; -import com.itsaky.androidide.tasks.GradleTask; - -import java.io.File; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public class Build extends ApkGeneratingTask { - - @Override - public String getName() { - return StudioApp.getInstance().getString(R.string.build); - } - - @Override - protected Set provideApkDirectories(File buildDir) { - final Set dirs = new HashSet<>(); - dirs.add(new File(buildDir, "outputs/apk/debug")); - dirs.add(new File(buildDir, "outputs/apk/release")); - return dirs; - } - - @Override - public String getCommands() { - return "build"; - } - - @Override - public List getTasks() { - return Arrays.asList(getCommands()); - } - - @Override - public int getTaskID() { - return IDEService.TASK_BUILD; - } - - @Override - public boolean canOutput() { - return true; - } - - @Override - public GradleTask.Type getType() { - return GradleTask.Type.BUILD; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/Bundle.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/Bundle.java deleted file mode 100755 index 0c8385b1f..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/Bundle.java +++ /dev/null @@ -1,63 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks.gradle.build; - -import com.itsaky.androidide.R; -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.services.builder.IDEService; -import com.itsaky.androidide.tasks.BaseGradleTask; -import com.itsaky.androidide.tasks.GradleTask; - -import java.util.Arrays; -import java.util.List; - -public class Bundle extends BaseGradleTask { - - @Override - public String getName() { - return StudioApp.getInstance().getString(R.string.create_aab); - } - - @Override - public String getCommands() { - return "bundle"; - } - - @Override - public List getTasks() { - return Arrays.asList(getCommands()); - } - - @Override - public int getTaskID() { - return IDEService.TASK_BUNDLE; - } - - @Override - public boolean canOutput() { - return true; - } - - @Override - public GradleTask.Type getType() { - return GradleTask.Type.BUILD; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/Clean.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/Clean.java deleted file mode 100755 index 721671534..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/Clean.java +++ /dev/null @@ -1,63 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks.gradle.build; - -import com.itsaky.androidide.R; -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.services.builder.IDEService; -import com.itsaky.androidide.tasks.BaseGradleTask; -import com.itsaky.androidide.tasks.GradleTask; - -import java.util.Arrays; -import java.util.List; - -public class Clean extends BaseGradleTask { - - @Override - public String getName() { - return StudioApp.getInstance().getString(R.string.clean_project); - } - - @Override - public String getCommands() { - return "clean"; - } - - @Override - public List getTasks() { - return Arrays.asList(getCommands()); - } - - @Override - public int getTaskID() { - return IDEService.TASK_CLEAN; - } - - @Override - public boolean canOutput() { - return true; - } - - @Override - public GradleTask.Type getType() { - return GradleTask.Type.BUILD; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/CleanBuild.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/CleanBuild.java deleted file mode 100755 index e3f912c69..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/build/CleanBuild.java +++ /dev/null @@ -1,63 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks.gradle.build; - -import com.itsaky.androidide.R; -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.services.builder.IDEService; -import com.itsaky.androidide.tasks.BaseGradleTask; -import com.itsaky.androidide.tasks.GradleTask; - -import java.util.Arrays; -import java.util.List; - -public class CleanBuild extends BaseGradleTask { - - @Override - public String getName() { - return StudioApp.getInstance().getString(R.string.clean_amp_build); - } - - @Override - public String getCommands() { - return "clean build"; - } - - @Override - public List getTasks() { - return Arrays.asList("clean", "build"); - } - - @Override - public int getTaskID() { - return IDEService.TASK_CLEAN_BUILD; - } - - @Override - public boolean canOutput() { - return true; - } - - @Override - public GradleTask.Type getType() { - return GradleTask.Type.BUILD; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/Lint.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/Lint.java deleted file mode 100755 index bd83e83c1..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/Lint.java +++ /dev/null @@ -1,62 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks.gradle.lint; - -import com.itsaky.androidide.R; -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.services.builder.IDEService; -import com.itsaky.androidide.tasks.BaseGradleTask; - -import java.util.Arrays; -import java.util.List; - -public class Lint extends BaseGradleTask { - - @Override - public String getName() { - return StudioApp.getInstance().getString(R.string.lint); - } - - @Override - public String getCommands() { - return "lint"; - } - - @Override - public List getTasks() { - return Arrays.asList("lint"); - } - - @Override - public int getTaskID() { - return IDEService.TASK_LINT; - } - - @Override - public boolean canOutput() { - return true; - } - - @Override - public Type getType() { - return Type.LINT; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/LintDebug.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/LintDebug.java deleted file mode 100755 index 2730f6883..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/LintDebug.java +++ /dev/null @@ -1,62 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks.gradle.lint; - -import com.itsaky.androidide.R; -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.services.builder.IDEService; -import com.itsaky.androidide.tasks.BaseGradleTask; - -import java.util.Collections; -import java.util.List; - -public class LintDebug extends BaseGradleTask { - - @Override - public String getName() { - return StudioApp.getInstance().getString(R.string.lint_debug); - } - - @Override - public String getCommands() { - return "lintDebug"; - } - - @Override - public List getTasks() { - return Collections.singletonList("lintDebug"); - } - - @Override - public int getTaskID() { - return IDEService.TASK_LINT_DEBUG; - } - - @Override - public boolean canOutput() { - return true; - } - - @Override - public Type getType() { - return Type.LINT; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/LintRelease.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/LintRelease.java deleted file mode 100755 index 929babd0c..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/lint/LintRelease.java +++ /dev/null @@ -1,62 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks.gradle.lint; - -import com.itsaky.androidide.R; -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.services.builder.IDEService; -import com.itsaky.androidide.tasks.BaseGradleTask; - -import java.util.Arrays; -import java.util.List; - -public class LintRelease extends BaseGradleTask { - - @Override - public String getName() { - return StudioApp.getInstance().getString(R.string.lint_release); - } - - @Override - public String getCommands() { - return "lintRelease"; - } - - @Override - public List getTasks() { - return Arrays.asList("lintRelease"); - } - - @Override - public int getTaskID() { - return IDEService.TASK_LINT_RELEASE; - } - - @Override - public boolean canOutput() { - return true; - } - - @Override - public Type getType() { - return Type.LINT; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/plugin/InitializeIDEProject.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/plugin/InitializeIDEProject.java deleted file mode 100755 index 1aa3603b9..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/plugin/InitializeIDEProject.java +++ /dev/null @@ -1,60 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks.gradle.plugin; - -import com.itsaky.androidide.tasks.BaseGradleTask; -import com.itsaky.androidide.tasks.GradleTask; - -import java.util.Arrays; -import java.util.List; - -public class InitializeIDEProject extends BaseGradleTask { - - @Override - public String getName() { - return "initializeIDEProject"; - } - - @Override - public String getCommands() { - return "initializeIDEProject"; - } - - @Override - public List getTasks() { - return Arrays.asList(getCommands()); - } - - @Override - public int getTaskID() { - return TASK_INIT_PROJECT; - } - - @Override - public boolean canOutput() { - return true; - } - - @Override - public GradleTask.Type getType() { - return Type.ANDROIDIDE_PLUGIN; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/resources/DatabindingGenBaseClassesDebug.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/resources/DatabindingGenBaseClassesDebug.java deleted file mode 100755 index beb8dd2d1..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/resources/DatabindingGenBaseClassesDebug.java +++ /dev/null @@ -1,64 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks.gradle.resources; - -import com.itsaky.androidide.tasks.BaseGradleTask; - -import java.util.Arrays; -import java.util.List; - -public class DatabindingGenBaseClassesDebug extends BaseGradleTask { - - @Override - public boolean affectsGeneratedSources() { - return true; - } - - @Override - public String getName() { - return "Generate databinding classes"; - } - - @Override - public String getCommands() { - return "databindingGenBaseClassesDebug"; - } - - @Override - public List getTasks() { - return Arrays.asList(getCommands()); - } - - @Override - public int getTaskID() { - return DATABINDING_GEN_BASE_CLASSES_DEBUG; - } - - @Override - public boolean canOutput() { - return true; - } - - @Override - public Type getType() { - return Type.BUILD; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/resources/ProcessDebugResources.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/resources/ProcessDebugResources.java deleted file mode 100755 index f2c61ca84..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/resources/ProcessDebugResources.java +++ /dev/null @@ -1,65 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks.gradle.resources; - -import com.itsaky.androidide.tasks.BaseGradleTask; -import com.itsaky.androidide.tasks.GradleTask; - -import java.util.Arrays; -import java.util.List; - -public class ProcessDebugResources extends BaseGradleTask { - - @Override - public boolean affectsGeneratedSources() { - return true; - } - - @Override - public String getName() { - return "processDebugResources"; - } - - @Override - public String getCommands() { - return "processDebugResources"; - } - - @Override - public List getTasks() { - return Arrays.asList(getCommands()); - } - - @Override - public int getTaskID() { - return TASK_PROCESS_DEBUG_RESOURCES; - } - - @Override - public boolean canOutput() { - return true; - } - - @Override - public GradleTask.Type getType() { - return Type.BUILD; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/tasks/gradle/resources/UpdateResourceClassesTask.java b/app/src/main/java/com/itsaky/androidide/tasks/gradle/resources/UpdateResourceClassesTask.java deleted file mode 100755 index 1fd747239..000000000 --- a/app/src/main/java/com/itsaky/androidide/tasks/gradle/resources/UpdateResourceClassesTask.java +++ /dev/null @@ -1,82 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.tasks.gradle.resources; - -import com.itsaky.androidide.tasks.BaseGradleTask; -import com.itsaky.androidide.tasks.GradleTask; - -import java.util.ArrayList; -import java.util.List; - -public class UpdateResourceClassesTask extends BaseGradleTask { - - private final boolean viewBinding; - - public UpdateResourceClassesTask(boolean viewBinding) { - this.viewBinding = viewBinding; - } - - @Override - public boolean affectsGeneratedSources() { - return true; - } - - @Override - public String getName() { - return "Update resource classes"; - } - - @Override - public String getCommands() { - String command = ""; - if (viewBinding) { - command = new DatabindingGenBaseClassesDebug().getCommands(); - command += " "; - } - command += new ProcessDebugResources().getCommands(); - return command; - } - - @Override - public List getTasks() { - List tasks = new ArrayList<>(); - if (viewBinding) { - tasks.addAll(new DatabindingGenBaseClassesDebug().getTasks()); - } - tasks.addAll(new ProcessDebugResources().getTasks()); - return tasks; - } - - @Override - public int getTaskID() { - return TASK_UPDATE_RESOURCE_CLASSES; - } - - @Override - public boolean canOutput() { - return true; - } - - @Override - public GradleTask.Type getType() { - return Type.BUILD; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/utils/EditorActivityActions.kt b/app/src/main/java/com/itsaky/androidide/utils/EditorActivityActions.kt index 9716ca12a..ed7395786 100644 --- a/app/src/main/java/com/itsaky/androidide/utils/EditorActivityActions.kt +++ b/app/src/main/java/com/itsaky/androidide/utils/EditorActivityActions.kt @@ -37,9 +37,9 @@ package com.itsaky.androidide.utils import android.content.Context import com.itsaky.androidide.actions.ActionItem import com.itsaky.androidide.actions.ActionsRegistry +import com.itsaky.androidide.actions.build.CancelBuildAction import com.itsaky.androidide.actions.build.QuickRunAction import com.itsaky.androidide.actions.build.RunActionMenu -import com.itsaky.androidide.actions.build.CancelBuildAction import com.itsaky.androidide.actions.editor.CopyAction import com.itsaky.androidide.actions.editor.CutAction import com.itsaky.androidide.actions.editor.ExpandSelectionAction diff --git a/app/src/main/java/com/itsaky/androidide/utils/ProjectFinder.java b/app/src/main/java/com/itsaky/androidide/utils/ProjectFinder.java deleted file mode 100755 index 6bcbbfd3b..000000000 --- a/app/src/main/java/com/itsaky/androidide/utils/ProjectFinder.java +++ /dev/null @@ -1,201 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - **************************************************************************************/ - -package com.itsaky.androidide.utils; - -import android.text.TextUtils; - -import com.blankj.utilcode.util.FileIOUtils; -import com.itsaky.androidide.projects.AndroidProject; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.File; -import java.io.FileFilter; -import java.util.regex.Pattern; - -import fr.arnaudguyon.xmltojsonlib.XmlToJson; - -public class ProjectFinder { - - public static AndroidProject fromFolder(File file) { - if (!file.isDirectory() || file.isHidden()) return null; - File settings = new File(file, "settings.gradle"); - if (!settings.exists()) return null; - String content = FileUtil.readFile(settings.getAbsolutePath()); - if (TextUtils.isEmpty(content)) return null; - - AndroidProject project = new AndroidProject(); - for (File module : file.listFiles()) { - if (module.isDirectory() && !module.isHidden()) { - try { - proceedModule(file, module, project); - } catch (JSONException e) { - continue; - } - } - } - - project.setAppName(file.getName()); - project.setProjectPath(file.getAbsolutePath()); - if (project.getMainModule() == null - && project.getModulePaths().size() > 0 - && project.getModulePaths().get(0) != null) { - File f = new File(project.getModulePaths().get(0)); - if (!f.exists() || !f.isDirectory()) return null; - project.setMainModule(f.getName()); - project.setMainSourcePath(new File(f, "src/main/java").getAbsolutePath()); - } - - return project; - } - - private static void proceedModule(File file, File module, AndroidProject project) - throws JSONException { - final Pattern appPattern = - Pattern.compile("apply\\s+plugin\\s*:\\s*(['\"])com.android.application(['\"])"); - File projectGradle = new File(file, "build.gradle"); - File moduleGradle = new File(module, "build.gradle"); - File manifest = new File(module, "src/main/AndroidManifest.xml"); - File res = new File(module, "src/main/res"); - if (!module.exists() - || !projectGradle.exists() - || !moduleGradle.exists() - || !manifest.exists()) return; - if (!module.isDirectory() - || !moduleGradle.isFile() - || !projectGradle.isFile() - || !manifest.isFile()) return; - - File java = new File(module, "src/main/java"); - if (java.exists() && java.isDirectory()) - project.addSource(java.getAbsolutePath()).addModule(module.getAbsolutePath()); - - File libsFolder = new File(module, "libs"); - if (libsFolder.exists() && libsFolder.isDirectory()) { - File[] libs = libsFolder.listFiles(); - if (libs != null && libs.length > 0) { - for (File lib : libs) - if (lib.getName().endsWith(".jar")) project.addClasspath(lib.getAbsolutePath()); - } - } - - project.addSource( - new File(module, "build/generated/source/buildConfig/debug").getAbsolutePath()); - project.addSource( - new File(module, "build/generated/data_binding_base_class_source_out/debug/out") - .getAbsolutePath()); - - JSONObject obj = - new XmlToJson.Builder(FileUtil.readFile(manifest.getAbsolutePath())) - .build() - .toJson(); - if (!obj.has("manifest")) return; - String iconPath = null; - if (obj.has("manifest") - && obj.getJSONObject("manifest").has("application") - && obj.getJSONObject("manifest").getJSONObject("application").has("android:icon")) { - String iconRes = - obj.getJSONObject("manifest") - .getJSONObject("application") - .getString("android:icon"); - if (iconRes.startsWith("@drawable")) { - final String iconName = iconRes.replace("@drawable/", ""); - File[] drawables = listDrawables(res); - for (File drawable : drawables) { - File[] icons = listFilesNotEndingWith(drawable, ".xml"); - for (File icon : icons) { - String nameWithoutExtension = - icon.getName().substring(0, icon.getName().lastIndexOf(".")); - if (nameWithoutExtension.equals(iconName)) { - iconPath = icon.getAbsolutePath(); - break; - } - } - } - } else if (iconRes.startsWith("@drawable")) { - final String iconName = iconRes.replace("@drawable/", ""); - File[] drawables = listMipmaps(res); - for (File drawable : drawables) { - File[] icons = listFilesNotEndingWith(drawable, ".xml"); - for (File icon : icons) { - String nameWithoutExtension = - icon.getName().substring(0, icon.getName().lastIndexOf(".")); - if (nameWithoutExtension.equals(iconName)) { - iconPath = icon.getAbsolutePath(); - break; - } - } - } - } - } - final String packageName = obj.getJSONObject("manifest").getString("package"); - final String mainModuleName = module.getName(); - - boolean isMainModule = false; - if (project.getMainModule() == null) { - String content = FileIOUtils.readFile2String(moduleGradle); - if (content != null && appPattern.matcher(content).find()) { - isMainModule = true; - project.setMainModule(mainModuleName); - project.setMainSourcePath(new File(module, "src/main/java").getAbsolutePath()); - } - } - - if (iconPath != null) { - project.setIconPath(iconPath); - } - - if (packageName != null && isMainModule) { - project.setPackageName(packageName); - } - } - - private static File[] listDrawables(File file) { - return listFolderStartingWith(file, "drawable"); - } - - private static File[] listMipmaps(File file) { - return listFolderStartingWith(file, "mipmap"); - } - - private static File[] listFolderStartingWith(File file, final String prefix) { - return file.listFiles( - new FileFilter() { - - @Override - public boolean accept(File p1) { - return p1.isDirectory() && p1.getName().startsWith(prefix); - } - }); - } - - private static File[] listFilesNotEndingWith(File file, final String suffix) { - return file.listFiles( - new FileFilter() { - - @Override - public boolean accept(File p1) { - return p1.isFile() && !p1.getName().endsWith(suffix); - } - }); - } -} diff --git a/app/src/main/java/com/itsaky/androidide/viewmodel/EditorViewModel.java b/app/src/main/java/com/itsaky/androidide/viewmodel/EditorViewModel.java index 5e6bf7991..98a5117fa 100644 --- a/app/src/main/java/com/itsaky/androidide/viewmodel/EditorViewModel.java +++ b/app/src/main/java/com/itsaky/androidide/viewmodel/EditorViewModel.java @@ -25,9 +25,6 @@ import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModel; -import com.itsaky.androidide.projects.AndroidProject; -import com.itsaky.androidide.projects.IDEProject; - import java.io.File; import java.util.ArrayList; import java.util.List; @@ -37,8 +34,6 @@ import java.util.Objects; public class EditorViewModel extends ViewModel { private final MutableLiveData> mFiles = new MutableLiveData<>(new ArrayList<>()); - private final MutableLiveData mProject = new MutableLiveData<>(null); - private final MutableLiveData mIDEProject = new MutableLiveData<>(null); private final MutableLiveData mFilesModified = new MutableLiveData<>(false); /** @@ -47,44 +42,6 @@ public class EditorViewModel extends ViewModel { */ private final MutableLiveData> mCurrentFile = new MutableLiveData<>(null); - /** - * Get the current {@link AndroidProject}. - * - * @return The android project. - */ - @Nullable - public AndroidProject getAndroidProject() { - return mProject.getValue(); - } - - /** - * Set the android project currently opened in the editor activity. - * - * @param project The project that is opened. - */ - public void setAndroidProject(final AndroidProject project) { - this.mProject.setValue(project); - } - - /** - * Get the {@link IDEProject} opened in the editor activity. - * - * @return The ide project. - */ - @Nullable - public IDEProject getIDEProject() { - return this.mIDEProject.getValue(); - } - - /** - * Set the IDEProject that is currently opened in the editor activity. - * - * @param project The project that is opened. - */ - public void setIDEProject(final IDEProject project) { - this.mIDEProject.setValue(project); - } - /** * Add the given file to the list of opened files. * @@ -112,6 +69,10 @@ public class EditorViewModel extends ViewModel { setCurrentFile(-1, null); } + public void setCurrentFile(final int index, @Nullable final File file) { + mCurrentFile.setValue(Pair.create(index, file)); + } + /** * Get the opened file at the given index. * @@ -167,10 +128,6 @@ public class EditorViewModel extends ViewModel { return mCurrentFile.getValue().second; } - public void setCurrentFile(final int index, @Nullable final File file) { - mCurrentFile.setValue(Pair.create(index, file)); - } - public void setFilesModified(boolean modified) { this.mFilesModified.setValue(modified); } diff --git a/app/src/main/java/com/itsaky/androidide/views/editor/CodeEditorView.java b/app/src/main/java/com/itsaky/androidide/views/editor/CodeEditorView.java index 0263e0109..9abee6d85 100644 --- a/app/src/main/java/com/itsaky/androidide/views/editor/CodeEditorView.java +++ b/app/src/main/java/com/itsaky/androidide/views/editor/CodeEditorView.java @@ -62,11 +62,6 @@ import com.itsaky.androidide.utils.TypefaceUtils; import com.itsaky.inflater.values.ValuesTableFactory; import com.itsaky.lsp.models.Range; -import io.github.rosemoe.sora.event.ContentChangeEvent; -import io.github.rosemoe.sora.lang.EmptyLanguage; -import io.github.rosemoe.sora.text.Content; -import io.github.rosemoe.sora.widget.component.Magnifier; - import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.Token; @@ -78,6 +73,11 @@ import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; +import io.github.rosemoe.sora.event.ContentChangeEvent; +import io.github.rosemoe.sora.lang.EmptyLanguage; +import io.github.rosemoe.sora.text.Content; +import io.github.rosemoe.sora.widget.component.Magnifier; + /** * A view that handles opened code editors. * diff --git a/build-tools/tooling-api-impl/src/test/test-home/.androidide/init/model.jar b/build-tools/tooling-api-impl/src/test/test-home/.androidide/init/model.jar index 374ab99056a820bbc2f5e2db19264edc37bad21e..9269203824e1dc4170c52b90a335ea6a5a982a51 100644 GIT binary patch delta 35 rcmex&eE7M=iaW)?061`ZAe^+k<5TX`5a3NfiK+P+_i(LxLW!*dDV delta 35 rcmex&eE7M=iaW)?061`ZAeqnV97TX`5a3NabY+`eCk(LxLW!?_9K