mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
Resolved merge conflicts
This commit is contained in:
@@ -1,24 +1,24 @@
|
|||||||
name: Delete old workflow runs
|
name: Delete old workflow runs
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
days:
|
days:
|
||||||
description: 'Number of days.'
|
description: 'Number of days.'
|
||||||
required: true
|
required: true
|
||||||
default: 30
|
default: 30
|
||||||
minimum_runs:
|
minimum_runs:
|
||||||
description: 'The minimum runs to keep for each workflow.'
|
description: 'The minimum runs to keep for each workflow.'
|
||||||
required: true
|
required: true
|
||||||
default: 6
|
default: 6
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
del_runs:
|
del_runs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Delete workflow runs
|
- name: Delete workflow runs
|
||||||
uses: Mattraks/delete-workflow-runs@v2
|
uses: Mattraks/delete-workflow-runs@v2
|
||||||
with:
|
with:
|
||||||
token: ${{ github.token }}
|
token: ${{ github.token }}
|
||||||
repository: ${{ github.repository }}
|
repository: ${{ github.repository }}
|
||||||
retain_days: ${{ github.event.inputs.days }}
|
retain_days: ${{ github.event.inputs.days }}
|
||||||
keep_minimum_runs: ${{ github.event.inputs.minimum_runs }}
|
keep_minimum_runs: ${{ github.event.inputs.minimum_runs }}
|
||||||
Generated
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
<profile name="Gradle Imported" enabled="true">
|
<profile name="Gradle Imported" enabled="true">
|
||||||
<outputRelativeToContentRoot value="true" />
|
<outputRelativeToContentRoot value="true" />
|
||||||
<processorPath useClasspath="false">
|
<processorPath useClasspath="false">
|
||||||
<entry name="$PROJECT_DIR$/../../../itsaky/.gradle/caches/modules-2/files-2.1/com.google.auto.value/auto-value/1.9/fd4ec236e20ae0895c30e83260f611bcbc185086/auto-value-1.9.jar" />
|
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.auto.value/auto-value/1.9/fd4ec236e20ae0895c30e83260f611bcbc185086/auto-value-1.9.jar" />
|
||||||
</processorPath>
|
</processorPath>
|
||||||
<module name="AndroidIDE.build-tools.google-java-format.main" />
|
<module name="AndroidIDE.build-tools.google-java-format.main" />
|
||||||
</profile>
|
</profile>
|
||||||
|
|||||||
Generated
+17
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="deploymentTargetDropDown">
|
||||||
|
<runningDeviceTargetSelectedWithDropDown>
|
||||||
|
<Target>
|
||||||
|
<type value="RUNNING_DEVICE_TARGET" />
|
||||||
|
<deviceKey>
|
||||||
|
<Key>
|
||||||
|
<type value="SERIAL_NUMBER" />
|
||||||
|
<value value="b36e6c44" />
|
||||||
|
</Key>
|
||||||
|
</deviceKey>
|
||||||
|
</Target>
|
||||||
|
</runningDeviceTargetSelectedWithDropDown>
|
||||||
|
<timeTargetWasSelectedWithDropDown value="2022-06-05T02:50:58.945303Z" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="Encoding">
|
<component name="Encoding">
|
||||||
<file url="file://$PROJECT_DIR$/build-tools/google-java-format/src/main/java/com/google/googlejavaformat/java/StringWrapper.java" charset="UTF-8" />
|
<file url="file://$PROJECT_DIR$/build-tools/google-java-format/src/main/java/com/google/googlejavaformat/java/StringWrapper.java" charset="UTF-8" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Generated
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="GoogleJavaFormatSettings">
|
<component name="GoogleJavaFormatSettings">
|
||||||
<option name="enabled" value="true" />
|
<option name="enabled" value="true" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Generated
+5
@@ -61,5 +61,10 @@
|
|||||||
<option name="name" value="maven2" />
|
<option name="name" value="maven2" />
|
||||||
<option name="url" value="https://repo.eclipse.org/content/repositories/lemminx-snapshots/" />
|
<option name="url" value="https://repo.eclipse.org/content/repositories/lemminx-snapshots/" />
|
||||||
</remote-repository>
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="MavenLocal" />
|
||||||
|
<option name="name" value="MavenLocal" />
|
||||||
|
<option name="url" value="file:$USER_HOME$/.m2/repository" />
|
||||||
|
</remote-repository>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Generated
+6
-6
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="KtfmtSettings">
|
<component name="KtfmtSettings">
|
||||||
<option name="enabled" value="true" />
|
<option name="enabled" value="true" />
|
||||||
<option name="uiFormatterStyle" value="Dropbox" />
|
<option name="uiFormatterStyle" value="Dropbox" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
+179
-179
@@ -1,179 +1,179 @@
|
|||||||
# AndroidIDE Changelog
|
# AndroidIDE Changelog
|
||||||
This is the changelog of all the releases of AndroidIDE.
|
This is the changelog of all the releases of AndroidIDE.
|
||||||
|
|
||||||
## **v2.0.2-beta** (in development)
|
## **v2.0.2-beta** (in development)
|
||||||
|
|
||||||
### Important notes
|
### Important notes
|
||||||
<!--Breaking changes and other important stuff here-->
|
<!--Breaking changes and other important stuff here-->
|
||||||
|
|
||||||
### Additions
|
### Additions
|
||||||
- Warn about empty body for the following statements :
|
- Warn about empty body for the following statements :
|
||||||
- `if`
|
- `if`
|
||||||
- `else`
|
- `else`
|
||||||
- `try`
|
- `try`
|
||||||
- `catch`
|
- `catch`
|
||||||
- `finally`
|
- `finally`
|
||||||
- `for`
|
- `for`
|
||||||
- `while`
|
- `while`
|
||||||
- `do while`
|
- `do while`
|
||||||
- New java code actions :
|
- New java code actions :
|
||||||
- `Generate toString()`: Overrides the `toString()` method for the current class. Always accessible.
|
- `Generate toString()`: Overrides the `toString()` method for the current class. Always accessible.
|
||||||
- `Generate constructor`: Allows the user to select fields from the current class, then generates a constructor with those fields as parameters.
|
- `Generate constructor`: Allows the user to select fields from the current class, then generates a constructor with those fields as parameters.
|
||||||
- `Remove unused imports`: Removes imports that are not used in the source file.
|
- `Remove unused imports`: Removes imports that are not used in the source file.
|
||||||
- `Import orderer`: Organizes the imports. Thanks to @MrIkso (#180).
|
- `Import orderer`: Organizes the imports. Thanks to @MrIkso (#180).
|
||||||
- XML Code formatter. Thanks to @MrIkso (#180).
|
- XML Code formatter. Thanks to @MrIkso (#180).
|
||||||
- New Gradle command line options: `--build-cache` and `--offline`. Thanks to @MrIkso (#180).
|
- New Gradle command line options: `--build-cache` and `--offline`. Thanks to @MrIkso (#180).
|
||||||
- Highlight IDE logs based on the log line priority.
|
- Highlight IDE logs based on the log line priority.
|
||||||
- Added Brazilian Portuguese translations. Thanks to @Hakaisu (#165).
|
- Added Brazilian Portuguese translations. Thanks to @Hakaisu (#165).
|
||||||
|
|
||||||
### Removals
|
### Removals
|
||||||
<!--Things that were removed-->
|
<!--Things that were removed-->
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- Crash when performing 'Replace all' action in editor (#158).
|
- Crash when performing 'Replace all' action in editor (#158).
|
||||||
- Crash when layout inflation fails (#168).
|
- Crash when layout inflation fails (#168).
|
||||||
- Always show toasts on UI thread (#160).
|
- Always show toasts on UI thread (#160).
|
||||||
- Fixed: Multiline logs in IDE logs are not highlighted properly.
|
- Fixed: Multiline logs in IDE logs are not highlighted properly.
|
||||||
- Fixed: Invalid log line formatting when tag to too long.
|
- Fixed: Invalid log line formatting when tag to too long.
|
||||||
- Fixed: Application crashes when layout inflation fails (#168).
|
- Fixed: Application crashes when layout inflation fails (#168).
|
||||||
- Fixed: Invalid syntax highlighting for text tags in XML files. Thanks to @MrIkso (#180).
|
- Fixed: Invalid syntax highlighting for text tags in XML files. Thanks to @MrIkso (#180).
|
||||||
- Fixed: Extra empty `new line` gets appendend to files while saving.
|
- Fixed: Extra empty `new line` gets appendend to files while saving.
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
- Do not show 'Cut' & 'Paste' action if editor is not editable.
|
- Do not show 'Cut' & 'Paste' action if editor is not editable.
|
||||||
- Use [ported version of NetBeans' `nb-javac`](https://github.com/itsaky/nb-javac-android) for Java language server.
|
- Use [ported version of NetBeans' `nb-javac`](https://github.com/itsaky/nb-javac-android) for Java language server.
|
||||||
- Removed extra Maven repository URLs from project templates. Thanks to @MrIkso (#188).
|
- Removed extra Maven repository URLs from project templates. Thanks to @MrIkso (#188).
|
||||||
- Update dependency versions in project templates and update the Kotlin project template image. Thanks to @BanDroid (#191).
|
- Update dependency versions in project templates and update the Kotlin project template image. Thanks to @BanDroid (#191).
|
||||||
- Updated Hindi translations. Thanks to @Premjit-Chowdhury (#171).
|
- Updated Hindi translations. Thanks to @Premjit-Chowdhury (#171).
|
||||||
- Updated Russian translation. Thansk to @AndreyKozhev (#181).
|
- Updated Russian translation. Thansk to @AndreyKozhev (#181).
|
||||||
|
|
||||||
## **v2.0.1-beta**
|
## **v2.0.1-beta**
|
||||||
AndroidIDE v2.0.1-beta is here with new features, improvements and bug fixes.
|
AndroidIDE v2.0.1-beta is here with new features, improvements and bug fixes.
|
||||||
|
|
||||||
### Important notes
|
### Important notes
|
||||||
- As 64-bit installation does not work on Android 12 (due
|
- As 64-bit installation does not work on Android 12 (due
|
||||||
to [restriction by the OS](https://source.android.com/devices/tech/debug/tagged-pointers)), 32-bit
|
to [restriction by the OS](https://source.android.com/devices/tech/debug/tagged-pointers)), 32-bit
|
||||||
build tools need to be installed when installing AndroidIDE on devices running Android 12.
|
build tools need to be installed when installing AndroidIDE on devices running Android 12.
|
||||||
- Google services and Firebase integration has been removed.
|
- Google services and Firebase integration has been removed.
|
||||||
|
|
||||||
### Additions
|
### Additions
|
||||||
- Code formatter for Java source code.
|
- Code formatter for Java source code.
|
||||||
- Support for
|
- Support for
|
||||||
[`GestureOverlayView`](https://developer.android.com/reference/android/gesture/GestureOverlayView),
|
[`GestureOverlayView`](https://developer.android.com/reference/android/gesture/GestureOverlayView),
|
||||||
[`ToggleButton`](https://developer.android.com/reference/android/widget/ToggleButton),
|
[`ToggleButton`](https://developer.android.com/reference/android/widget/ToggleButton),
|
||||||
[`Switch`](https://developer.android.com/reference/android/widget/Switch),
|
[`Switch`](https://developer.android.com/reference/android/widget/Switch),
|
||||||
[`GridLayout`](https://developer.android.com/reference/android/widget/GridLayout),
|
[`GridLayout`](https://developer.android.com/reference/android/widget/GridLayout),
|
||||||
[`ListView`](https://developer.android.com/reference/android/widget/ListView) (#145) in layout
|
[`ListView`](https://developer.android.com/reference/android/widget/ListView) (#145) in layout
|
||||||
inflater.
|
inflater.
|
||||||
- Preference to disable use of `TYPE_TEXT_VARIATION_VISIBLE_PASSWORD` flag in editor.
|
- Preference to disable use of `TYPE_TEXT_VARIATION_VISIBLE_PASSWORD` flag in editor.
|
||||||
- Automatically trigger completion when attributes are inserted from completion window.
|
- Automatically trigger completion when attributes are inserted from completion window.
|
||||||
- New java code actions :
|
- New java code actions :
|
||||||
- Add import
|
- Add import
|
||||||
- Add 'throws'
|
- Add 'throws'
|
||||||
- Generate constructor
|
- Generate constructor
|
||||||
- Generate setters/getters
|
- Generate setters/getters
|
||||||
- Field to block
|
- Field to block
|
||||||
- Remove unused class
|
- Remove unused class
|
||||||
- Remove unused method
|
- Remove unused method
|
||||||
- Remove unused 'throws'
|
- Remove unused 'throws'
|
||||||
- You can now override multiple superclass methods at once.
|
- You can now override multiple superclass methods at once.
|
||||||
- `DocumentsProvider` for providing access to files in `HOME` directory.
|
- `DocumentsProvider` for providing access to files in `HOME` directory.
|
||||||
|
|
||||||
### Removals
|
### Removals
|
||||||
- Removed initial view attributes from view tags completion in XMLCompletionProvider.
|
- Removed initial view attributes from view tags completion in XMLCompletionProvider.
|
||||||
- Vertical text action window has been removed.
|
- Vertical text action window has been removed.
|
||||||
- Removed Google services and Firebase integration.
|
- Removed Google services and Firebase integration.
|
||||||
- Removed the horizontal text actions menu from the editor in favour of the new actions menu.
|
- Removed the horizontal text actions menu from the editor in favour of the new actions menu.
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- Cash in attribute editors when adding an attribute.
|
- Cash in attribute editors when adding an attribute.
|
||||||
- Crash when selecting diagnostic item from diagnostics list.
|
- Crash when selecting diagnostic item from diagnostics list.
|
||||||
- Some diagnostic items are not shown in diagnostic window (#96).
|
- Some diagnostic items are not shown in diagnostic window (#96).
|
||||||
- Diagnostics were updated late in the editor.
|
- Diagnostics were updated late in the editor.
|
||||||
- Popup windows created by editor are not dismissed even when the file is closed.
|
- Popup windows created by editor are not dismissed even when the file is closed.
|
||||||
- No build output when activity is recreated (#121).
|
- No build output when activity is recreated (#121).
|
||||||
- Crash in UI Designer when activity is recreated (#124).
|
- Crash in UI Designer when activity is recreated (#124).
|
||||||
- Invalid syntax highlighting for application logs (#152).
|
- Invalid syntax highlighting for application logs (#152).
|
||||||
- Illegal argument exception while overriding methods in Java completion provider.
|
- Illegal argument exception while overriding methods in Java completion provider.
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
- Do not import classes from `java.lang` package when completion items are selected.
|
- Do not import classes from `java.lang` package when completion items are selected.
|
||||||
- XML completion provider now uses 'Match completions in lower case' preference.
|
- XML completion provider now uses 'Match completions in lower case' preference.
|
||||||
- Dismiss all windows shown by editor when file tab is unselected or when the bottom sheet is
|
- Dismiss all windows shown by editor when file tab is unselected or when the bottom sheet is
|
||||||
expanded.
|
expanded.
|
||||||
- Improved the editor actions menu.
|
- Improved the editor actions menu.
|
||||||
- Sort completion items according to their kind and sort text.
|
- Sort completion items according to their kind and sort text.
|
||||||
- Restore file tree state when application is resumed (#150).
|
- Restore file tree state when application is resumed (#150).
|
||||||
- Updated templates to work with Android 12 (#144).
|
- Updated templates to work with Android 12 (#144).
|
||||||
- Updated Chinese translation. Thanks to @mikofe (#128).
|
- Updated Chinese translation. Thanks to @mikofe (#128).
|
||||||
- Updated French translation. Thanks to @Se-Lyan (#136).
|
- Updated French translation. Thanks to @Se-Lyan (#136).
|
||||||
- Updated German translation (#144).
|
- Updated German translation (#144).
|
||||||
|
|
||||||
## **v2.0.0-beta**
|
## **v2.0.0-beta**
|
||||||
|
|
||||||
AndroidIDE v2.0.0-beta is here with new features and improvements.
|
AndroidIDE v2.0.0-beta is here with new features and improvements.
|
||||||
|
|
||||||
### Important Notes
|
### Important Notes
|
||||||
|
|
||||||
- This is a pre-release and is not so stable. There are some features that are partially
|
- This is a pre-release and is not so stable. There are some features that are partially
|
||||||
implemented.
|
implemented.
|
||||||
- The minimum SDK has been raised to `26` (`Android O`).
|
- The minimum SDK has been raised to `26` (`Android O`).
|
||||||
|
|
||||||
### Additions
|
### Additions
|
||||||
|
|
||||||
- XML Layout Designer with ability to preview XML drawables.
|
- XML Layout Designer with ability to preview XML drawables.
|
||||||
- Added packages for terminal.
|
- Added packages for terminal.
|
||||||
- libGDx project template. Thanks to @Smooth-E (#81).
|
- libGDx project template. Thanks to @Smooth-E (#81).
|
||||||
- Kotlin project template. Thanks to @BanDroid (#60).
|
- Kotlin project template. Thanks to @BanDroid (#60).
|
||||||
- Preference to switch between `bash` and `/system/bin/sh` in terminal.
|
- Preference to switch between `bash` and `/system/bin/sh` in terminal.
|
||||||
- Preference for matching partial names in java completion.
|
- Preference for matching partial names in java completion.
|
||||||
- Preference to choose between `floating window text actions` and `text actions in ActionMode`.
|
- Preference to choose between `floating window text actions` and `text actions in ActionMode`.
|
||||||
- Preference to enable/disable font ligatures.
|
- Preference to enable/disable font ligatures.
|
||||||
- Show process output when build tools installation fails.
|
- Show process output when build tools installation fails.
|
||||||
- Ability to expand selection in supported languages.
|
- Ability to expand selection in supported languages.
|
||||||
- Ask user to save unsaved files before closing project.
|
- Ask user to save unsaved files before closing project.
|
||||||
- Hindi translation. Thanks to @Premjit-Chowdhury (#70, #127).
|
- Hindi translation. Thanks to @Premjit-Chowdhury (#70, #127).
|
||||||
- German translation. Thanks to @MarvinStelter.
|
- German translation. Thanks to @MarvinStelter.
|
||||||
- Indonesian translation. Thanks to @BanDroid (#54, #57, #60, #72, #125).
|
- Indonesian translation. Thanks to @BanDroid (#54, #57, #60, #72, #125).
|
||||||
- Chinese translation. Thanks to @Rosemoe (#56, #73, #104) and @mikofe (#118, #119, #123).
|
- Chinese translation. Thanks to @Rosemoe (#56, #73, #104) and @mikofe (#118, #119, #123).
|
||||||
- French translation. Thanks to @Se-Lyan (#79).
|
- French translation. Thanks to @Se-Lyan (#79).
|
||||||
- Russian translation. Thanks to @Smooth-E (#97).
|
- Russian translation. Thanks to @Smooth-E (#97).
|
||||||
|
|
||||||
### Removals
|
### Removals
|
||||||
|
|
||||||
- Autosave of files is removed. However, a preference has been added for the same which, when
|
- Autosave of files is removed. However, a preference has been added for the same which, when
|
||||||
enabled, saves the files automatically before close.
|
enabled, saves the files automatically before close.
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
||||||
- File does not close and crashes if reopened and closed again.
|
- File does not close and crashes if reopened and closed again.
|
||||||
- Flickering of whole auto completion window.
|
- Flickering of whole auto completion window.
|
||||||
- Flickering of completion item due to API info.
|
- Flickering of completion item due to API info.
|
||||||
- Build tools installation fails if `JAVA_HOME` does not exist.
|
- Build tools installation fails if `JAVA_HOME` does not exist.
|
||||||
- Invalid syntax highlight for method invocations in java.
|
- Invalid syntax highlight for method invocations in java.
|
||||||
- Package private classes not included in java completion.
|
- Package private classes not included in java completion.
|
||||||
- IDE crashes when `Paste` option is selected in terminal and no clip is available.
|
- IDE crashes when `Paste` option is selected in terminal and no clip is available.
|
||||||
- Fixed a bug due to which the IDE was not able to open empty files.
|
- Fixed a bug due to which the IDE was not able to open empty files.
|
||||||
- `LogSender` class not included in JLS workspace.
|
- `LogSender` class not included in JLS workspace.
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|
||||||
- Show crash report when the IDE crashes.
|
- Show crash report when the IDE crashes.
|
||||||
- The Java language server is now embedded in the IDE itself.
|
- The Java language server is now embedded in the IDE itself.
|
||||||
- The AndroidIDE Gradle plugin is now packaged with the IDE.
|
- The AndroidIDE Gradle plugin is now packaged with the IDE.
|
||||||
- Show name of opened project.
|
- Show name of opened project.
|
||||||
- Show signature help in window instead of using a `TextView`.
|
- Show signature help in window instead of using a `TextView`.
|
||||||
- The java completion provider now uses a custom JDK runtime image with Android framework classes
|
- The java completion provider now uses a custom JDK runtime image with Android framework classes
|
||||||
and is no more dependent on JDK installation.
|
and is no more dependent on JDK installation.
|
||||||
- Disable `Save` option when all files are saved.
|
- Disable `Save` option when all files are saved.
|
||||||
- Allow installation of files from file tree.
|
- Allow installation of files from file tree.
|
||||||
|
|
||||||
### New Contributors
|
### New Contributors
|
||||||
|
|
||||||
* @BanDroid
|
* @BanDroid
|
||||||
* @Rosemoe
|
* @Rosemoe
|
||||||
* @Premjit-Chowdhury
|
* @Premjit-Chowdhury
|
||||||
* @Se-Lyan
|
* @Se-Lyan
|
||||||
* @Smooth-E
|
* @Smooth-E
|
||||||
* @ansh2166
|
* @ansh2166
|
||||||
* @mikofe
|
* @mikofe
|
||||||
|
|||||||
+27
-27
@@ -1,28 +1,28 @@
|
|||||||
# Contributing
|
# Contributing
|
||||||
This document outlines how to propose a change to AndrodIDE. By contributing to this project, you agree to abide the terms specified in [CODE OF CONDUCT](./CODE_OF_CONDUCT.md).
|
This document outlines how to propose a change to AndrodIDE. By contributing to this project, you agree to abide the terms specified in [CODE OF CONDUCT](./CODE_OF_CONDUCT.md).
|
||||||
|
|
||||||
## Propose a change
|
## Propose a change
|
||||||
To contribute to this project,
|
To contribute to this project,
|
||||||
- Fork the repo.
|
- Fork the repo.
|
||||||
- Clone the forked repo to your local machine.
|
- Clone the forked repo to your local machine.
|
||||||
- Open the project in Android Studio.
|
- Open the project in Android Studio.
|
||||||
- Make your changes.
|
- Make your changes.
|
||||||
- Create a pull request.
|
- Create a pull request.
|
||||||
|
|
||||||
## Note
|
## Note
|
||||||
`Java 11` is required to build the project.
|
`Java 11` is required to build the project.
|
||||||
|
|
||||||
Building AndroidIDE in AndroidIDE itself is also possible. But that might require some modifications.
|
Building AndroidIDE in AndroidIDE itself is also possible. But that might require some modifications.
|
||||||
|
|
||||||
If you face `AAPT2` issue while building AndroidIDE in the IDE itself, specify the `android.aapt2FromMavenOverride` property in `gradle.properties` with location of `aapt2` binary from Android SDK. However, this is an **experimental** property.
|
If you face `AAPT2` issue while building AndroidIDE in the IDE itself, specify the `android.aapt2FromMavenOverride` property in `gradle.properties` with location of `aapt2` binary from Android SDK. However, this is an **experimental** property.
|
||||||
|
|
||||||
## Source code format
|
## Source code format
|
||||||
The source code must have `2-space` indentation (soft tab).
|
The source code must have `2-space` indentation (soft tab).
|
||||||
Java source code is formatted using `google-java-format` with `GOOGLE` style formatting.
|
Java source code is formatted using `google-java-format` with `GOOGLE` style formatting.
|
||||||
You can execute `./gradlew formatJavaSources` in terminal to format all Java source files using Google Java Format.
|
You can execute `./gradlew formatJavaSources` in terminal to format all Java source files using Google Java Format.
|
||||||
**This will commit the changes as well**.
|
**This will commit the changes as well**.
|
||||||
|
|
||||||
## Issues & Pull requests
|
## Issues & Pull requests
|
||||||
Use the issue/PR templates when possible. Provide a proper title and a clear description for the issue/PR. For bug reports, provide a step-by-step procedure to reproduce the issue. Always put crash logs, build outputs, etc in `code blocks`.
|
Use the issue/PR templates when possible. Provide a proper title and a clear description for the issue/PR. For bug reports, provide a step-by-step procedure to reproduce the issue. Always put crash logs, build outputs, etc in `code blocks`.
|
||||||
|
|
||||||
If you want to discuss anything about the project, you can discuss it in the [Telegram group](https://t.me/androidide_discussions).
|
If you want to discuss anything about the project, you can discuss it in the [Telegram group](https://t.me/androidide_discussions).
|
||||||
+37
-37
@@ -1,37 +1,37 @@
|
|||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion rootProject.ext.compileSdk
|
compileSdkVersion rootProject.ext.compileSdk
|
||||||
buildToolsVersion rootProject.ext.buildTools
|
buildToolsVersion rootProject.ext.buildTools
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion rootProject.ext.minSdk
|
minSdkVersion rootProject.ext.minSdk
|
||||||
targetSdkVersion rootProject.ext.targetSdk
|
targetSdkVersion rootProject.ext.targetSdk
|
||||||
}
|
}
|
||||||
|
|
||||||
buildFeatures.viewBinding true
|
buildFeatures.viewBinding true
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility rootProject.ext.javaSourceVersion
|
sourceCompatibility rootProject.ext.javaSourceVersion
|
||||||
targetCompatibility rootProject.ext.javaTargetVersion
|
targetCompatibility rootProject.ext.javaTargetVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':common')
|
implementation project(':common')
|
||||||
implementation common.editor
|
implementation common.editor
|
||||||
implementation common.utilcode
|
implementation common.utilcode
|
||||||
|
|
||||||
implementation "androidx.core:core-ktx:1.7.0"
|
implementation "androidx.core:core-ktx:1.7.0"
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?><!--
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
~ This file is part of AndroidIDE.
|
~ This file is part of AndroidIDE.
|
||||||
~
|
~
|
||||||
~ AndroidIDE is free software: you can redistribute it and/or modify
|
~ AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
~ it under the terms of the GNU General Public License as published by
|
~ it under the terms of the GNU General Public License as published by
|
||||||
~ the Free Software Foundation, either version 3 of the License, or
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
~ (at your option) any later version.
|
~ (at your option) any later version.
|
||||||
~
|
~
|
||||||
~ AndroidIDE is distributed in the hope that it will be useful,
|
~ AndroidIDE is distributed in the hope that it will be useful,
|
||||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
~ GNU General Public License for more details.
|
~ GNU General Public License for more details.
|
||||||
~
|
~
|
||||||
~ You should have received a copy of the GNU General Public License
|
~ You should have received a copy of the GNU General Public License
|
||||||
~ along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
~ along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
<manifest package="com.itsaky.androidide.actions" />
|
<manifest package="com.itsaky.androidide.actions" />
|
||||||
@@ -1,54 +1,54 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions;
|
package com.itsaky.androidide.actions;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
public class ActionData {
|
public class ActionData {
|
||||||
|
|
||||||
private final Map<Class<?>, Object> instances = new HashMap<>();
|
private final Map<Class<?>, Object> instances = new HashMap<>();
|
||||||
|
|
||||||
public <T> void put(@NonNull Class<T> type, @Nullable T object) {
|
public <T> void put(@NonNull Class<T> type, @Nullable T object) {
|
||||||
Objects.requireNonNull(type);
|
Objects.requireNonNull(type);
|
||||||
this.instances.put(type, object);
|
this.instances.put(type, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public <T> T get(@NonNull Class<T> type) {
|
public <T> T get(@NonNull Class<T> type) {
|
||||||
Objects.requireNonNull(type);
|
Objects.requireNonNull(type);
|
||||||
|
|
||||||
final var object = this.instances.get(type);
|
final var object = this.instances.get(type);
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type.cast(object);
|
return type.cast(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
this.instances.clear();
|
this.instances.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,113 +1,113 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions
|
package com.itsaky.androidide.actions
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An action that can be registered using the [ActionsRegistry]
|
* An action that can be registered using the [ActionsRegistry]
|
||||||
* [com.itsaky.androidide.actions.ActionsRegistry]
|
* [com.itsaky.androidide.actions.ActionsRegistry]
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
interface ActionItem {
|
interface ActionItem {
|
||||||
|
|
||||||
val id: String
|
val id: String
|
||||||
var label: String
|
var label: String
|
||||||
var visible: Boolean
|
var visible: Boolean
|
||||||
var enabled: Boolean
|
var enabled: Boolean
|
||||||
var icon: Drawable?
|
var icon: Drawable?
|
||||||
var requiresUIThread: Boolean
|
var requiresUIThread: Boolean
|
||||||
var location: Location
|
var location: Location
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare the action. Subclasses can modify the visual properties of this action here.
|
* Prepare the action. Subclasses can modify the visual properties of this action here.
|
||||||
* @param data The data containing various information about the event.
|
* @param data The data containing various information about the event.
|
||||||
*/
|
*/
|
||||||
fun prepare(data: ActionData)
|
fun prepare(data: ActionData)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the action. The action executed in a background thread by default.
|
* Execute the action. The action executed in a background thread by default.
|
||||||
*
|
*
|
||||||
* @param data The data containing various information about the event.
|
* @param data The data containing various information about the event.
|
||||||
* @return `true` if this action was executed successfully, `false` otherwise.
|
* @return `true` if this action was executed successfully, `false` otherwise.
|
||||||
*/
|
*/
|
||||||
fun execAction(data: ActionData): Any
|
fun execAction(data: ActionData): Any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called just after the [execAction] method executes **successfully** (i.e. returns `true`).
|
* Called just after the [execAction] method executes **successfully** (i.e. returns `true`).
|
||||||
* Subclasses are free to do UI related work here as this method is called on UI thread.
|
* Subclasses are free to do UI related work here as this method is called on UI thread.
|
||||||
*
|
*
|
||||||
* @param data The data containing various information about the event.
|
* @param data The data containing various information about the event.
|
||||||
*/
|
*/
|
||||||
fun postExec(data: ActionData, result: Any) = Unit
|
fun postExec(data: ActionData, result: Any) = Unit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the show as action flags for the menu item.
|
* Return the show as action flags for the menu item.
|
||||||
*
|
*
|
||||||
* @return The show as action flags.
|
* @return The show as action flags.
|
||||||
*/
|
*/
|
||||||
fun getShowAsActionFlags(data: ActionData): Int = -1
|
fun getShowAsActionFlags(data: ActionData): Int = -1
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given [ActionData] has instances of the given [types].
|
* Checks if the given [ActionData] has instances of the given [types].
|
||||||
*
|
*
|
||||||
* @param data The data to check.
|
* @param data The data to check.
|
||||||
* @param types The type of objects to look for.
|
* @param types The type of objects to look for.
|
||||||
* @return `true` if the [data] has the given [types], `false` otherwise.
|
* @return `true` if the [data] has the given [types], `false` otherwise.
|
||||||
*/
|
*/
|
||||||
fun hasRequiredData(data: ActionData, vararg types: Class<*>): Boolean {
|
fun hasRequiredData(data: ActionData, vararg types: Class<*>): Boolean {
|
||||||
for (type in types) {
|
for (type in types) {
|
||||||
data.get(type) ?: return false
|
data.get(type) ?: return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Marks this action item as invisible. */
|
/** Marks this action item as invisible. */
|
||||||
fun markInvisible() {
|
fun markInvisible() {
|
||||||
visible = false
|
visible = false
|
||||||
enabled = false
|
enabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Location where an action item will be shown. */
|
/** Location where an action item will be shown. */
|
||||||
enum class Location(val id: String) {
|
enum class Location(val id: String) {
|
||||||
|
|
||||||
/** Location marker for action items shown in editor activity's toolbar. */
|
/** Location marker for action items shown in editor activity's toolbar. */
|
||||||
EDITOR_TOOLBAR("editor.activity.toolbar"),
|
EDITOR_TOOLBAR("editor.activity.toolbar"),
|
||||||
|
|
||||||
/** Location marker for action items shown in editor's text action menu. */
|
/** Location marker for action items shown in editor's text action menu. */
|
||||||
EDITOR_TEXT_ACTIONS("editor.textActions"),
|
EDITOR_TEXT_ACTIONS("editor.textActions"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Location marker for action items shown in 'Code actions' submenu in editor's text action
|
* Location marker for action items shown in 'Code actions' submenu in editor's text action
|
||||||
* menu.
|
* menu.
|
||||||
*/
|
*/
|
||||||
EDITOR_CODE_ACTIONS("editor.codeActions"),
|
EDITOR_CODE_ACTIONS("editor.codeActions"),
|
||||||
|
|
||||||
/** Location marker for action items show in 'Find & Replace' action mode menu in editor. */
|
/** Location marker for action items show in 'Find & Replace' action mode menu in editor. */
|
||||||
EDITOR_SEARCH_ACTION_MODE("editor.searchActionMode");
|
EDITOR_SEARCH_ACTION_MODE("editor.searchActionMode");
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
fun forId(id: String): Location {
|
fun forId(id: String): Location {
|
||||||
return values().first { it.id == id }
|
return values().first { it.id == id }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,36 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions
|
package com.itsaky.androidide.actions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An action menu is an action which can contain child actions.
|
* An action menu is an action which can contain child actions.
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
interface ActionMenu : ActionItem {
|
interface ActionMenu : ActionItem {
|
||||||
|
|
||||||
val children: MutableSet<ActionItem>
|
val children: MutableSet<ActionItem>
|
||||||
|
|
||||||
fun addAction(action: ActionItem) = children.add(action)
|
fun addAction(action: ActionItem) = children.add(action)
|
||||||
|
|
||||||
fun removeAction(action: ActionItem) = children.remove(action)
|
fun removeAction(action: ActionItem) = children.remove(action)
|
||||||
|
|
||||||
/** Action menus are not supposed to perform any action */
|
/** Action menus are not supposed to perform any action */
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,108 +1,108 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.actions
|
package com.itsaky.androidide.actions
|
||||||
|
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import com.itsaky.androidide.actions.internal.DefaultActionsRegistry
|
import com.itsaky.androidide.actions.internal.DefaultActionsRegistry
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
abstract class ActionsRegistry {
|
abstract class ActionsRegistry {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private var instance: ActionsRegistry? = null
|
private var instance: ActionsRegistry? = null
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getInstance(): ActionsRegistry {
|
fun getInstance(): ActionsRegistry {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
instance = DefaultActionsRegistry()
|
instance = DefaultActionsRegistry()
|
||||||
}
|
}
|
||||||
|
|
||||||
return instance as ActionsRegistry
|
return instance as ActionsRegistry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the given action.
|
* Register the given action.
|
||||||
*
|
*
|
||||||
* @param action The action to register. Must not be `null`.
|
* @param action The action to register. Must not be `null`.
|
||||||
* @return `true` if the action was registered successfully. `false` otherwise.
|
* @return `true` if the action was registered successfully. `false` otherwise.
|
||||||
*/
|
*/
|
||||||
abstract fun registerAction(action: ActionItem): Boolean
|
abstract fun registerAction(action: ActionItem): Boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregister the given action.
|
* Unregister the given action.
|
||||||
*
|
*
|
||||||
* @param action The action to unregister. Must not be `null`.
|
* @param action The action to unregister. Must not be `null`.
|
||||||
* @return `true` if the action was unregistered successfully. `false` otherwise.
|
* @return `true` if the action was unregistered successfully. `false` otherwise.
|
||||||
*/
|
*/
|
||||||
abstract fun unregisterAction(action: ActionItem): Boolean
|
abstract fun unregisterAction(action: ActionItem): Boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregister the action with the given ID.
|
* Unregister the action with the given ID.
|
||||||
*
|
*
|
||||||
* @param id The ID of action to unregister. Must not be `null`.
|
* @param id The ID of action to unregister. Must not be `null`.
|
||||||
* @return `true` if the action was unregistered successfully. `false` otherwise.
|
* @return `true` if the action was unregistered successfully. `false` otherwise.
|
||||||
*/
|
*/
|
||||||
abstract fun unregisterAction(id: String): Boolean
|
abstract fun unregisterAction(id: String): Boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the action with the given ID.
|
* Find the action with the given ID.
|
||||||
*
|
*
|
||||||
* @param id The ID of the action to find.
|
* @param id The ID of the action to find.
|
||||||
* @return The found action or `null`.
|
* @return The found action or `null`.
|
||||||
*/
|
*/
|
||||||
abstract fun findAction(location: ActionItem.Location, id: String): ActionItem?
|
abstract fun findAction(location: ActionItem.Location, id: String): ActionItem?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill the given menu with the registered actions.
|
* Fill the given menu with the registered actions.
|
||||||
*
|
*
|
||||||
* Subclasses must first call [ActionItem.prepare] to update the action.
|
* Subclasses must first call [ActionItem.prepare] to update the action.
|
||||||
*/
|
*/
|
||||||
abstract fun fillMenu(data: ActionData, location: ActionItem.Location, menu: Menu)
|
abstract fun fillMenu(data: ActionData, location: ActionItem.Location, menu: Menu)
|
||||||
|
|
||||||
/** Get all the registered actions at the given location. */
|
/** Get all the registered actions at the given location. */
|
||||||
abstract fun getActions(location: ActionItem.Location): Map<String, ActionItem>
|
abstract fun getActions(location: ActionItem.Location): Map<String, ActionItem>
|
||||||
/** Clear all the registered actions. */
|
/** Clear all the registered actions. */
|
||||||
abstract fun clearActions(location: ActionItem.Location)
|
abstract fun clearActions(location: ActionItem.Location)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a listener that will be called when any action is executed. The callbacks are called
|
* Register a listener that will be called when any action is executed. The callbacks are called
|
||||||
* irrespective of the action's execution result.
|
* irrespective of the action's execution result.
|
||||||
*
|
*
|
||||||
* @param listener The listener to register.
|
* @param listener The listener to register.
|
||||||
*/
|
*/
|
||||||
abstract fun registerActionExecListener(listener: ActionExecListener)
|
abstract fun registerActionExecListener(listener: ActionExecListener)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregister the given listener.
|
* Unregister the given listener.
|
||||||
*
|
*
|
||||||
* @param listener The listener to unregister.
|
* @param listener The listener to unregister.
|
||||||
*/
|
*/
|
||||||
abstract fun unregisterActionExecListener(listener: ActionExecListener)
|
abstract fun unregisterActionExecListener(listener: ActionExecListener)
|
||||||
|
|
||||||
/** Listener for listening to callbacks for action execution. */
|
/** Listener for listening to callbacks for action execution. */
|
||||||
interface ActionExecListener {
|
interface ActionExecListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The given action was executed.
|
* The given action was executed.
|
||||||
* @param action The action that was executed.
|
* @param action The action that was executed.
|
||||||
* @param result The result of the action execution.
|
* @param result The result of the action execution.
|
||||||
*/
|
*/
|
||||||
fun onExec(action: ActionItem, result: Any)
|
fun onExec(action: ActionItem, result: Any)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+174
-174
@@ -1,174 +1,174 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.actions.internal
|
package com.itsaky.androidide.actions.internal
|
||||||
|
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import com.blankj.utilcode.util.ThreadUtils
|
import com.blankj.utilcode.util.ThreadUtils
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.ActionItem
|
import com.itsaky.androidide.actions.ActionItem
|
||||||
import com.itsaky.androidide.actions.ActionMenu
|
import com.itsaky.androidide.actions.ActionMenu
|
||||||
import com.itsaky.androidide.actions.ActionsRegistry
|
import com.itsaky.androidide.actions.ActionsRegistry
|
||||||
import com.itsaky.androidide.utils.ILogger
|
import com.itsaky.androidide.utils.ILogger
|
||||||
import java.util.concurrent.*
|
import java.util.concurrent.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation for the [ActionsRegistry]
|
* Default implementation for the [ActionsRegistry]
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
class DefaultActionsRegistry : ActionsRegistry() {
|
class DefaultActionsRegistry : ActionsRegistry() {
|
||||||
|
|
||||||
private val log = ILogger.newInstance("DefaultActionsRegistry")
|
private val log = ILogger.newInstance("DefaultActionsRegistry")
|
||||||
private val actions: MutableMap<String, MutableMap<String, ActionItem>> = mutableMapOf()
|
private val actions: MutableMap<String, MutableMap<String, ActionItem>> = mutableMapOf()
|
||||||
private val listeners = mutableSetOf<ActionExecListener>()
|
private val listeners = mutableSetOf<ActionExecListener>()
|
||||||
|
|
||||||
override fun getActions(location: ActionItem.Location): MutableMap<String, ActionItem> {
|
override fun getActions(location: ActionItem.Location): MutableMap<String, ActionItem> {
|
||||||
if (actions[location.id] == null) {
|
if (actions[location.id] == null) {
|
||||||
actions[location.id] = mutableMapOf()
|
actions[location.id] = mutableMapOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions[location.id]!!
|
return actions[location.id]!!
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun registerAction(action: ActionItem): Boolean {
|
override fun registerAction(action: ActionItem): Boolean {
|
||||||
val actionsAtLocation = getActions(action.location)
|
val actionsAtLocation = getActions(action.location)
|
||||||
actionsAtLocation[action.id] = action
|
actionsAtLocation[action.id] = action
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun unregisterAction(action: ActionItem): Boolean {
|
override fun unregisterAction(action: ActionItem): Boolean {
|
||||||
val actions = getActions(action.location)
|
val actions = getActions(action.location)
|
||||||
val older = actions.remove(action.id)
|
val older = actions.remove(action.id)
|
||||||
if (older != null) {
|
if (older != null) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun unregisterAction(id: String): Boolean {
|
override fun unregisterAction(id: String): Boolean {
|
||||||
for (locations in this.actions.values) {
|
for (locations in this.actions.values) {
|
||||||
val older = locations.remove(id)
|
val older = locations.remove(id)
|
||||||
if (older != null) {
|
if (older != null) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun findAction(location: ActionItem.Location, id: String): ActionItem? =
|
override fun findAction(location: ActionItem.Location, id: String): ActionItem? =
|
||||||
getActions(location)[id]
|
getActions(location)[id]
|
||||||
|
|
||||||
override fun clearActions(location: ActionItem.Location) = getActions(location).clear()
|
override fun clearActions(location: ActionItem.Location) = getActions(location).clear()
|
||||||
|
|
||||||
override fun registerActionExecListener(listener: ActionExecListener) {
|
override fun registerActionExecListener(listener: ActionExecListener) {
|
||||||
listeners.add(listener)
|
listeners.add(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun unregisterActionExecListener(listener: ActionExecListener) {
|
override fun unregisterActionExecListener(listener: ActionExecListener) {
|
||||||
listeners.remove(listener)
|
listeners.remove(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fillMenu(data: ActionData, location: ActionItem.Location, menu: Menu) {
|
override fun fillMenu(data: ActionData, location: ActionItem.Location, menu: Menu) {
|
||||||
val actions = getActions(location)
|
val actions = getActions(location)
|
||||||
|
|
||||||
for (action in actions.values) {
|
for (action in actions.values) {
|
||||||
action.prepare(data)
|
action.prepare(data)
|
||||||
|
|
||||||
if (!action.visible) {
|
if (!action.visible) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
addActionToMenu(menu, action, data)
|
addActionToMenu(menu, action, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addActionToMenu(menu: Menu, action: ActionItem, data: ActionData) {
|
private fun addActionToMenu(menu: Menu, action: ActionItem, data: ActionData) {
|
||||||
val item: MenuItem =
|
val item: MenuItem =
|
||||||
if (action is ActionMenu) {
|
if (action is ActionMenu) {
|
||||||
val sub = menu.addSubMenu(action.label)
|
val sub = menu.addSubMenu(action.label)
|
||||||
|
|
||||||
for (subItem in action.children) {
|
for (subItem in action.children) {
|
||||||
subItem.prepare(data)
|
subItem.prepare(data)
|
||||||
if (subItem.visible) {
|
if (subItem.visible) {
|
||||||
addActionToMenu(sub, subItem, data)
|
addActionToMenu(sub, subItem, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub.item
|
sub.item
|
||||||
} else {
|
} else {
|
||||||
menu.add(action.label)
|
menu.add(action.label)
|
||||||
}
|
}
|
||||||
|
|
||||||
item.isEnabled = action.enabled
|
item.isEnabled = action.enabled
|
||||||
item.icon = action.icon
|
item.icon = action.icon
|
||||||
|
|
||||||
if (item.icon != null) {
|
if (item.icon != null) {
|
||||||
item.icon.alpha = if (action.enabled) 255 else 76
|
item.icon.alpha = if (action.enabled) 255 else 76
|
||||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
|
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
|
||||||
} else {
|
} else {
|
||||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
|
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.getShowAsActionFlags(data) != -1) {
|
if (action.getShowAsActionFlags(data) != -1) {
|
||||||
item.setShowAsAction(action.getShowAsActionFlags(data))
|
item.setShowAsAction(action.getShowAsActionFlags(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action !is ActionMenu) {
|
if (action !is ActionMenu) {
|
||||||
item.setOnMenuItemClickListener {
|
item.setOnMenuItemClickListener {
|
||||||
if (action.requiresUIThread) {
|
if (action.requiresUIThread) {
|
||||||
ThreadUtils.runOnUiThread {
|
ThreadUtils.runOnUiThread {
|
||||||
val result = action.execAction(data)
|
val result = action.execAction(data)
|
||||||
action.postExec(data, result)
|
action.postExec(data, result)
|
||||||
notifyActionExec(action, result)
|
notifyActionExec(action, result)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
execInBackground(action, data, it)
|
execInBackground(action, data, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun execInBackground(action: ActionItem, data: ActionData, it: MenuItem) {
|
private fun execInBackground(action: ActionItem, data: ActionData, it: MenuItem) {
|
||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
CompletableFuture.supplyAsync { action.execAction(data) }
|
CompletableFuture.supplyAsync { action.execAction(data) }
|
||||||
.whenComplete { result, error ->
|
.whenComplete { result, error ->
|
||||||
if (result == null || (result is Boolean && !result) || error != null) {
|
if (result == null || (result is Boolean && !result) || error != null) {
|
||||||
log.error(
|
log.error(
|
||||||
"An error occurred when performing action '${it.title}'. Action failed in ${System.currentTimeMillis() - start}ms",
|
"An error occurred when performing action '${it.title}'. Action failed in ${System.currentTimeMillis() - start}ms",
|
||||||
error)
|
error)
|
||||||
} else {
|
} else {
|
||||||
log.info(
|
log.info(
|
||||||
"Action '${it.title}' completed in ${System.currentTimeMillis() - start}ms")
|
"Action '${it.title}' completed in ${System.currentTimeMillis() - start}ms")
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadUtils.runOnUiThread {
|
ThreadUtils.runOnUiThread {
|
||||||
action.postExec(data, result ?: false)
|
action.postExec(data, result ?: false)
|
||||||
notifyActionExec(action, result ?: false)
|
notifyActionExec(action, result ?: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun notifyActionExec(action: ActionItem, result: Any) {
|
private fun notifyActionExec(action: ActionItem, result: Any) {
|
||||||
for (listener in listeners) {
|
for (listener in listeners) {
|
||||||
listener.onExec(action, result)
|
listener.onExec(action, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+143
-143
@@ -1,144 +1,144 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion rootProject.ext.compileSdk
|
compileSdkVersion rootProject.ext.compileSdk
|
||||||
buildToolsVersion rootProject.ext.buildTools
|
buildToolsVersion rootProject.ext.buildTools
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId rootProject.ext.packageName
|
applicationId rootProject.ext.packageName
|
||||||
minSdkVersion rootProject.ext.minSdk
|
minSdkVersion rootProject.ext.minSdk
|
||||||
targetSdkVersion rootProject.ext.targetSdk
|
targetSdkVersion rootProject.ext.targetSdk
|
||||||
versionCode rootProject.ext.versionCode
|
versionCode rootProject.ext.versionCode
|
||||||
versionName rootProject.ext.versionName
|
versionName rootProject.ext.versionName
|
||||||
|
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
coreLibraryDesugaringEnabled true
|
coreLibraryDesugaringEnabled true
|
||||||
sourceCompatibility rootProject.ext.javaSourceVersion
|
sourceCompatibility rootProject.ext.javaSourceVersion
|
||||||
targetCompatibility rootProject.ext.javaTargetVersion
|
targetCompatibility rootProject.ext.javaTargetVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "11"
|
jvmTarget = "11"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding true
|
viewBinding true
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
|
|
||||||
debug {
|
debug {
|
||||||
storeFile file ("dev.keystore")
|
storeFile file ("dev.keystore")
|
||||||
keyAlias "androidide"
|
keyAlias "androidide"
|
||||||
storePassword "ed68424fb109e5aa8146e4b86caa72e3"
|
storePassword "ed68424fb109e5aa8146e4b86caa72e3"
|
||||||
keyPassword "ed68424fb109e5aa8146e4b86caa72e3"
|
keyPassword "ed68424fb109e5aa8146e4b86caa72e3"
|
||||||
}
|
}
|
||||||
|
|
||||||
release {
|
release {
|
||||||
storeFile file ("dev.keystore")
|
storeFile file ("dev.keystore")
|
||||||
keyAlias "androidide"
|
keyAlias "androidide"
|
||||||
storePassword "ed68424fb109e5aa8146e4b86caa72e3"
|
storePassword "ed68424fb109e5aa8146e4b86caa72e3"
|
||||||
keyPassword "ed68424fb109e5aa8146e4b86caa72e3"
|
keyPassword "ed68424fb109e5aa8146e4b86caa72e3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile ('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile ('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
signingConfig signingConfigs.debug
|
signingConfig signingConfigs.debug
|
||||||
}
|
}
|
||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
shrinkResources true
|
shrinkResources true
|
||||||
proguardFiles getDefaultProguardFile ('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile ('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
resources {
|
resources {
|
||||||
excludes += ['META-INF/eclipse.inf',
|
excludes += ['META-INF/eclipse.inf',
|
||||||
'META-INF/CHANGES',
|
'META-INF/CHANGES',
|
||||||
'META-INF/README.md',
|
'META-INF/README.md',
|
||||||
'about_files/LICENSE-2.0.txt',
|
'about_files/LICENSE-2.0.txt',
|
||||||
'plugin.xml',
|
'plugin.xml',
|
||||||
'plugin.properties',
|
'plugin.properties',
|
||||||
'about.mappings',
|
'about.mappings',
|
||||||
'about.properties',
|
'about.properties',
|
||||||
'about.ini',
|
'about.ini',
|
||||||
'modeling32.png']
|
'modeling32.png']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lint {
|
lint {
|
||||||
abortOnError false
|
abortOnError false
|
||||||
disable 'VectorPath', 'NestedWeights', 'ContentDescription', 'SmallSp'
|
disable 'VectorPath', 'NestedWeights', 'ContentDescription', 'SmallSp'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
// Annotation processors
|
// Annotation processors
|
||||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.1'
|
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.1'
|
||||||
|
|
||||||
implementation common.editor
|
implementation common.editor
|
||||||
implementation common.utilcode
|
implementation common.utilcode
|
||||||
implementation common.file_picker
|
implementation common.file_picker
|
||||||
implementation common.glide
|
implementation common.glide
|
||||||
implementation common.quickaction
|
implementation common.quickaction
|
||||||
implementation common.bll
|
implementation common.bll
|
||||||
implementation common.xml2json
|
implementation common.xml2json
|
||||||
implementation google.gson
|
implementation google.gson
|
||||||
implementation google.guava
|
implementation google.guava
|
||||||
|
|
||||||
implementation common.jsoup
|
implementation common.jsoup
|
||||||
|
|
||||||
// AndroidX
|
// AndroidX
|
||||||
implementation androidx.annotation
|
implementation androidx.annotation
|
||||||
implementation androidx.appcompat
|
implementation androidx.appcompat
|
||||||
implementation androidx.cardview
|
implementation androidx.cardview
|
||||||
implementation androidx.constraintlayout
|
implementation androidx.constraintlayout
|
||||||
implementation androidx.coordinatorlayout
|
implementation androidx.coordinatorlayout
|
||||||
implementation androidx.drawer
|
implementation androidx.drawer
|
||||||
implementation androidx.grid
|
implementation androidx.grid
|
||||||
implementation androidx.preference
|
implementation androidx.preference
|
||||||
implementation androidx.recyclerview
|
implementation androidx.recyclerview
|
||||||
implementation androidx.vectors
|
implementation androidx.vectors
|
||||||
implementation androidx.animated_vectors
|
implementation androidx.animated_vectors
|
||||||
implementation google.material
|
implementation google.material
|
||||||
|
|
||||||
// Kotlin
|
// Kotlin
|
||||||
implementation "androidx.core:core-ktx:1.7.0"
|
implementation "androidx.core:core-ktx:1.7.0"
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
|
||||||
// Local projects here
|
// Local projects here
|
||||||
implementation project (':build-tools:tooling-api')
|
implementation project (':build-tools:tooling-api')
|
||||||
implementation project (':treeview')
|
implementation project (':treeview')
|
||||||
implementation project (':emulatorview')
|
implementation project (':emulatorview')
|
||||||
implementation project (':xml-inflater')
|
implementation project (':xml-inflater')
|
||||||
implementation project (':lexers')
|
implementation project (':lexers')
|
||||||
implementation project (':common')
|
implementation project (':common')
|
||||||
implementation project (':actions')
|
implementation project (':actions')
|
||||||
|
|
||||||
implementation project (':lsp:api')
|
implementation project (':lsp:api')
|
||||||
implementation project (':lsp:java')
|
implementation project (':lsp:java')
|
||||||
implementation project (':lsp:xml')
|
implementation project (':lsp:xml')
|
||||||
|
|
||||||
implementation fileTree (dir: 'libs', include: ['*.jar'])
|
implementation fileTree (dir: 'libs', include: ['*.jar'])
|
||||||
|
|
||||||
// LeakCanary
|
// LeakCanary
|
||||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
|
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
|
||||||
|
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||||
|
|
||||||
// This is to build the tooling-api-impl project before the app is built
|
// This is to build the tooling-api-impl project before the app is built
|
||||||
// So we always copy the latest JAR file to assets
|
// So we always copy the latest JAR file to assets
|
||||||
compileOnly project (path: ':build-tools:tooling-api-impl')
|
compileOnly project (path: ':build-tools:tooling-api-impl')
|
||||||
}
|
}
|
||||||
Binary file not shown.
@@ -1,187 +1,187 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide;
|
package com.itsaky.androidide;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.appcompat.widget.TooltipCompat;
|
import androidx.appcompat.widget.TooltipCompat;
|
||||||
import androidx.core.util.Pair;
|
import androidx.core.util.Pair;
|
||||||
|
|
||||||
import com.itsaky.androidide.app.StudioActivity;
|
import com.itsaky.androidide.app.StudioActivity;
|
||||||
import com.itsaky.androidide.databinding.ActivityAboutBinding;
|
import com.itsaky.androidide.databinding.ActivityAboutBinding;
|
||||||
import com.itsaky.androidide.databinding.LayoutAboutItemsBinding;
|
import com.itsaky.androidide.databinding.LayoutAboutItemsBinding;
|
||||||
import com.itsaky.androidide.models.License;
|
import com.itsaky.androidide.models.License;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class AboutActivity extends StudioActivity {
|
public class AboutActivity extends StudioActivity {
|
||||||
|
|
||||||
public static final String JDK_SOURCE = "https://github.com/itsaky/OpenJDK-Android";
|
public static final String JDK_SOURCE = "https://github.com/itsaky/OpenJDK-Android";
|
||||||
private ActivityAboutBinding binding;
|
private ActivityAboutBinding binding;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected View bindLayout() {
|
protected View bindLayout() {
|
||||||
binding = ActivityAboutBinding.inflate(getLayoutInflater());
|
binding = ActivityAboutBinding.inflate(getLayoutInflater());
|
||||||
return binding.getRoot();
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
binding.items.footerText.setText(getFooter());
|
binding.items.footerText.setText(getFooter());
|
||||||
|
|
||||||
setupTranslations();
|
setupTranslations();
|
||||||
setupLicenses();
|
setupLicenses();
|
||||||
|
|
||||||
LayoutAboutItemsBinding items = binding.items;
|
LayoutAboutItemsBinding items = binding.items;
|
||||||
TooltipCompat.setTooltipText(items.discuss, getString(R.string.discussions_on_telegram));
|
TooltipCompat.setTooltipText(items.discuss, getString(R.string.discussions_on_telegram));
|
||||||
TooltipCompat.setTooltipText(items.github, getString(R.string.title_github));
|
TooltipCompat.setTooltipText(items.github, getString(R.string.title_github));
|
||||||
TooltipCompat.setTooltipText(items.email, getString(R.string.about_option_email));
|
TooltipCompat.setTooltipText(items.email, getString(R.string.about_option_email));
|
||||||
TooltipCompat.setTooltipText(items.website, getString(R.string.about_option_website));
|
TooltipCompat.setTooltipText(items.website, getString(R.string.about_option_website));
|
||||||
items.github.setOnClickListener(v -> getApp().openGitHub());
|
items.github.setOnClickListener(v -> getApp().openGitHub());
|
||||||
items.discuss.setOnClickListener(v -> getApp().openTelegramGroup());
|
items.discuss.setOnClickListener(v -> getApp().openTelegramGroup());
|
||||||
items.email.setOnClickListener(v -> getApp().emailUs());
|
items.email.setOnClickListener(v -> getApp().emailUs());
|
||||||
items.website.setOnClickListener(v -> getApp().openWebsite());
|
items.website.setOnClickListener(v -> getApp().openWebsite());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupTranslations() {
|
private void setupTranslations() {
|
||||||
final var translations = createTranslationsList();
|
final var translations = createTranslationsList();
|
||||||
final var sb = new StringBuilder();
|
final var sb = new StringBuilder();
|
||||||
|
|
||||||
for (var translation : translations) {
|
for (var translation : translations) {
|
||||||
final var author = translation.first;
|
final var author = translation.first;
|
||||||
final var language = translation.second;
|
final var language = translation.second;
|
||||||
|
|
||||||
sb.append(author);
|
sb.append(author);
|
||||||
sb.append(" - ");
|
sb.append(" - ");
|
||||||
sb.append(language);
|
sb.append(language);
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.items.translations.setText(sb);
|
binding.items.translations.setText(sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the list of translations. The list items are pairs. The first item of the pair is the
|
* Create the list of translations. The list items are pairs. The first item of the pair is the
|
||||||
* name of the language. The second item is the name of the person who made the translations.
|
* name of the language. The second item is the name of the person who made the translations.
|
||||||
*
|
*
|
||||||
* <p>If you're adding translations, make sure you add an item to this list. You can choose to
|
* <p>If you're adding translations, make sure you add an item to this list. You can choose to
|
||||||
* display the language in a localized version. For example : Language: हिन्दी - < name of author
|
* display the language in a localized version. For example : Language: हिन्दी - < name of author
|
||||||
* >
|
* >
|
||||||
*
|
*
|
||||||
* <p>Prefer using unicode escapes for language names. For example, हिन्दी can be written as :
|
* <p>Prefer using unicode escapes for language names. For example, हिन्दी can be written as :
|
||||||
* Language: \u0939\u093f\u0928\u094d\u0926\u0940 - < name of author >
|
* Language: \u0939\u093f\u0928\u094d\u0926\u0940 - < name of author >
|
||||||
*
|
*
|
||||||
* @return The translations list.
|
* @return The translations list.
|
||||||
*/
|
*/
|
||||||
private List<Pair<String, String>> createTranslationsList() {
|
private List<Pair<String, String>> createTranslationsList() {
|
||||||
final var list = new ArrayList<Pair<String, String>>();
|
final var list = new ArrayList<Pair<String, String>>();
|
||||||
|
|
||||||
list.add(Pair.create("Bahasa Indonesia", "Fitrah Nuno Syahbani"));
|
list.add(Pair.create("Bahasa Indonesia", "Fitrah Nuno Syahbani"));
|
||||||
list.add(Pair.create("\u4e2d\u6587", "Rosemoe and @mikofe")); // 中文
|
list.add(Pair.create("\u4e2d\u6587", "Rosemoe and @mikofe")); // 中文
|
||||||
list.add(Pair.create("Deutsch", "Marvin Stelter"));
|
list.add(Pair.create("Deutsch", "Marvin Stelter"));
|
||||||
list.add(Pair.create("\u0939\u093f\u0928\u094d\u0926\u0940", "Premjit Chowdhury")); // हिन्दी
|
list.add(Pair.create("\u0939\u093f\u0928\u094d\u0926\u0940", "Premjit Chowdhury")); // हिन्दी
|
||||||
list.add(Pair.create("Russian", "Smooth-E"));
|
list.add(Pair.create("Russian", "Smooth-E"));
|
||||||
list.add(Pair.create("French", "Se-Lyan"));
|
list.add(Pair.create("French", "Se-Lyan"));
|
||||||
list.add(Pair.create("Portuguese-Brazilian", "Frederick'XS"));
|
list.add(Pair.create("Portuguese-Brazilian", "Frederick'XS"));
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupLicenses() {
|
private void setupLicenses() {
|
||||||
final var licenses = new ArrayList<License>();
|
final var licenses = new ArrayList<License>();
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License(
|
new License(
|
||||||
"AndroidX Libraries", "Apache License 2.0", "https://github.com/androidx/androidx"));
|
"AndroidX Libraries", "Apache License 2.0", "https://github.com/androidx/androidx"));
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License("Gradle Build Tool", "Apache License 2.0", "https://github.com/gradle/gradle"));
|
new License("Gradle Build Tool", "Apache License 2.0", "https://github.com/gradle/gradle"));
|
||||||
licenses.add(new License("Gson", "Apache License 2.0", "https://github.com/google/gson"));
|
licenses.add(new License("Gson", "Apache License 2.0", "https://github.com/google/gson"));
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License(
|
new License(
|
||||||
"Material Components for Android",
|
"Material Components for Android",
|
||||||
"Apache License 2.0",
|
"Apache License 2.0",
|
||||||
"https://github.com/material-components/material-components-android"));
|
"https://github.com/material-components/material-components-android"));
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License("ANTLR4 Runtime", "BSD 3-clause License", "https://github.com/antlr/antlr4"));
|
new License("ANTLR4 Runtime", "BSD 3-clause License", "https://github.com/antlr/antlr4"));
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License("Glide", "BSD, part MIT and Apache 2.0", "https://github.com/bumptech/glide"));
|
new License("Glide", "BSD, part MIT and Apache 2.0", "https://github.com/bumptech/glide"));
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License(
|
new License(
|
||||||
"Android UtilCode", "Apache License 2.0", "https://github.com/Blankj/AndroidUtilCode"));
|
"Android UtilCode", "Apache License 2.0", "https://github.com/Blankj/AndroidUtilCode"));
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License(
|
new License(
|
||||||
"UnicornFilePicker",
|
"UnicornFilePicker",
|
||||||
"Apache License 2.0",
|
"Apache License 2.0",
|
||||||
"https://github.com/abhishekti7/UnicornFilePicker"));
|
"https://github.com/abhishekti7/UnicornFilePicker"));
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License("QuickAction", "Apache License 2.0", "https://github.com/piruin/quickaction"));
|
new License("QuickAction", "Apache License 2.0", "https://github.com/piruin/quickaction"));
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License("XmlToJson", "Apache License 2.0", "https://github.com/smart-fun/XmlToJson"));
|
new License("XmlToJson", "Apache License 2.0", "https://github.com/smart-fun/XmlToJson"));
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License(
|
new License(
|
||||||
"AndroidTreeView",
|
"AndroidTreeView",
|
||||||
"Apache License 2.0",
|
"Apache License 2.0",
|
||||||
"https://github.com/bmelnychuk/AndroidTreeView"));
|
"https://github.com/bmelnychuk/AndroidTreeView"));
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License(
|
new License(
|
||||||
"CodeEditor v0.5.2", "Apache License 2.0", "https://github.com/Rosemoe/CodeEditor"));
|
"CodeEditor v0.5.2", "Apache License 2.0", "https://github.com/Rosemoe/CodeEditor"));
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License("Guava-Android", "Apache License 2.0", "https://github.com/google/guava"));
|
new License("Guava-Android", "Apache License 2.0", "https://github.com/google/guava"));
|
||||||
licenses.add(new License("Jsoup", "MIT License", "https://github.com/jhy/jsoup"));
|
licenses.add(new License("Jsoup", "MIT License", "https://github.com/jhy/jsoup"));
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License("Termux [Terminal Emulator]", "GPL 3", "https://github.com/termux/termux-app"));
|
new License("Termux [Terminal Emulator]", "GPL 3", "https://github.com/termux/termux-app"));
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License("JavaPoet", "Apache License 2.0", "https://github.com/square/JavaPoet"));
|
new License("JavaPoet", "Apache License 2.0", "https://github.com/square/JavaPoet"));
|
||||||
licenses.add(
|
licenses.add(
|
||||||
new License("Zip4j", "Apache License 2.0", "https://github.com/srikanth-lingala/zip4j"));
|
new License("Zip4j", "Apache License 2.0", "https://github.com/srikanth-lingala/zip4j"));
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (License license : licenses) {
|
for (License license : licenses) {
|
||||||
sb.append("\u2022 ");
|
sb.append("\u2022 ");
|
||||||
sb.append(license.name);
|
sb.append(license.name);
|
||||||
sb.append("<br>");
|
sb.append("<br>");
|
||||||
sb.append(getString(R.string.msg_about_licensed_under));
|
sb.append(getString(R.string.msg_about_licensed_under));
|
||||||
sb.append(license.license);
|
sb.append(license.license);
|
||||||
sb.append("<br><a href=\"");
|
sb.append("<br><a href=\"");
|
||||||
sb.append(license.url);
|
sb.append(license.url);
|
||||||
sb.append("\">");
|
sb.append("\">");
|
||||||
sb.append(license.url);
|
sb.append(license.url);
|
||||||
sb.append("</a>");
|
sb.append("</a>");
|
||||||
sb.append("<br><br>");
|
sb.append("<br><br>");
|
||||||
}
|
}
|
||||||
sb.append(getString(R.string.license_jdk));
|
sb.append(getString(R.string.license_jdk));
|
||||||
sb.append(String.format("<br><a href=\"%1$s\">%1$s</a>", JDK_SOURCE));
|
sb.append(String.format("<br><a href=\"%1$s\">%1$s</a>", JDK_SOURCE));
|
||||||
sb.append("<br><br>");
|
sb.append("<br><br>");
|
||||||
binding.items.licenses.setText(Html.fromHtml(sb.toString(), Html.FROM_HTML_MODE_LEGACY));
|
binding.items.licenses.setText(Html.fromHtml(sb.toString(), Html.FROM_HTML_MODE_LEGACY));
|
||||||
binding.items.licenses.setMovementMethod(LinkMovementMethod.getInstance());
|
binding.items.licenses.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getFooter() {
|
private String getFooter() {
|
||||||
final String arch = android.os.Build.SUPPORTED_ABIS[0];
|
final String arch = android.os.Build.SUPPORTED_ABIS[0];
|
||||||
try {
|
try {
|
||||||
final String version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
|
final String version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
|
||||||
return getString(R.string.about_footer, version, arch);
|
return getString(R.string.about_footer, version, arch);
|
||||||
} catch (Throwable th) {
|
} catch (Throwable th) {
|
||||||
return getString(R.string.about_footer_alternate, arch);
|
return getString(R.string.about_footer_alternate, arch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,321 +1,321 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide;
|
package com.itsaky.androidide;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
|
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.transition.TransitionManager;
|
import androidx.transition.TransitionManager;
|
||||||
|
|
||||||
import com.blankj.utilcode.util.FileIOUtils;
|
import com.blankj.utilcode.util.FileIOUtils;
|
||||||
import com.blankj.utilcode.util.SizeUtils;
|
import com.blankj.utilcode.util.SizeUtils;
|
||||||
import com.blankj.utilcode.util.ThreadUtils;
|
import com.blankj.utilcode.util.ThreadUtils;
|
||||||
import com.google.android.material.button.MaterialButton;
|
import com.google.android.material.button.MaterialButton;
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.itsaky.androidide.app.StudioActivity;
|
import com.itsaky.androidide.app.StudioActivity;
|
||||||
import com.itsaky.androidide.databinding.ActivityDownloadBinding;
|
import com.itsaky.androidide.databinding.ActivityDownloadBinding;
|
||||||
import com.itsaky.androidide.fragments.sheets.ProgressSheet;
|
import com.itsaky.androidide.fragments.sheets.ProgressSheet;
|
||||||
import com.itsaky.androidide.managers.PreferenceManager;
|
import com.itsaky.androidide.managers.PreferenceManager;
|
||||||
import com.itsaky.androidide.shell.IProcessExecutor;
|
import com.itsaky.androidide.shell.IProcessExecutor;
|
||||||
import com.itsaky.androidide.shell.ProcessExecutorFactory;
|
import com.itsaky.androidide.shell.ProcessExecutorFactory;
|
||||||
import com.itsaky.androidide.shell.ProcessStreamsHolder;
|
import com.itsaky.androidide.shell.ProcessStreamsHolder;
|
||||||
import com.itsaky.androidide.tasks.TaskExecutor;
|
import com.itsaky.androidide.tasks.TaskExecutor;
|
||||||
import com.itsaky.androidide.tasks.callables.ListDirectoryCallable;
|
import com.itsaky.androidide.tasks.callables.ListDirectoryCallable;
|
||||||
import com.itsaky.androidide.utils.DialogUtils;
|
import com.itsaky.androidide.utils.DialogUtils;
|
||||||
import com.itsaky.androidide.utils.Environment;
|
import com.itsaky.androidide.utils.Environment;
|
||||||
import com.itsaky.androidide.utils.FileUtil;
|
import com.itsaky.androidide.utils.FileUtil;
|
||||||
import com.itsaky.androidide.utils.InputStreamLineReader;
|
import com.itsaky.androidide.utils.InputStreamLineReader;
|
||||||
import com.itsaky.toaster.Toaster;
|
import com.itsaky.toaster.Toaster;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import abhishekti7.unicorn.filepicker.UnicornFilePicker;
|
import abhishekti7.unicorn.filepicker.UnicornFilePicker;
|
||||||
|
|
||||||
public class DownloadActivity extends StudioActivity {
|
public class DownloadActivity extends StudioActivity {
|
||||||
|
|
||||||
private ActivityDownloadBinding binding;
|
private ActivityDownloadBinding binding;
|
||||||
private ProgressSheet progressSheet;
|
private ProgressSheet progressSheet;
|
||||||
private File choosenDir = null;
|
private File choosenDir = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected View bindLayout() {
|
protected View bindLayout() {
|
||||||
binding = ActivityDownloadBinding.inflate(getLayoutInflater());
|
binding = ActivityDownloadBinding.inflate(getLayoutInflater());
|
||||||
return binding.getRoot();
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
final OnClickListener clickListener = this::handleClick;
|
final OnClickListener clickListener = this::handleClick;
|
||||||
binding.dismiss.setOnClickListener(clickListener);
|
binding.dismiss.setOnClickListener(clickListener);
|
||||||
binding.choose.setOnClickListener(clickListener);
|
binding.choose.setOnClickListener(clickListener);
|
||||||
binding.install.setOnClickListener(clickListener);
|
binding.install.setOnClickListener(clickListener);
|
||||||
|
|
||||||
binding.install.setEnabled(false);
|
binding.install.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleClick(View v) {
|
private void handleClick(View v) {
|
||||||
final int id = v.getId();
|
final int id = v.getId();
|
||||||
if (id == binding.dismiss.getId()) {
|
if (id == binding.dismiss.getId()) {
|
||||||
TransitionManager.beginDelayedTransition(binding.getRoot());
|
TransitionManager.beginDelayedTransition(binding.getRoot());
|
||||||
binding.card.setVisibility(View.GONE);
|
binding.card.setVisibility(View.GONE);
|
||||||
} else if (id == binding.choose.getId()) {
|
} else if (id == binding.choose.getId()) {
|
||||||
try {
|
try {
|
||||||
binding.install.setEnabled(false);
|
binding.install.setEnabled(false);
|
||||||
UnicornFilePicker.from(this)
|
UnicornFilePicker.from(this)
|
||||||
.addConfigBuilder()
|
.addConfigBuilder()
|
||||||
.addItemDivider(false)
|
.addItemDivider(false)
|
||||||
.selectMultipleFiles(false)
|
.selectMultipleFiles(false)
|
||||||
.setRootDirectory(FileUtil.getExternalStorageDir())
|
.setRootDirectory(FileUtil.getExternalStorageDir())
|
||||||
.showHiddenFiles(true)
|
.showHiddenFiles(true)
|
||||||
.showOnlyDirectory(true)
|
.showOnlyDirectory(true)
|
||||||
.theme(R.style.AppTheme_FilePicker)
|
.theme(R.style.AppTheme_FilePicker)
|
||||||
.build()
|
.build()
|
||||||
.forResult(abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE);
|
.forResult(abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE);
|
||||||
} catch (Throwable th) {
|
} catch (Throwable th) {
|
||||||
LOG.error(getString(R.string.err_cannot_start_file_picker), th);
|
LOG.error(getString(R.string.err_cannot_start_file_picker), th);
|
||||||
}
|
}
|
||||||
} else if (id == binding.install.getId()) {
|
} else if (id == binding.install.getId()) {
|
||||||
if (choosenDir == null) {
|
if (choosenDir == null) {
|
||||||
getApp().toast(R.string.msg_pick_files, Toaster.Type.ERROR);
|
getApp().toast(R.string.msg_pick_files, Toaster.Type.ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!choosenDir.exists()) {
|
if (!choosenDir.exists()) {
|
||||||
getApp().toast(R.string.msg_file_doesnt_exist, Toaster.Type.ERROR);
|
getApp().toast(R.string.msg_file_doesnt_exist, Toaster.Type.ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
installAll();
|
installAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void installAll() {
|
private void installAll() {
|
||||||
showProgress();
|
showProgress();
|
||||||
getApp().getPrefManager().putBoolean(PreferenceManager.KEY_FRAMEWORK_DOWNLOADED, true);
|
getApp().getPrefManager().putBoolean(PreferenceManager.KEY_FRAMEWORK_DOWNLOADED, true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final File script = createExtractScript();
|
final File script = createExtractScript();
|
||||||
final ProcessStreamsHolder holder = new ProcessStreamsHolder();
|
final ProcessStreamsHolder holder = new ProcessStreamsHolder();
|
||||||
final IProcessExecutor executor = ProcessExecutorFactory.commonExecutor();
|
final IProcessExecutor executor = ProcessExecutorFactory.commonExecutor();
|
||||||
|
|
||||||
executor.execAsync(
|
executor.execAsync(
|
||||||
holder,
|
holder,
|
||||||
this::onInstallProcessExit,
|
this::onInstallProcessExit,
|
||||||
true,
|
true,
|
||||||
Environment.BUSYBOX.getAbsolutePath(),
|
Environment.BUSYBOX.getAbsolutePath(),
|
||||||
"sh", // We use busybox's sh, because Environment.SHELL is not installed yet...
|
"sh", // We use busybox's sh, because Environment.SHELL is not installed yet...
|
||||||
script.getAbsolutePath());
|
script.getAbsolutePath());
|
||||||
|
|
||||||
this.output = new StringBuilder();
|
this.output = new StringBuilder();
|
||||||
final InputStreamLineReader reader =
|
final InputStreamLineReader reader =
|
||||||
new InputStreamLineReader(holder.in, this::onInstallationOutput);
|
new InputStreamLineReader(holder.in, this::onInstallationOutput);
|
||||||
new Thread(reader).start();
|
new Thread(reader).start();
|
||||||
|
|
||||||
} catch (DownloadActivity.InstallationException e) {
|
} catch (DownloadActivity.InstallationException e) {
|
||||||
LOG.error(getString(R.string.err_installation), e);
|
LOG.error(getString(R.string.err_installation), e);
|
||||||
onInstallationFailed(e.exitCode);
|
onInstallationFailed(e.exitCode);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.error(getString(R.string.err_installation), e);
|
LOG.error(getString(R.string.err_installation), e);
|
||||||
onInstallationFailed(5); // Exit code 5 : I/O Error
|
onInstallationFailed(5); // Exit code 5 : I/O Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onInstallationOutput(final String line) {
|
private void onInstallationOutput(final String line) {
|
||||||
ThreadUtils.runOnUiThread(() -> this.appendOut(line));
|
ThreadUtils.runOnUiThread(() -> this.appendOut(line));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onInstallProcessExit(final int code) {
|
private void onInstallProcessExit(final int code) {
|
||||||
ThreadUtils.runOnUiThread(
|
ThreadUtils.runOnUiThread(
|
||||||
() -> {
|
() -> {
|
||||||
if (code == 0) { // 0 = normal execution
|
if (code == 0) { // 0 = normal execution
|
||||||
getApp().getPrefManager().putBoolean(PreferenceManager.KEY_FRAMEWORK_INSTALLED, true);
|
getApp().getPrefManager().putBoolean(PreferenceManager.KEY_FRAMEWORK_INSTALLED, true);
|
||||||
showRestartNeeded();
|
showRestartNeeded();
|
||||||
if (getProgressSheet().isShowing()) {
|
if (getProgressSheet().isShowing()) {
|
||||||
getProgressSheet().dismiss();
|
getProgressSheet().dismiss();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
onInstallationFailed(code);
|
onInstallationFailed(code);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onInstallationFailed(int code) {
|
private void onInstallationFailed(int code) {
|
||||||
// TODO Can this be improved by adding some animations?
|
// TODO Can this be improved by adding some animations?
|
||||||
|
|
||||||
if (getProgressSheet().isShowing()) {
|
if (getProgressSheet().isShowing()) {
|
||||||
getProgressSheet().dismiss();
|
getProgressSheet().dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(this);
|
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(this);
|
||||||
builder.setTitle(R.string.title_installation_failed);
|
builder.setTitle(R.string.title_installation_failed);
|
||||||
builder.setMessage(getString(R.string.msg_installation_failed, code, this.output.toString()));
|
builder.setMessage(getString(R.string.msg_installation_failed, code, this.output.toString()));
|
||||||
builder.setPositiveButton(
|
builder.setPositiveButton(
|
||||||
android.R.string.ok,
|
android.R.string.ok,
|
||||||
(d, w) -> {
|
(d, w) -> {
|
||||||
d.dismiss();
|
d.dismiss();
|
||||||
finishAffinity();
|
finishAffinity();
|
||||||
});
|
});
|
||||||
builder.setNegativeButton(android.R.string.cancel, null);
|
builder.setNegativeButton(android.R.string.cancel, null);
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private File createExtractScript() throws DownloadActivity.InstallationException {
|
private File createExtractScript() throws DownloadActivity.InstallationException {
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
sb.append("cd");
|
sb.append("cd");
|
||||||
joiner(sb);
|
joiner(sb);
|
||||||
sb.append("echo 'Installing...'");
|
sb.append("echo 'Installing...'");
|
||||||
joiner(sb);
|
joiner(sb);
|
||||||
|
|
||||||
File[] files = choosenDir.listFiles(ARCHIVE_FILTER);
|
File[] files = choosenDir.listFiles(ARCHIVE_FILTER);
|
||||||
|
|
||||||
if (files == null || files.length <= 0) {
|
if (files == null || files.length <= 0) {
|
||||||
throw new InstallationException(2);
|
throw new InstallationException(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (File f : files) {
|
for (File f : files) {
|
||||||
if (f.getName().endsWith(".tar.xz")) {
|
if (f.getName().endsWith(".tar.xz")) {
|
||||||
if (f.getName().startsWith("androidide-sysroot")) {
|
if (f.getName().startsWith("androidide-sysroot")) {
|
||||||
sb.append("cd $SYSROOT/..");
|
sb.append("cd $SYSROOT/..");
|
||||||
joiner(sb);
|
joiner(sb);
|
||||||
}
|
}
|
||||||
sb.append("$BUSYBOX tar xvJf '").append(f.getAbsolutePath()).append("'");
|
sb.append("$BUSYBOX tar xvJf '").append(f.getAbsolutePath()).append("'");
|
||||||
joiner(sb);
|
joiner(sb);
|
||||||
sb.append("cd $HOME");
|
sb.append("cd $HOME");
|
||||||
joiner(sb);
|
joiner(sb);
|
||||||
} else if (f.getName().endsWith(".zip")) {
|
} else if (f.getName().endsWith(".zip")) {
|
||||||
sb.append("$BUSYBOX unzip '").append(f.getAbsolutePath()).append("'");
|
sb.append("$BUSYBOX unzip '").append(f.getAbsolutePath()).append("'");
|
||||||
joiner(sb);
|
joiner(sb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.append("echo 'Cleaning unsupported flags in binaries...'");
|
sb.append("echo 'Cleaning unsupported flags in binaries...'");
|
||||||
joiner(sb);
|
joiner(sb);
|
||||||
String DONE = "DONE";
|
String DONE = "DONE";
|
||||||
sb.append("echo ").append(DONE);
|
sb.append("echo ").append(DONE);
|
||||||
|
|
||||||
final File script = new File(Environment.TMP_DIR, "extract_tools.sh");
|
final File script = new File(Environment.TMP_DIR, "extract_tools.sh");
|
||||||
if (!FileIOUtils.writeFileFromString(script, sb.toString())) {
|
if (!FileIOUtils.writeFileFromString(script, sb.toString())) {
|
||||||
throw new InstallationException(2);
|
throw new InstallationException(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void joiner(StringBuilder sb) {
|
private void joiner(StringBuilder sb) {
|
||||||
sb.append(" && ");
|
sb.append(" && ");
|
||||||
}
|
}
|
||||||
|
|
||||||
private StringBuilder output = new StringBuilder();
|
private StringBuilder output = new StringBuilder();
|
||||||
|
|
||||||
private void appendOut(String line) {
|
private void appendOut(String line) {
|
||||||
LOG.debug("Installation:", line);
|
LOG.debug("Installation:", line);
|
||||||
output.append(line.trim());
|
output.append(line.trim());
|
||||||
output.append("\n");
|
output.append("\n");
|
||||||
|
|
||||||
getProgressSheet().setSubMessage(line);
|
getProgressSheet().setSubMessage(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
if (requestCode == abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE
|
if (requestCode == abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE
|
||||||
&& resultCode == RESULT_OK) {
|
&& resultCode == RESULT_OK) {
|
||||||
ArrayList<String> files = data.getStringArrayListExtra("filePaths");
|
ArrayList<String> files = data.getStringArrayListExtra("filePaths");
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
if (files.size() == 1) {
|
if (files.size() == 1) {
|
||||||
File choosenDir = new File(files.get(0));
|
File choosenDir = new File(files.get(0));
|
||||||
if (choosenDir.exists() && choosenDir.isDirectory()) {
|
if (choosenDir.exists() && choosenDir.isDirectory()) {
|
||||||
this.choosenDir = choosenDir;
|
this.choosenDir = choosenDir;
|
||||||
setDone(binding.choose);
|
setDone(binding.choose);
|
||||||
binding.install.setEnabled(true);
|
binding.install.setEnabled(true);
|
||||||
new TaskExecutor()
|
new TaskExecutor()
|
||||||
.executeAsync(
|
.executeAsync(
|
||||||
new ListDirectoryCallable(choosenDir),
|
new ListDirectoryCallable(choosenDir),
|
||||||
__ -> binding.filesText.setText(getString(R.string.msg_installable_files, __)));
|
__ -> binding.filesText.setText(getString(R.string.msg_installable_files, __)));
|
||||||
} else {
|
} else {
|
||||||
getApp().toast(R.string.msg_picked_isnt_dir, Toaster.Type.ERROR);
|
getApp().toast(R.string.msg_picked_isnt_dir, Toaster.Type.ERROR);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getApp().toast(R.string.msg_pick_single_file, Toaster.Type.ERROR);
|
getApp().toast(R.string.msg_pick_single_file, Toaster.Type.ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDone(MaterialButton button) {
|
private void setDone(MaterialButton button) {
|
||||||
final int dp8 = SizeUtils.dp2px(8);
|
final int dp8 = SizeUtils.dp2px(8);
|
||||||
final int dp4 = SizeUtils.dp2px(4);
|
final int dp4 = SizeUtils.dp2px(4);
|
||||||
final int dp24 = SizeUtils.dp2px(24);
|
final int dp24 = SizeUtils.dp2px(24);
|
||||||
button.setText("");
|
button.setText("");
|
||||||
button.setIconResource(R.drawable.ic_ok);
|
button.setIconResource(R.drawable.ic_ok);
|
||||||
button.setIconTint(ColorStateList.valueOf(ContextCompat.getColor(this, R.color.bg_green)));
|
button.setIconTint(ColorStateList.valueOf(ContextCompat.getColor(this, R.color.bg_green)));
|
||||||
button.setBackgroundColor(android.graphics.Color.TRANSPARENT);
|
button.setBackgroundColor(android.graphics.Color.TRANSPARENT);
|
||||||
button.setPaddingRelative(dp8, dp4, dp8, dp4);
|
button.setPaddingRelative(dp8, dp4, dp8, dp4);
|
||||||
button.setStrokeWidth(0);
|
button.setStrokeWidth(0);
|
||||||
button.setGravity(Gravity.CENTER);
|
button.setGravity(Gravity.CENTER);
|
||||||
button.setIconPadding(0);
|
button.setIconPadding(0);
|
||||||
button.setInsetTop(0);
|
button.setInsetTop(0);
|
||||||
button.setInsetBottom(0);
|
button.setInsetBottom(0);
|
||||||
button.setPaddingRelative(dp24, dp4, dp24, dp4);
|
button.setPaddingRelative(dp24, dp4, dp24, dp4);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showProgress() {
|
private void showProgress() {
|
||||||
getProgressSheet().setCancelable(false);
|
getProgressSheet().setCancelable(false);
|
||||||
getProgressSheet().setShowShadow(false);
|
getProgressSheet().setShowShadow(false);
|
||||||
getProgressSheet()
|
getProgressSheet()
|
||||||
.setSubMessageEnabled(true)
|
.setSubMessageEnabled(true)
|
||||||
.setWelcomeTextEnabled(true)
|
.setWelcomeTextEnabled(true)
|
||||||
.show(getSupportFragmentManager(), "progress_sheet");
|
.show(getSupportFragmentManager(), "progress_sheet");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showRestartNeeded() {
|
private void showRestartNeeded() {
|
||||||
setDone(binding.install);
|
setDone(binding.install);
|
||||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(this);
|
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(this);
|
||||||
builder.setTitle(R.string.title_restart);
|
builder.setTitle(R.string.title_restart);
|
||||||
builder.setMessage(R.string.msg_restart);
|
builder.setMessage(R.string.msg_restart);
|
||||||
builder.setCancelable(false);
|
builder.setCancelable(false);
|
||||||
builder.setPositiveButton(android.R.string.ok, (p1, p2) -> finishAffinity());
|
builder.setPositiveButton(android.R.string.ok, (p1, p2) -> finishAffinity());
|
||||||
builder.create().show();
|
builder.create().show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProgressSheet getProgressSheet() {
|
private ProgressSheet getProgressSheet() {
|
||||||
return progressSheet == null
|
return progressSheet == null
|
||||||
? progressSheet = new ProgressSheet().setMessage(getString(R.string.please_wait))
|
? progressSheet = new ProgressSheet().setMessage(getString(R.string.please_wait))
|
||||||
: progressSheet;
|
: progressSheet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final FileFilter ARCHIVE_FILTER =
|
private final FileFilter ARCHIVE_FILTER =
|
||||||
p1 -> p1.isFile() && (p1.getName().endsWith(".tar.xz") || p1.getName().endsWith(".zip"));
|
p1 -> p1.isFile() && (p1.getName().endsWith(".tar.xz") || p1.getName().endsWith(".zip"));
|
||||||
|
|
||||||
private static class InstallationException extends Exception {
|
private static class InstallationException extends Exception {
|
||||||
private final int exitCode;
|
private final int exitCode;
|
||||||
|
|
||||||
public InstallationException(int exitCode) {
|
public InstallationException(int exitCode) {
|
||||||
this.exitCode = exitCode;
|
this.exitCode = exitCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -425,4 +425,4 @@ public class MainActivity extends StudioActivity
|
|||||||
mProgressSheet.dismiss();
|
mProgressSheet.dismiss();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,92 +1,92 @@
|
|||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
**************************************************************************************/
|
**************************************************************************************/
|
||||||
|
|
||||||
package com.itsaky.androidide;
|
package com.itsaky.androidide;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.itsaky.androidide.app.StudioActivity;
|
import com.itsaky.androidide.app.StudioActivity;
|
||||||
import com.itsaky.androidide.app.StudioApp;
|
import com.itsaky.androidide.app.StudioApp;
|
||||||
import com.itsaky.androidide.databinding.ActivitySplashBinding;
|
import com.itsaky.androidide.databinding.ActivitySplashBinding;
|
||||||
import com.itsaky.androidide.models.ConstantsBridge;
|
import com.itsaky.androidide.models.ConstantsBridge;
|
||||||
import com.itsaky.androidide.utils.DialogUtils;
|
import com.itsaky.androidide.utils.DialogUtils;
|
||||||
|
|
||||||
public class SplashActivity extends StudioActivity {
|
public class SplashActivity extends StudioActivity {
|
||||||
private static final Handler mHandler = new Handler();
|
private static final Handler mHandler = new Handler();
|
||||||
private final Runnable mRunnable =
|
private final Runnable mRunnable =
|
||||||
() -> {
|
() -> {
|
||||||
ConstantsBridge.SPLASH_TO_MAIN = true;
|
ConstantsBridge.SPLASH_TO_MAIN = true;
|
||||||
startActivity(new Intent(SplashActivity.this, MainActivity.class));
|
startActivity(new Intent(SplashActivity.this, MainActivity.class));
|
||||||
finish();
|
finish();
|
||||||
};
|
};
|
||||||
private ActivitySplashBinding binding;
|
private ActivitySplashBinding binding;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
binding.splashText.setText(getString(R.string.msg_checking_storage_permissions));
|
binding.splashText.setText(getString(R.string.msg_checking_storage_permissions));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStorageAlreadyGranted() {
|
protected void onStorageAlreadyGranted() {
|
||||||
super.onStorageAlreadyGranted();
|
super.onStorageAlreadyGranted();
|
||||||
proceed();
|
proceed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStorageGranted() {
|
protected void onStorageGranted() {
|
||||||
super.onStorageGranted();
|
super.onStorageGranted();
|
||||||
proceed();
|
proceed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected View bindLayout() {
|
protected View bindLayout() {
|
||||||
binding = ActivitySplashBinding.inflate(getLayoutInflater());
|
binding = ActivitySplashBinding.inflate(getLayoutInflater());
|
||||||
return binding.getRoot();
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void proceed() {
|
private void proceed() {
|
||||||
if (!StudioApp.isAbiSupported()) {
|
if (!StudioApp.isAbiSupported()) {
|
||||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(this);
|
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(this);
|
||||||
builder.setTitle(R.string.title_device_not_supported);
|
builder.setTitle(R.string.title_device_not_supported);
|
||||||
builder.setMessage(R.string.msg_device_not_supported);
|
builder.setMessage(R.string.msg_device_not_supported);
|
||||||
builder.setCancelable(false);
|
builder.setCancelable(false);
|
||||||
builder.setPositiveButton(android.R.string.ok, (p1, p2) -> finishAffinity());
|
builder.setPositiveButton(android.R.string.ok, (p1, p2) -> finishAffinity());
|
||||||
builder.create().show();
|
builder.create().show();
|
||||||
} else {
|
} else {
|
||||||
binding.splashText.setText(getString(R.string.msg_storage_granted));
|
binding.splashText.setText(getString(R.string.msg_storage_granted));
|
||||||
if (getApp().isFrameworkInstalled()) {
|
if (getApp().isFrameworkInstalled()) {
|
||||||
goToMain();
|
goToMain();
|
||||||
} else {
|
} else {
|
||||||
startActivity(new Intent(this, DownloadActivity.class));
|
startActivity(new Intent(this, DownloadActivity.class));
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void goToMain() {
|
private void goToMain() {
|
||||||
mHandler.removeCallbacks(mRunnable);
|
mHandler.removeCallbacks(mRunnable);
|
||||||
mHandler.postDelayed(mRunnable, 1000);
|
mHandler.postDelayed(mRunnable, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +1,55 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions
|
package com.itsaky.androidide.actions
|
||||||
|
|
||||||
import com.itsaky.androidide.EditorActivity
|
import com.itsaky.androidide.EditorActivity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marker class for actions that execute build related tasks.
|
* Marker class for actions that execute build related tasks.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
abstract class BaseBuildAction : EditorActivityAction() {
|
abstract class BaseBuildAction : EditorActivityAction() {
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
val context = getActivity(data)
|
val context = getActivity(data)
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
visible = false
|
visible = false
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
visible = true
|
visible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isBuildInProgress(context)) {
|
if (isBuildInProgress(context)) {
|
||||||
enabled = false
|
enabled = false
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
enabled = true
|
enabled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun postExec(data: ActionData, result: Any) {
|
override fun postExec(data: ActionData, result: Any) {
|
||||||
val context = getActivity(data) ?: return
|
val context = getActivity(data) ?: return
|
||||||
context.invalidateOptionsMenu()
|
context.invalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shouldPrepare() = visible && enabled
|
fun shouldPrepare() = visible && enabled
|
||||||
|
|
||||||
private fun isBuildInProgress(activity: EditorActivity): Boolean =
|
private fun isBuildInProgress(activity: EditorActivity): Boolean =
|
||||||
activity.buildService == null || activity.buildService.isBuildInProgress
|
activity.buildService == null || activity.buildService.isBuildInProgress
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +1,62 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions
|
package com.itsaky.androidide.actions
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.views.editor.IDEEditor
|
import com.itsaky.androidide.views.editor.IDEEditor
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
abstract class BaseEditorAction : ActionItem {
|
abstract class BaseEditorAction : ActionItem {
|
||||||
|
|
||||||
override var label: String = ""
|
override var label: String = ""
|
||||||
override var visible: Boolean = true
|
override var visible: Boolean = true
|
||||||
override var enabled: Boolean = true
|
override var enabled: Boolean = true
|
||||||
override var icon: Drawable? = null
|
override var icon: Drawable? = null
|
||||||
override var requiresUIThread: Boolean =
|
override var requiresUIThread: Boolean =
|
||||||
true // all editor actions must be executed on UI thread
|
true // all editor actions must be executed on UI thread
|
||||||
override var location: ActionItem.Location = ActionItem.Location.EDITOR_TEXT_ACTIONS
|
override var location: ActionItem.Location = ActionItem.Location.EDITOR_TEXT_ACTIONS
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
getEditor(data)
|
getEditor(data)
|
||||||
?: kotlin.run {
|
?: kotlin.run {
|
||||||
visible = false
|
visible = false
|
||||||
enabled = false
|
enabled = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
visible = true
|
visible = true
|
||||||
enabled = true
|
enabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getEditor(data: ActionData): IDEEditor? {
|
fun getEditor(data: ActionData): IDEEditor? {
|
||||||
return data.get(IDEEditor::class.java)
|
return data.get(IDEEditor::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getContext(data: ActionData): Context? {
|
fun getContext(data: ActionData): Context? {
|
||||||
val editor = getEditor(data) ?: return null
|
val editor = getEditor(data) ?: return null
|
||||||
return editor.context
|
return editor.context
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tintDrawable(context: Context, drawable: Drawable): Drawable {
|
fun tintDrawable(context: Context, drawable: Drawable): Drawable {
|
||||||
drawable.setTint(
|
drawable.setTint(
|
||||||
ContextCompat.getColor(context, com.itsaky.androidide.R.color.primaryIconColor))
|
ContextCompat.getColor(context, com.itsaky.androidide.R.color.primaryIconColor))
|
||||||
return drawable
|
return drawable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,45 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions
|
package com.itsaky.androidide.actions
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import com.itsaky.androidide.EditorActivity
|
import com.itsaky.androidide.EditorActivity
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
abstract class EditorActivityAction : ActionItem {
|
abstract class EditorActivityAction : ActionItem {
|
||||||
|
|
||||||
override var enabled: Boolean = true
|
override var enabled: Boolean = true
|
||||||
override var visible: Boolean = true
|
override var visible: Boolean = true
|
||||||
override var icon: Drawable? = null
|
override var icon: Drawable? = null
|
||||||
override var label: String = ""
|
override var label: String = ""
|
||||||
override var location: ActionItem.Location = ActionItem.Location.EDITOR_TOOLBAR
|
override var location: ActionItem.Location = ActionItem.Location.EDITOR_TOOLBAR
|
||||||
|
|
||||||
override var requiresUIThread: Boolean = false
|
override var requiresUIThread: Boolean = false
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
if (!hasRequiredData(data, Context::class.java)) {
|
if (!hasRequiredData(data, Context::class.java)) {
|
||||||
markInvisible()
|
markInvisible()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getActivity(data: ActionData): EditorActivity? {
|
fun getActivity(data: ActionData): EditorActivity? {
|
||||||
val context = data.get(Context::class.java) ?: return null
|
val context = data.get(Context::class.java) ?: return null
|
||||||
return context as EditorActivity
|
return context as EditorActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions
|
package com.itsaky.androidide.actions
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
abstract class EditorActivityActionMenu : EditorActivityAction(), ActionMenu {
|
abstract class EditorActivityActionMenu : EditorActivityAction(), ActionMenu {
|
||||||
override val children: MutableSet<ActionItem> = mutableSetOf()
|
override val children: MutableSet<ActionItem> = mutableSetOf()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,46 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions
|
package com.itsaky.androidide.actions
|
||||||
|
|
||||||
import com.itsaky.androidide.views.editor.CodeEditorView
|
import com.itsaky.androidide.views.editor.CodeEditorView
|
||||||
import com.itsaky.androidide.views.editor.IDEEditor
|
import com.itsaky.androidide.views.editor.IDEEditor
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
abstract class EditorRelatedAction : EditorActivityAction() {
|
abstract class EditorRelatedAction : EditorActivityAction() {
|
||||||
|
|
||||||
override var requiresUIThread: Boolean = true
|
override var requiresUIThread: Boolean = true
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
val editor =
|
val editor =
|
||||||
getEditor(data)
|
getEditor(data)
|
||||||
?: run {
|
?: run {
|
||||||
visible = false
|
visible = false
|
||||||
enabled = false
|
enabled = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val file = editor.file
|
val file = editor.file
|
||||||
|
|
||||||
visible = file != null
|
visible = file != null
|
||||||
enabled = visible
|
enabled = visible
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getEditor(data: ActionData): IDEEditor? = data.get(IDEEditor::class.java)
|
fun getEditor(data: ActionData): IDEEditor? = data.get(IDEEditor::class.java)
|
||||||
|
|
||||||
fun getEditorView(data: ActionData): CodeEditorView? = data[CodeEditorView::class.java]
|
fun getEditorView(data: ActionData): CodeEditorView? = data[CodeEditorView::class.java]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.build
|
package com.itsaky.androidide.actions.build
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseBuildAction
|
import com.itsaky.androidide.actions.BaseBuildAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class AssembleDebugAction() : BaseBuildAction() {
|
class AssembleDebugAction() : BaseBuildAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.build_debug)
|
label = context.getString(R.string.build_debug)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_run_debug)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_run_debug)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "editor_assembleDebug"
|
override val id: String = "editor_assembleDebug"
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val activity = getActivity(data) ?: return false
|
val activity = getActivity(data) ?: return false
|
||||||
|
|
||||||
activity.assembleDebug(true)
|
activity.assembleDebug(true)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.build
|
package com.itsaky.androidide.actions.build
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseBuildAction
|
import com.itsaky.androidide.actions.BaseBuildAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class AssembleReleaseAction() : BaseBuildAction() {
|
class AssembleReleaseAction() : BaseBuildAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.build_release)
|
label = context.getString(R.string.build_release)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_run_release)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_run_release)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "editor_assembleRelease"
|
override val id: String = "editor_assembleRelease"
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val activity = getActivity(data) ?: return false
|
val activity = getActivity(data) ?: return false
|
||||||
|
|
||||||
activity.assembleRelease()
|
activity.assembleRelease()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.build
|
package com.itsaky.androidide.actions.build
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseBuildAction
|
import com.itsaky.androidide.actions.BaseBuildAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class BuildAction() : BaseBuildAction() {
|
class BuildAction() : BaseBuildAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.build)
|
label = context.getString(R.string.build)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_run)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_run)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "editor_build"
|
override val id: String = "editor_build"
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val activity = getActivity(data) ?: return false
|
val activity = getActivity(data) ?: return false
|
||||||
|
|
||||||
activity.build()
|
activity.build()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +1,44 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.build
|
package com.itsaky.androidide.actions.build
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionItem
|
import com.itsaky.androidide.actions.ActionItem
|
||||||
import com.itsaky.androidide.actions.ActionMenu
|
import com.itsaky.androidide.actions.ActionMenu
|
||||||
import com.itsaky.androidide.actions.BaseBuildAction
|
import com.itsaky.androidide.actions.BaseBuildAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class BuildActionMenu() : BaseBuildAction(), ActionMenu {
|
class BuildActionMenu() : BaseBuildAction(), ActionMenu {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.build_tasks)
|
label = context.getString(R.string.build_tasks)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_run)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_run)
|
||||||
|
|
||||||
addAction(BuildAction(context))
|
addAction(BuildAction(context))
|
||||||
addAction(AssembleDebugAction(context))
|
addAction(AssembleDebugAction(context))
|
||||||
addAction(AssembleReleaseAction(context))
|
addAction(AssembleReleaseAction(context))
|
||||||
addAction(CreateAABAction(context))
|
addAction(CreateAABAction(context))
|
||||||
addAction(CleanAction(context))
|
addAction(CleanAction(context))
|
||||||
addAction(RebuildAction(context))
|
addAction(RebuildAction(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
override val children: MutableSet<ActionItem> = mutableSetOf()
|
override val children: MutableSet<ActionItem> = mutableSetOf()
|
||||||
override val id: String = "editor_buildTasks"
|
override val id: String = "editor_buildTasks"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +1,66 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.build
|
package com.itsaky.androidide.actions.build
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.EditorActivityAction
|
import com.itsaky.androidide.actions.EditorActivityAction
|
||||||
import com.itsaky.androidide.utils.ILogger
|
import com.itsaky.androidide.utils.ILogger
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class CancelBuildAction() : EditorActivityAction() {
|
class CancelBuildAction() : EditorActivityAction() {
|
||||||
|
|
||||||
private val log = ILogger.newInstance(javaClass.simpleName)
|
private val log = ILogger.newInstance(javaClass.simpleName)
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.title_cancel_build)
|
label = context.getString(R.string.title_cancel_build)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_stop_daemons)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_stop_daemons)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "editor_stopGradleDaemons"
|
override val id: String = "editor_stopGradleDaemons"
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
visible = true
|
visible = true
|
||||||
enabled = true
|
enabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val context = getActivity(data) ?: return false
|
val context = getActivity(data) ?: return false
|
||||||
|
|
||||||
log.info("Sending build cancellation request...")
|
log.info("Sending build cancellation request...")
|
||||||
context.buildService.cancelCurrentBuild().whenComplete { result, error ->
|
context.buildService.cancelCurrentBuild().whenComplete { result, error ->
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
log.error("Failed to send build cancellation request", error)
|
log.error("Failed to send build cancellation request", error)
|
||||||
return@whenComplete
|
return@whenComplete
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.wasEnqueued) {
|
if (!result.wasEnqueued) {
|
||||||
log.warn(
|
log.warn(
|
||||||
"Unable to enqueue cancellation request",
|
"Unable to enqueue cancellation request",
|
||||||
result.failureReason,
|
result.failureReason,
|
||||||
result.failureReason!!.message)
|
result.failureReason!!.message)
|
||||||
return@whenComplete
|
return@whenComplete
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Build cancellation request was successfully enqueued...")
|
log.info("Build cancellation request was successfully enqueued...")
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.build
|
package com.itsaky.androidide.actions.build
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseBuildAction
|
import com.itsaky.androidide.actions.BaseBuildAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class CleanAction() : BaseBuildAction() {
|
class CleanAction() : BaseBuildAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.clean_project)
|
label = context.getString(R.string.clean_project)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_clean)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_clean)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "editor_clean"
|
override val id: String = "editor_clean"
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val context = getActivity(data) ?: return false
|
val context = getActivity(data) ?: return false
|
||||||
|
|
||||||
context.clean()
|
context.clean()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.build
|
package com.itsaky.androidide.actions.build
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseBuildAction
|
import com.itsaky.androidide.actions.BaseBuildAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class CreateAABAction() : BaseBuildAction() {
|
class CreateAABAction() : BaseBuildAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.create_aab)
|
label = context.getString(R.string.create_aab)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_bundle)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_bundle)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "editor_createAAB"
|
override val id: String = "editor_createAAB"
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val context = getActivity(data) ?: return false
|
val context = getActivity(data) ?: return false
|
||||||
|
|
||||||
context.bundle()
|
context.bundle()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,46 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.build
|
package com.itsaky.androidide.actions.build
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.R.string
|
import com.itsaky.androidide.R.string
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseBuildAction
|
import com.itsaky.androidide.actions.BaseBuildAction
|
||||||
import com.itsaky.androidide.actions.EditorActivityAction
|
import com.itsaky.androidide.actions.EditorActivityAction
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers a project sync request.
|
* Triggers a project sync request.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
class ProjectSyncAction() : BaseBuildAction() {
|
class ProjectSyncAction() : BaseBuildAction() {
|
||||||
|
|
||||||
override val id: String = "action_editor_syncProject"
|
override val id: String = "action_editor_syncProject"
|
||||||
override var requiresUIThread = true
|
override var requiresUIThread = true
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(string.title_sync_project)
|
label = context.getString(string.title_sync_project)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_sync)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_sync)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Any {
|
override fun execAction(data: ActionData): Any {
|
||||||
return getActivity(data)!!.initializeProject()
|
return getActivity(data)!!.initializeProject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,45 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.build
|
package com.itsaky.androidide.actions.build
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseBuildAction
|
import com.itsaky.androidide.actions.BaseBuildAction
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The 'Quick Run' action in the editor activity.
|
* The 'Quick Run' action in the editor activity.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
class QuickRunAction() : BaseBuildAction() {
|
class QuickRunAction() : BaseBuildAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.quick_run_debug)
|
label = context.getString(R.string.quick_run_debug)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_run_outline)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_run_outline)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "editor_quick_run"
|
override val id: String = "editor_quick_run"
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val context = getActivity(data) ?: return false
|
val context = getActivity(data) ?: return false
|
||||||
context.assembleDebug(true)
|
context.assembleDebug(true)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.build
|
package com.itsaky.androidide.actions.build
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseBuildAction
|
import com.itsaky.androidide.actions.BaseBuildAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class RebuildAction() : BaseBuildAction() {
|
class RebuildAction() : BaseBuildAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.clean_amp_build)
|
label = context.getString(R.string.clean_amp_build)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_rebuild)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_rebuild)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "editor_cleanAndBuild"
|
override val id: String = "editor_cleanAndBuild"
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val context = getActivity(data) ?: return false
|
val context = getActivity(data) ?: return false
|
||||||
|
|
||||||
context.cleanAndRebuild()
|
context.cleanAndRebuild()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.build
|
package com.itsaky.androidide.actions.build
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionItem
|
import com.itsaky.androidide.actions.ActionItem
|
||||||
import com.itsaky.androidide.actions.ActionMenu
|
import com.itsaky.androidide.actions.ActionMenu
|
||||||
import com.itsaky.androidide.actions.BaseBuildAction
|
import com.itsaky.androidide.actions.BaseBuildAction
|
||||||
import com.itsaky.androidide.actions.lint.LintTaskMenu
|
import com.itsaky.androidide.actions.lint.LintTaskMenu
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class RunActionMenu() : BaseBuildAction(), ActionMenu {
|
class RunActionMenu() : BaseBuildAction(), ActionMenu {
|
||||||
|
|
||||||
override val children: MutableSet<ActionItem> = mutableSetOf()
|
override val children: MutableSet<ActionItem> = mutableSetOf()
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.run)
|
label = context.getString(R.string.run)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_run)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_run)
|
||||||
|
|
||||||
addAction(BuildActionMenu(context))
|
addAction(BuildActionMenu(context))
|
||||||
addAction(LintTaskMenu(context))
|
addAction(LintTaskMenu(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "editor_runMenu"
|
override val id: String = "editor_runMenu"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.editor
|
package com.itsaky.androidide.actions.editor
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseEditorAction
|
import com.itsaky.androidide.actions.BaseEditorAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class CopyAction() : BaseEditorAction() {
|
class CopyAction() : BaseEditorAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.copy)
|
label = context.getString(R.string.copy)
|
||||||
|
|
||||||
val arr = context.obtainStyledAttributes(intArrayOf(android.R.attr.actionModeCopyDrawable))
|
val arr = context.obtainStyledAttributes(intArrayOf(android.R.attr.actionModeCopyDrawable))
|
||||||
icon = arr.getDrawable(0)?.let { tintDrawable(context, it) }
|
icon = arr.getDrawable(0)?.let { tintDrawable(context, it) }
|
||||||
arr.recycle()
|
arr.recycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "ideEditor_copy"
|
override val id: String = "ideEditor_copy"
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val editor = getEditor(data) ?: return false
|
val editor = getEditor(data) ?: return false
|
||||||
editor.copyText()
|
editor.copyText()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,53 +1,53 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.editor
|
package com.itsaky.androidide.actions.editor
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseEditorAction
|
import com.itsaky.androidide.actions.BaseEditorAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class CutAction() : BaseEditorAction() {
|
class CutAction() : BaseEditorAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.cut)
|
label = context.getString(R.string.cut)
|
||||||
|
|
||||||
val arr = context.obtainStyledAttributes(intArrayOf(android.R.attr.actionModeCutDrawable))
|
val arr = context.obtainStyledAttributes(intArrayOf(android.R.attr.actionModeCutDrawable))
|
||||||
icon = arr.getDrawable(0)?.let { tintDrawable(context, it) }
|
icon = arr.getDrawable(0)?.let { tintDrawable(context, it) }
|
||||||
arr.recycle()
|
arr.recycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
super.prepare(data)
|
super.prepare(data)
|
||||||
|
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
visible = getEditor(data)?.isEditable ?: false
|
visible = getEditor(data)?.isEditable ?: false
|
||||||
enabled = visible
|
enabled = visible
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "ideEditor_cut"
|
override val id: String = "ideEditor_cut"
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val editor = getEditor(data) ?: return false
|
val editor = getEditor(data) ?: return false
|
||||||
editor.cutText()
|
editor.cutText()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +1,44 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.editor
|
package com.itsaky.androidide.actions.editor
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.ActionItem
|
import com.itsaky.androidide.actions.ActionItem
|
||||||
import com.itsaky.androidide.actions.EditorRelatedAction
|
import com.itsaky.androidide.actions.EditorRelatedAction
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expands the current selection using the language server set in editor.
|
* Expands the current selection using the language server set in editor.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
class ExpandSelectionAction() : EditorRelatedAction() {
|
class ExpandSelectionAction() : EditorRelatedAction() {
|
||||||
override val id: String = "editor_expandSelection"
|
override val id: String = "editor_expandSelection"
|
||||||
override var location: ActionItem.Location = ActionItem.Location.EDITOR_TEXT_ACTIONS
|
override var location: ActionItem.Location = ActionItem.Location.EDITOR_TEXT_ACTIONS
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.action_expand_selection)
|
label = context.getString(R.string.action_expand_selection)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_expand_selection)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_expand_selection)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Any {
|
override fun execAction(data: ActionData): Any {
|
||||||
return getEditor(data)!!.expandSelection()
|
return getEditor(data)!!.expandSelection()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +1,54 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.editor
|
package com.itsaky.androidide.actions.editor
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseEditorAction
|
import com.itsaky.androidide.actions.BaseEditorAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class PasteAction() : BaseEditorAction() {
|
class PasteAction() : BaseEditorAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.paste)
|
label = context.getString(R.string.paste)
|
||||||
|
|
||||||
val arr = context.obtainStyledAttributes(intArrayOf(android.R.attr.actionModePasteDrawable))
|
val arr = context.obtainStyledAttributes(intArrayOf(android.R.attr.actionModePasteDrawable))
|
||||||
icon = arr.getDrawable(0)?.let { tintDrawable(context, it) }
|
icon = arr.getDrawable(0)?.let { tintDrawable(context, it) }
|
||||||
arr.recycle()
|
arr.recycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "ideEditor_paste"
|
override val id: String = "ideEditor_paste"
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
super.prepare(data)
|
super.prepare(data)
|
||||||
|
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
visible = getEditor(data)?.isEditable ?: false
|
visible = getEditor(data)?.isEditable ?: false
|
||||||
enabled = visible
|
enabled = visible
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val editor = getEditor(data) ?: return false
|
val editor = getEditor(data) ?: return false
|
||||||
editor.pasteText()
|
editor.pasteText()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +1,43 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.editor
|
package com.itsaky.androidide.actions.editor
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseEditorAction
|
import com.itsaky.androidide.actions.BaseEditorAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class SelectAllAction() : BaseEditorAction() {
|
class SelectAllAction() : BaseEditorAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.selectAll)
|
label = context.getString(R.string.selectAll)
|
||||||
|
|
||||||
val arr = context.obtainStyledAttributes(intArrayOf(android.R.attr.actionModeSelectAllDrawable))
|
val arr = context.obtainStyledAttributes(intArrayOf(android.R.attr.actionModeSelectAllDrawable))
|
||||||
icon = arr.getDrawable(0)?.let { tintDrawable(context, it) }
|
icon = arr.getDrawable(0)?.let { tintDrawable(context, it) }
|
||||||
arr.recycle()
|
arr.recycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "ideEditor_selectAll"
|
override val id: String = "ideEditor_selectAll"
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val editor = getEditor(data) ?: return false
|
val editor = getEditor(data) ?: return false
|
||||||
editor.selectAll()
|
editor.selectAll()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,45 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.editor.find
|
package com.itsaky.androidide.actions.editor.find
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 'Go to next' action in editor's search action mode.
|
* 'Go to next' action in editor's search action mode.
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
class GoToNextAction() : SearchActionModeAction() {
|
class GoToNextAction() : SearchActionModeAction() {
|
||||||
override val id: String = "editor.find.next"
|
override val id: String = "editor.find.next"
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.next)
|
label = context.getString(R.string.next)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_search_next)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_search_next)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Any {
|
override fun execAction(data: ActionData): Any {
|
||||||
val editor = getEditor(data)!!
|
val editor = getEditor(data)!!
|
||||||
if (!editor.searcher.hasQuery()) {
|
if (!editor.searcher.hasQuery()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return editor.searcher.gotoNext()
|
return editor.searcher.gotoNext()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,46 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.editor.find
|
package com.itsaky.androidide.actions.editor.find
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.R.string
|
import com.itsaky.androidide.R.string
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 'Go to previous' action in editor's search action mode.
|
* 'Go to previous' action in editor's search action mode.
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
class GoToPreviousAction() : SearchActionModeAction() {
|
class GoToPreviousAction() : SearchActionModeAction() {
|
||||||
override val id: String = "editor.find.previous"
|
override val id: String = "editor.find.previous"
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(string.previous)
|
label = context.getString(string.previous)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_search_previous)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_search_previous)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Any {
|
override fun execAction(data: ActionData): Any {
|
||||||
val editor = getEditor(data)!!
|
val editor = getEditor(data)!!
|
||||||
if (!editor.searcher.hasQuery()) {
|
if (!editor.searcher.hasQuery()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return editor.searcher.gotoPrevious()
|
return editor.searcher.gotoPrevious()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,87 +1,87 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.editor.find
|
package com.itsaky.androidide.actions.editor.find
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.databinding.LayoutEditorFindReplaceBinding
|
import com.itsaky.androidide.databinding.LayoutEditorFindReplaceBinding
|
||||||
import com.itsaky.androidide.utils.DialogUtils
|
import com.itsaky.androidide.utils.DialogUtils
|
||||||
import com.itsaky.androidide.utils.ILogger
|
import com.itsaky.androidide.utils.ILogger
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows dialog to replace one or all the matched text in editor searcher.
|
* Shows dialog to replace one or all the matched text in editor searcher.
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
class ReplaceAction() : SearchActionModeAction() {
|
class ReplaceAction() : SearchActionModeAction() {
|
||||||
|
|
||||||
override val id: String = "editor.search.replace"
|
override val id: String = "editor.search.replace"
|
||||||
private val log = ILogger.newInstance(javaClass.simpleName)
|
private val log = ILogger.newInstance(javaClass.simpleName)
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.replace)
|
label = context.getString(R.string.replace)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_search_replace)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_search_replace)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Any {
|
override fun execAction(data: ActionData): Any {
|
||||||
val context = data[Context::class.java]!!
|
val context = data[Context::class.java]!!
|
||||||
val editor = getEditor(data)!!
|
val editor = getEditor(data)!!
|
||||||
|
|
||||||
if (!editor.searcher.hasQuery()) {
|
if (!editor.searcher.hasQuery()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
val binding = LayoutEditorFindReplaceBinding.inflate(LayoutInflater.from(context))
|
val binding = LayoutEditorFindReplaceBinding.inflate(LayoutInflater.from(context))
|
||||||
val builder = DialogUtils.newMaterialDialogBuilder(context)
|
val builder = DialogUtils.newMaterialDialogBuilder(context)
|
||||||
builder.setTitle(R.string.replace)
|
builder.setTitle(R.string.replace)
|
||||||
builder.setView(binding.root)
|
builder.setView(binding.root)
|
||||||
builder.setNegativeButton(android.R.string.cancel, null)
|
builder.setNegativeButton(android.R.string.cancel, null)
|
||||||
builder.setPositiveButton(R.string.replace) { dialog, _ ->
|
builder.setPositiveButton(R.string.replace) { dialog, _ ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
val input = binding.replacementInput.editText
|
val input = binding.replacementInput.editText
|
||||||
if (input == null) {
|
if (input == null) {
|
||||||
log.error("Unable to perform replace action. Input field is null")
|
log.error("Unable to perform replace action. Input field is null")
|
||||||
return@setPositiveButton
|
return@setPositiveButton
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.searcher.replaceThis(input.text.toString())
|
editor.searcher.replaceThis(input.text.toString())
|
||||||
}
|
}
|
||||||
builder.setNeutralButton(R.string.replaceAll) { dialog, _ ->
|
builder.setNeutralButton(R.string.replaceAll) { dialog, _ ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
val input = binding.replacementInput.editText
|
val input = binding.replacementInput.editText
|
||||||
if (input == null) {
|
if (input == null) {
|
||||||
log.error("Unable to perform replace action. Input field is null")
|
log.error("Unable to perform replace action. Input field is null")
|
||||||
return@setNeutralButton
|
return@setNeutralButton
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.searcher.replaceAllAsync(input.text.toString()).whenComplete { _, error ->
|
editor.searcher.replaceAllAsync(input.text.toString()).whenComplete { _, error ->
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
log.error("Unable to replace all matched text", error)
|
log.error("Unable to replace all matched text", error)
|
||||||
} else {
|
} else {
|
||||||
editor.post { data[ActionMode::class.java]?.finish() }
|
editor.post { data[ActionMode::class.java]?.finish() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.show()
|
builder.show()
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-27
@@ -1,27 +1,27 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.editor.find
|
package com.itsaky.androidide.actions.editor.find
|
||||||
|
|
||||||
import com.itsaky.androidide.actions.ActionItem
|
import com.itsaky.androidide.actions.ActionItem
|
||||||
import com.itsaky.androidide.actions.ActionItem.Location
|
import com.itsaky.androidide.actions.ActionItem.Location
|
||||||
import com.itsaky.androidide.actions.EditorRelatedAction
|
import com.itsaky.androidide.actions.EditorRelatedAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
abstract class SearchActionModeAction : EditorRelatedAction() {
|
abstract class SearchActionModeAction : EditorRelatedAction() {
|
||||||
override var location: Location = ActionItem.Location.EDITOR_SEARCH_ACTION_MODE
|
override var location: Location = ActionItem.Location.EDITOR_SEARCH_ACTION_MODE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,46 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.etc
|
package com.itsaky.androidide.actions.etc
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.EditorActivityAction
|
import com.itsaky.androidide.actions.EditorActivityAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class DaemonStatusAction() : EditorActivityAction() {
|
class DaemonStatusAction() : EditorActivityAction() {
|
||||||
override val id: String = "editor_daemonStatus"
|
override val id: String = "editor_daemonStatus"
|
||||||
override var requiresUIThread: Boolean = true
|
override var requiresUIThread: Boolean = true
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.gradle_daemon_status)
|
label = context.getString(R.string.gradle_daemon_status)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_info)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
visible = true
|
visible = true
|
||||||
enabled = true
|
enabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val context = getActivity(data) ?: return false
|
val context = getActivity(data) ?: return false
|
||||||
context.showDaemonStatus()
|
context.showDaemonStatus()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +1,52 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.etc
|
package com.itsaky.androidide.actions.etc
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.GravityCompat
|
import androidx.core.view.GravityCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.EditorActivityAction
|
import com.itsaky.androidide.actions.EditorActivityAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class FileTreeAction() : EditorActivityAction() {
|
class FileTreeAction() : EditorActivityAction() {
|
||||||
|
|
||||||
override val id: String = "editor_fileTree"
|
override val id: String = "editor_fileTree"
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.msg_file_tree)
|
label = context.getString(R.string.msg_file_tree)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_folder)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_folder)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
visible = true
|
visible = true
|
||||||
enabled = true
|
enabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val context = getActivity(data) ?: return false
|
val context = getActivity(data) ?: return false
|
||||||
|
|
||||||
if (!context.binding.root.isDrawerOpen(GravityCompat.END)) {
|
if (!context.binding.root.isDrawerOpen(GravityCompat.END)) {
|
||||||
context.binding.root.openDrawer(GravityCompat.END)
|
context.binding.root.openDrawer(GravityCompat.END)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,46 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.etc
|
package com.itsaky.androidide.actions.etc
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.ActionItem
|
import com.itsaky.androidide.actions.ActionItem
|
||||||
import com.itsaky.androidide.actions.ActionMenu
|
import com.itsaky.androidide.actions.ActionMenu
|
||||||
import com.itsaky.androidide.actions.EditorActivityAction
|
import com.itsaky.androidide.actions.EditorActivityAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class FindActionMenu() : EditorActivityAction(), ActionMenu {
|
class FindActionMenu() : EditorActivityAction(), ActionMenu {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.menu_find)
|
label = context.getString(R.string.menu_find)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_search)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_search)
|
||||||
|
|
||||||
addAction(FindInFileAction(context))
|
addAction(FindInFileAction(context))
|
||||||
addAction(FindInProjectAction(context))
|
addAction(FindInProjectAction(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
override val children: MutableSet<ActionItem> = mutableSetOf()
|
override val children: MutableSet<ActionItem> = mutableSetOf()
|
||||||
override val id: String = "editor_findActions"
|
override val id: String = "editor_findActions"
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
visible = true
|
visible = true
|
||||||
enabled = children.size > 0
|
enabled = children.size > 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.etc
|
package com.itsaky.androidide.actions.etc
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.EditorRelatedAction
|
import com.itsaky.androidide.actions.EditorRelatedAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class FindInFileAction() : EditorRelatedAction() {
|
class FindInFileAction() : EditorRelatedAction() {
|
||||||
|
|
||||||
override val id: String = "editor_findInFile"
|
override val id: String = "editor_findInFile"
|
||||||
override var requiresUIThread: Boolean = true
|
override var requiresUIThread: Boolean = true
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.menu_find_file)
|
label = context.getString(R.string.menu_find_file)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_search_file)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_search_file)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val editor = getEditorView(data) ?: return false
|
val editor = getEditorView(data) ?: return false
|
||||||
editor.beginSearch()
|
editor.beginSearch()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +1,61 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.etc
|
package com.itsaky.androidide.actions.etc
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.EditorActivityAction
|
import com.itsaky.androidide.actions.EditorActivityAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class FindInProjectAction() : EditorActivityAction() {
|
class FindInProjectAction() : EditorActivityAction() {
|
||||||
|
|
||||||
override var requiresUIThread: Boolean = true
|
override var requiresUIThread: Boolean = true
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.menu_find_project)
|
label = context.getString(R.string.menu_find_project)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_search_project)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_search_project)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "editor_findInProject"
|
override val id: String = "editor_findInProject"
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
getActivity(data)
|
getActivity(data)
|
||||||
?: run {
|
?: run {
|
||||||
visible = false
|
visible = false
|
||||||
enabled = false
|
enabled = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
visible = true
|
visible = true
|
||||||
enabled = true
|
enabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val context = getActivity(data) ?: return false
|
val context = getActivity(data) ?: return false
|
||||||
val dialog = context.findInProjectDialog
|
val dialog = context.findInProjectDialog
|
||||||
|
|
||||||
return if (dialog != null) {
|
return if (dialog != null) {
|
||||||
dialog.show()
|
dialog.show()
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +1,62 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.etc
|
package com.itsaky.androidide.actions.etc
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.EditorRelatedAction
|
import com.itsaky.androidide.actions.EditorRelatedAction
|
||||||
import com.itsaky.androidide.handlers.FileOptionsHandler
|
import com.itsaky.androidide.handlers.FileOptionsHandler
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class PreviewLayoutAction() : EditorRelatedAction() {
|
class PreviewLayoutAction() : EditorRelatedAction() {
|
||||||
|
|
||||||
override val id: String = "editor_previewLayout"
|
override val id: String = "editor_previewLayout"
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.title_preview_layout)
|
label = context.getString(R.string.title_preview_layout)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_preview_layout)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_preview_layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
super.prepare(data)
|
super.prepare(data)
|
||||||
|
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val editor = getEditor(data)!!
|
val editor = getEditor(data)!!
|
||||||
val file = editor.file!!
|
val file = editor.file!!
|
||||||
|
|
||||||
val isXml = file.name.endsWith(".xml")
|
val isXml = file.name.endsWith(".xml")
|
||||||
|
|
||||||
visible =
|
visible =
|
||||||
isXml &&
|
isXml &&
|
||||||
file.parentFile != null &&
|
file.parentFile != null &&
|
||||||
Regex(FileOptionsHandler.LAYOUT_RES_PATH_REGEX)
|
Regex(FileOptionsHandler.LAYOUT_RES_PATH_REGEX)
|
||||||
.matches(file.parentFile!!.absolutePath)
|
.matches(file.parentFile!!.absolutePath)
|
||||||
enabled = visible
|
enabled = visible
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Any {
|
override fun execAction(data: ActionData): Any {
|
||||||
val activity = getActivity(data)!!
|
val activity = getActivity(data)!!
|
||||||
activity.previewLayout()
|
activity.previewLayout()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,46 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.file
|
package com.itsaky.androidide.actions.file
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.ActionItem
|
import com.itsaky.androidide.actions.ActionItem
|
||||||
import com.itsaky.androidide.actions.EditorRelatedAction
|
import com.itsaky.androidide.actions.EditorRelatedAction
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action that formats the code in the editor.
|
* Action that formats the code in the editor.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
class FormatCodeAction() : EditorRelatedAction() {
|
class FormatCodeAction() : EditorRelatedAction() {
|
||||||
override val id: String = "editor_file_formatCode"
|
override val id: String = "editor_file_formatCode"
|
||||||
override var location: ActionItem.Location = ActionItem.Location.EDITOR_TEXT_ACTIONS
|
override var location: ActionItem.Location = ActionItem.Location.EDITOR_TEXT_ACTIONS
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.title_format_code)
|
label = context.getString(R.string.title_format_code)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_format_code)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_format_code)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Any {
|
override fun execAction(data: ActionData): Any {
|
||||||
val editor = getEditor(data)!!
|
val editor = getEditor(data)!!
|
||||||
editor.formatCodeAsync()
|
editor.formatCodeAsync()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,86 +1,86 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.file
|
package com.itsaky.androidide.actions.file
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.EditorRelatedAction
|
import com.itsaky.androidide.actions.EditorRelatedAction
|
||||||
import com.itsaky.androidide.app.StudioApp
|
import com.itsaky.androidide.app.StudioApp
|
||||||
import com.itsaky.androidide.projects.ProjectManager
|
import com.itsaky.androidide.projects.ProjectManager
|
||||||
import com.itsaky.androidide.utils.ILogger
|
import com.itsaky.androidide.utils.ILogger
|
||||||
import com.itsaky.toaster.Toaster
|
import com.itsaky.toaster.Toaster
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class SaveFileAction() : EditorRelatedAction() {
|
class SaveFileAction() : EditorRelatedAction() {
|
||||||
|
|
||||||
private val log = ILogger.newInstance("SaveFileAction")
|
private val log = ILogger.newInstance("SaveFileAction")
|
||||||
|
|
||||||
override val id: String = "editor_saveFile"
|
override val id: String = "editor_saveFile"
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.save)
|
label = context.getString(R.string.save)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_save)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_save)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
|
|
||||||
val context =
|
val context =
|
||||||
getActivity(data)
|
getActivity(data)
|
||||||
?: run {
|
?: run {
|
||||||
visible = false
|
visible = false
|
||||||
enabled = false
|
enabled = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
visible = context.viewModel.openedFiles.isNotEmpty()
|
visible = context.viewModel.openedFiles.isNotEmpty()
|
||||||
enabled = context.areFilesModified()
|
enabled = context.areFilesModified()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val context = getActivity(data) ?: return false
|
val context = getActivity(data) ?: return false
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
// Cannot use context.saveAll() because this.execAction is called on non-UI thread
|
// Cannot use context.saveAll() because this.execAction is called on non-UI thread
|
||||||
// and saveAll call will result in UI actions
|
// and saveAll call will result in UI actions
|
||||||
val result = context.saveAllResult()
|
val result = context.saveAllResult()
|
||||||
|
|
||||||
if (result.xmlSaved) {
|
if (result.xmlSaved) {
|
||||||
ProjectManager.generateSources(context.buildService)
|
ProjectManager.generateSources(context.buildService)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.gradleSaved) {
|
if (result.gradleSaved) {
|
||||||
context.notifySyncNeeded()
|
context.notifySyncNeeded()
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
} catch (error: Throwable) {
|
} catch (error: Throwable) {
|
||||||
log.error("Failed to save file", error)
|
log.error("Failed to save file", error)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun postExec(data: ActionData, result: Any) {
|
override fun postExec(data: ActionData, result: Any) {
|
||||||
if (result is Boolean && result) {
|
if (result is Boolean && result) {
|
||||||
StudioApp.getInstance().toast(R.string.all_saved, Toaster.Type.SUCCESS)
|
StudioApp.getInstance().toast(R.string.all_saved, Toaster.Type.SUCCESS)
|
||||||
} else {
|
} else {
|
||||||
log.error("Failed to save file")
|
log.error("Failed to save file")
|
||||||
TODO("Create message in strings.xml")
|
TODO("Create message in strings.xml")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.lint
|
package com.itsaky.androidide.actions.lint
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseBuildAction
|
import com.itsaky.androidide.actions.BaseBuildAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class LintAction() : BaseBuildAction() {
|
class LintAction() : BaseBuildAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.lint)
|
label = context.getString(R.string.lint)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_lint)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_lint)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "editor_lint"
|
override val id: String = "editor_lint"
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val context = getActivity(data) ?: return false
|
val context = getActivity(data) ?: return false
|
||||||
|
|
||||||
context.lint()
|
context.lint()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.lint
|
package com.itsaky.androidide.actions.lint
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseBuildAction
|
import com.itsaky.androidide.actions.BaseBuildAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class LintDebugAction() : BaseBuildAction() {
|
class LintDebugAction() : BaseBuildAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.lint_debug)
|
label = context.getString(R.string.lint_debug)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_run_debug)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_run_debug)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "editor_lintDebug"
|
override val id: String = "editor_lintDebug"
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val context = getActivity(data) ?: return false
|
val context = getActivity(data) ?: return false
|
||||||
|
|
||||||
context.lintDebug()
|
context.lintDebug()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.lint
|
package com.itsaky.androidide.actions.lint
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.BaseBuildAction
|
import com.itsaky.androidide.actions.BaseBuildAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class LintReleaseAction() : BaseBuildAction() {
|
class LintReleaseAction() : BaseBuildAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.lint_release)
|
label = context.getString(R.string.lint_release)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_run_release)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_run_release)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "editor_lintRelease"
|
override val id: String = "editor_lintRelease"
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val context = getActivity(data) ?: return false
|
val context = getActivity(data) ?: return false
|
||||||
|
|
||||||
context.lintRelease()
|
context.lintRelease()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.lint
|
package com.itsaky.androidide.actions.lint
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionItem
|
import com.itsaky.androidide.actions.ActionItem
|
||||||
import com.itsaky.androidide.actions.ActionMenu
|
import com.itsaky.androidide.actions.ActionMenu
|
||||||
import com.itsaky.androidide.actions.BaseBuildAction
|
import com.itsaky.androidide.actions.BaseBuildAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class LintTaskMenu() : BaseBuildAction(), ActionMenu {
|
class LintTaskMenu() : BaseBuildAction(), ActionMenu {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.lint_tasks)
|
label = context.getString(R.string.lint_tasks)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_lint)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_lint)
|
||||||
|
|
||||||
addAction(LintAction(context))
|
addAction(LintAction(context))
|
||||||
addAction(LintDebugAction(context))
|
addAction(LintDebugAction(context))
|
||||||
addAction(LintReleaseAction(context))
|
addAction(LintReleaseAction(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
override val children: MutableSet<ActionItem> = mutableSetOf()
|
override val children: MutableSet<ActionItem> = mutableSetOf()
|
||||||
override val id: String = "editor_lintTasks"
|
override val id: String = "editor_lintTasks"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,63 +1,63 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.text
|
package com.itsaky.androidide.actions.text
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.blankj.utilcode.util.KeyboardUtils
|
import com.blankj.utilcode.util.KeyboardUtils
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.EditorRelatedAction
|
import com.itsaky.androidide.actions.EditorRelatedAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class RedoAction() : EditorRelatedAction() {
|
class RedoAction() : EditorRelatedAction() {
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.redo)
|
label = context.getString(R.string.redo)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_redo)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_redo)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val id: String = "editor_redo"
|
override val id: String = "editor_redo"
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
super.prepare(data)
|
super.prepare(data)
|
||||||
|
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val editor = getEditor(data)!!
|
val editor = getEditor(data)!!
|
||||||
enabled = editor.canRedo()
|
enabled = editor.canRedo()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Boolean {
|
override fun execAction(data: ActionData): Boolean {
|
||||||
val editor = getEditor(data)!!
|
val editor = getEditor(data)!!
|
||||||
editor.redo()
|
editor.redo()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getShowAsActionFlags(data: ActionData): Int {
|
override fun getShowAsActionFlags(data: ActionData): Int {
|
||||||
return if (KeyboardUtils.isSoftInputVisible(data.get(Context::class.java) as Activity)) {
|
return if (KeyboardUtils.isSoftInputVisible(data.get(Context::class.java) as Activity)) {
|
||||||
MenuItem.SHOW_AS_ACTION_IF_ROOM
|
MenuItem.SHOW_AS_ACTION_IF_ROOM
|
||||||
} else {
|
} else {
|
||||||
MenuItem.SHOW_AS_ACTION_NEVER
|
MenuItem.SHOW_AS_ACTION_NEVER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,56 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.actions.text
|
package com.itsaky.androidide.actions.text
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.EditorRelatedAction
|
import com.itsaky.androidide.actions.EditorRelatedAction
|
||||||
|
|
||||||
/** @author Akash Yadav */
|
/** @author Akash Yadav */
|
||||||
class UndoAction() : EditorRelatedAction() {
|
class UndoAction() : EditorRelatedAction() {
|
||||||
|
|
||||||
override val id: String = "editor_undo"
|
override val id: String = "editor_undo"
|
||||||
|
|
||||||
constructor(context: Context) : this() {
|
constructor(context: Context) : this() {
|
||||||
label = context.getString(R.string.undo)
|
label = context.getString(R.string.undo)
|
||||||
icon = ContextCompat.getDrawable(context, R.drawable.ic_undo)
|
icon = ContextCompat.getDrawable(context, R.drawable.ic_undo)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun prepare(data: ActionData) {
|
override fun prepare(data: ActionData) {
|
||||||
super.prepare(data)
|
super.prepare(data)
|
||||||
|
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val editor = getEditor(data)!!
|
val editor = getEditor(data)!!
|
||||||
enabled = editor.canUndo()
|
enabled = editor.canUndo()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execAction(data: ActionData): Any {
|
override fun execAction(data: ActionData): Any {
|
||||||
val editor = getEditor(data)
|
val editor = getEditor(data)
|
||||||
return if (editor != null) {
|
return if (editor != null) {
|
||||||
editor.undo()
|
editor.undo()
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,230 +1,230 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.adapters;
|
package com.itsaky.androidide.adapters;
|
||||||
|
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
import com.blankj.utilcode.util.ThreadUtils;
|
import com.blankj.utilcode.util.ThreadUtils;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.itsaky.androidide.R;
|
import com.itsaky.androidide.R;
|
||||||
import com.itsaky.androidide.app.StudioApp;
|
import com.itsaky.androidide.app.StudioApp;
|
||||||
import com.itsaky.androidide.databinding.LayoutCompletionItemBinding;
|
import com.itsaky.androidide.databinding.LayoutCompletionItemBinding;
|
||||||
import com.itsaky.androidide.utils.ILogger;
|
import com.itsaky.androidide.utils.ILogger;
|
||||||
import com.itsaky.androidide.utils.TypefaceUtils;
|
import com.itsaky.androidide.utils.TypefaceUtils;
|
||||||
import com.itsaky.apiinfo.ApiInfo;
|
import com.itsaky.apiinfo.ApiInfo;
|
||||||
import com.itsaky.apiinfo.models.ClassInfo;
|
import com.itsaky.apiinfo.models.ClassInfo;
|
||||||
import com.itsaky.apiinfo.models.FieldInfo;
|
import com.itsaky.apiinfo.models.FieldInfo;
|
||||||
import com.itsaky.apiinfo.models.Info;
|
import com.itsaky.apiinfo.models.Info;
|
||||||
import com.itsaky.apiinfo.models.MethodInfo;
|
import com.itsaky.apiinfo.models.MethodInfo;
|
||||||
import com.itsaky.lsp.models.CompletionItem;
|
import com.itsaky.lsp.models.CompletionItem;
|
||||||
import com.itsaky.lsp.models.CompletionItemKind;
|
import com.itsaky.lsp.models.CompletionItemKind;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.github.rosemoe.sora.widget.component.EditorAutoCompletion;
|
import io.github.rosemoe.sora.widget.component.EditorAutoCompletion;
|
||||||
import io.github.rosemoe.sora.widget.component.EditorCompletionAdapter;
|
import io.github.rosemoe.sora.widget.component.EditorCompletionAdapter;
|
||||||
|
|
||||||
public class CompletionListAdapter extends EditorCompletionAdapter {
|
public class CompletionListAdapter extends EditorCompletionAdapter {
|
||||||
|
|
||||||
private static final ILogger LOG = ILogger.newInstance("CompletionListAdapter");
|
private static final ILogger LOG = ILogger.newInstance("CompletionListAdapter");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void attachValues(
|
public void attachValues(
|
||||||
EditorAutoCompletion window,
|
EditorAutoCompletion window,
|
||||||
List<io.github.rosemoe.sora.lang.completion.CompletionItem> items) {
|
List<io.github.rosemoe.sora.lang.completion.CompletionItem> items) {
|
||||||
super.attachValues(window, items);
|
super.attachValues(window, items);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemHeight() {
|
public int getItemHeight() {
|
||||||
return (int)
|
return (int)
|
||||||
TypedValue.applyDimension(
|
TypedValue.applyDimension(
|
||||||
TypedValue.COMPLEX_UNIT_DIP, 40, Resources.getSystem().getDisplayMetrics());
|
TypedValue.COMPLEX_UNIT_DIP, 40, Resources.getSystem().getDisplayMetrics());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected View getView(
|
protected View getView(
|
||||||
int position, View convertView, ViewGroup parent, boolean isCurrentCursorPosition) {
|
int position, View convertView, ViewGroup parent, boolean isCurrentCursorPosition) {
|
||||||
final LayoutCompletionItemBinding binding =
|
final LayoutCompletionItemBinding binding =
|
||||||
LayoutCompletionItemBinding.inflate(LayoutInflater.from(getContext()), parent, false);
|
LayoutCompletionItemBinding.inflate(LayoutInflater.from(getContext()), parent, false);
|
||||||
|
|
||||||
var item = (CompletionItem) getItem(position);
|
var item = (CompletionItem) getItem(position);
|
||||||
String label = item.getLabel(), desc = item.getDetail(), type = item.getKind().toString();
|
String label = item.getLabel(), desc = item.getDetail(), type = item.getKind().toString();
|
||||||
String header = type.length() <= 0 ? "O" : String.valueOf(type.charAt(0));
|
String header = type.length() <= 0 ? "O" : String.valueOf(type.charAt(0));
|
||||||
|
|
||||||
binding.completionIconText.setText(header);
|
binding.completionIconText.setText(header);
|
||||||
binding.completionLabel.setText(label);
|
binding.completionLabel.setText(label);
|
||||||
binding.completionType.setText(type);
|
binding.completionType.setText(type);
|
||||||
binding.completionDetail.setText(desc);
|
binding.completionDetail.setText(desc);
|
||||||
binding.completionIconText.setTypeface(TypefaceUtils.jetbrainsMono(), Typeface.BOLD);
|
binding.completionIconText.setTypeface(TypefaceUtils.jetbrainsMono(), Typeface.BOLD);
|
||||||
if (desc.isEmpty()) {
|
if (desc.isEmpty()) {
|
||||||
binding.completionDetail.setVisibility(View.GONE);
|
binding.completionDetail.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCurrentCursorPosition) {
|
if (isCurrentCursorPosition) {
|
||||||
binding
|
binding
|
||||||
.getRoot()
|
.getRoot()
|
||||||
.setBackgroundColor(
|
.setBackgroundColor(
|
||||||
ContextCompat.getColor(getContext(), R.color.completionList_backgroundSelected));
|
ContextCompat.getColor(getContext(), R.color.completionList_backgroundSelected));
|
||||||
} else {
|
} else {
|
||||||
binding
|
binding
|
||||||
.getRoot()
|
.getRoot()
|
||||||
.setBackgroundColor(
|
.setBackgroundColor(
|
||||||
ContextCompat.getColor(getContext(), R.color.completionList_background));
|
ContextCompat.getColor(getContext(), R.color.completionList_background));
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.completionApiInfo.setVisibility(View.GONE);
|
binding.completionApiInfo.setVisibility(View.GONE);
|
||||||
|
|
||||||
showApiInfoIfNeeded(item, binding.completionApiInfo);
|
showApiInfoIfNeeded(item, binding.completionApiInfo);
|
||||||
|
|
||||||
return binding.getRoot();
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showApiInfoIfNeeded(final CompletionItem item, final TextView completionApiInfo) {
|
private void showApiInfoIfNeeded(final CompletionItem item, final TextView completionApiInfo) {
|
||||||
|
|
||||||
new Thread(
|
new Thread(
|
||||||
() -> {
|
() -> {
|
||||||
final ApiInfo apiInfo = StudioApp.getInstance().apiInfo();
|
final ApiInfo apiInfo = StudioApp.getInstance().apiInfo();
|
||||||
boolean hasRead = apiInfo != null && apiInfo.hasRead();
|
boolean hasRead = apiInfo != null && apiInfo.hasRead();
|
||||||
boolean isValid = isValidForApiVersion(item);
|
boolean isValid = isValidForApiVersion(item);
|
||||||
|
|
||||||
if (hasRead && isValid) {
|
if (hasRead && isValid) {
|
||||||
|
|
||||||
JsonElement element = new Gson().toJsonTree(item.getData());
|
JsonElement element = new Gson().toJsonTree(item.getData());
|
||||||
if (element == null || !element.isJsonObject()) {
|
if (element == null || !element.isJsonObject()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
JsonObject data = element.getAsJsonObject();
|
JsonObject data = element.getAsJsonObject();
|
||||||
if (!data.has("className")) {
|
if (!data.has("className")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String className = data.get("className").getAsString();
|
final String className = data.get("className").getAsString();
|
||||||
CompletionItemKind kind = item.getKind();
|
CompletionItemKind kind = item.getKind();
|
||||||
|
|
||||||
ClassInfo clazz = apiInfo.getClassByName(className);
|
ClassInfo clazz = apiInfo.getClassByName(className);
|
||||||
if (clazz == null) {
|
if (clazz == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Info info = clazz;
|
Info info = clazz;
|
||||||
|
|
||||||
// If this Info is not a class info, find the right member
|
// If this Info is not a class info, find the right member
|
||||||
if (kind == CompletionItemKind.METHOD
|
if (kind == CompletionItemKind.METHOD
|
||||||
&& data.has("erasedParameterTypes")
|
&& data.has("erasedParameterTypes")
|
||||||
&& data.has("memberName")) {
|
&& data.has("memberName")) {
|
||||||
JsonElement erasedParameterTypesElement = data.get("erasedParameterTypes");
|
JsonElement erasedParameterTypesElement = data.get("erasedParameterTypes");
|
||||||
if (erasedParameterTypesElement.isJsonArray()) {
|
if (erasedParameterTypesElement.isJsonArray()) {
|
||||||
String simpleName = data.get("memberName").getAsString();
|
String simpleName = data.get("memberName").getAsString();
|
||||||
JsonArray erasedParameterTypes = erasedParameterTypesElement.getAsJsonArray();
|
JsonArray erasedParameterTypes = erasedParameterTypesElement.getAsJsonArray();
|
||||||
String[] paramTypes = new String[erasedParameterTypes.size()];
|
String[] paramTypes = new String[erasedParameterTypes.size()];
|
||||||
for (int i = 0; i < erasedParameterTypes.size(); i++) {
|
for (int i = 0; i < erasedParameterTypes.size(); i++) {
|
||||||
paramTypes[i] = erasedParameterTypes.get(i).getAsString();
|
paramTypes[i] = erasedParameterTypes.get(i).getAsString();
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodInfo method = clazz.getMethod(simpleName, paramTypes);
|
MethodInfo method = clazz.getMethod(simpleName, paramTypes);
|
||||||
|
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
info = method;
|
info = method;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (kind == CompletionItemKind.FIELD && data.has("memberName")) {
|
} else if (kind == CompletionItemKind.FIELD && data.has("memberName")) {
|
||||||
String simpleName = data.get("memberName").getAsString();
|
String simpleName = data.get("memberName").getAsString();
|
||||||
FieldInfo field = clazz.getFieldByName(simpleName);
|
FieldInfo field = clazz.getFieldByName(simpleName);
|
||||||
|
|
||||||
if (field != null) {
|
if (field != null) {
|
||||||
info = field;
|
info = field;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final StringBuilder infoBuilder = new StringBuilder();
|
final StringBuilder infoBuilder = new StringBuilder();
|
||||||
if (info.since > 1) {
|
if (info.since > 1) {
|
||||||
infoBuilder.append(
|
infoBuilder.append(
|
||||||
completionApiInfo
|
completionApiInfo
|
||||||
.getContext()
|
.getContext()
|
||||||
.getString(R.string.msg_api_info_since, info.since));
|
.getString(R.string.msg_api_info_since, info.since));
|
||||||
infoBuilder.append("\n");
|
infoBuilder.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.removed > 0) {
|
if (info.removed > 0) {
|
||||||
infoBuilder.append(
|
infoBuilder.append(
|
||||||
completionApiInfo
|
completionApiInfo
|
||||||
.getContext()
|
.getContext()
|
||||||
.getString(R.string.msg_api_info_removed, info.removed));
|
.getString(R.string.msg_api_info_removed, info.removed));
|
||||||
infoBuilder.append("\n");
|
infoBuilder.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.deprecated > 0) {
|
if (info.deprecated > 0) {
|
||||||
infoBuilder.append(
|
infoBuilder.append(
|
||||||
completionApiInfo
|
completionApiInfo
|
||||||
.getContext()
|
.getContext()
|
||||||
.getString(R.string.msg_api_info_deprecated, info.deprecated));
|
.getString(R.string.msg_api_info_deprecated, info.deprecated));
|
||||||
infoBuilder.append("\n");
|
infoBuilder.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadUtils.runOnUiThread(
|
ThreadUtils.runOnUiThread(
|
||||||
() -> {
|
() -> {
|
||||||
if (infoBuilder.toString().trim().length() > 0) {
|
if (infoBuilder.toString().trim().length() > 0) {
|
||||||
completionApiInfo.setText(infoBuilder.toString().trim());
|
completionApiInfo.setText(infoBuilder.toString().trim());
|
||||||
completionApiInfo.setVisibility(View.VISIBLE);
|
completionApiInfo.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
completionApiInfo.setVisibility(View.GONE);
|
completionApiInfo.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.start();
|
.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isValidForApiVersion(CompletionItem item) {
|
private boolean isValidForApiVersion(CompletionItem item) {
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final CompletionItemKind type = item.getKind();
|
final CompletionItemKind type = item.getKind();
|
||||||
final var data = item.getData();
|
final var data = item.getData();
|
||||||
if (
|
if (
|
||||||
|
|
||||||
// These represent a class type
|
// These represent a class type
|
||||||
(type == CompletionItemKind.CLASS
|
(type == CompletionItemKind.CLASS
|
||||||
|| type == CompletionItemKind.INTERFACE
|
|| type == CompletionItemKind.INTERFACE
|
||||||
|| type == CompletionItemKind.ENUM
|
|| type == CompletionItemKind.ENUM
|
||||||
|
|
||||||
// These represent a method type
|
// These represent a method type
|
||||||
|| type == CompletionItemKind.METHOD
|
|| type == CompletionItemKind.METHOD
|
||||||
|| type == CompletionItemKind.CONSTRUCTOR
|
|| type == CompletionItemKind.CONSTRUCTOR
|
||||||
|
|
||||||
// A field type
|
// A field type
|
||||||
|| type == CompletionItemKind.FIELD)
|
|| type == CompletionItemKind.FIELD)
|
||||||
&& data != null) {
|
&& data != null) {
|
||||||
return !TextUtils.isEmpty(data.getClassName());
|
return !TextUtils.isEmpty(data.getClassName());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,319 +1,319 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.filepicker;
|
package com.itsaky.androidide.filepicker;
|
||||||
|
|
||||||
import android.content.res.AssetFileDescriptor;
|
import android.content.res.AssetFileDescriptor;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.MatrixCursor;
|
import android.database.MatrixCursor;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.os.CancellationSignal;
|
import android.os.CancellationSignal;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.provider.DocumentsContract.Document;
|
import android.provider.DocumentsContract.Document;
|
||||||
import android.provider.DocumentsContract.Root;
|
import android.provider.DocumentsContract.Root;
|
||||||
import android.provider.DocumentsProvider;
|
import android.provider.DocumentsProvider;
|
||||||
import android.webkit.MimeTypeMap;
|
import android.webkit.MimeTypeMap;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.itsaky.androidide.R;
|
import com.itsaky.androidide.R;
|
||||||
import com.itsaky.androidide.utils.Environment;
|
import com.itsaky.androidide.utils.Environment;
|
||||||
import com.itsaky.androidide.utils.ILogger;
|
import com.itsaky.androidide.utils.ILogger;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A document provider for the Storage Access Framework which exposes the files in the $HOME/
|
* A document provider for the Storage Access Framework which exposes the files in the $HOME/
|
||||||
* directory to other apps.
|
* directory to other apps.
|
||||||
*
|
*
|
||||||
* <p>Note that this replaces providing an activity matching the ACTION_GET_CONTENT intent:
|
* <p>Note that this replaces providing an activity matching the ACTION_GET_CONTENT intent:
|
||||||
*
|
*
|
||||||
* <p>"A document provider and ACTION_GET_CONTENT should be considered mutually exclusive. If you
|
* <p>"A document provider and ACTION_GET_CONTENT should be considered mutually exclusive. If you
|
||||||
* support both of them simultaneously, your app will appear twice in the system picker UI, offering
|
* support both of them simultaneously, your app will appear twice in the system picker UI, offering
|
||||||
* two different ways of accessing your stored data. This would be confusing for users." -
|
* two different ways of accessing your stored data. This would be confusing for users." -
|
||||||
* http://developer.android.com/guide/topics/providers/document-provider.html#43
|
* http://developer.android.com/guide/topics/providers/document-provider.html#43
|
||||||
*
|
*
|
||||||
* @see <a
|
* @see <a
|
||||||
* href="https://github.com/termux/termux-app/blob/master/app/src/main/java/com/termux/filepicker/TermuxDocumentsProvider.java">TermuxDocumentsProvider</a>
|
* href="https://github.com/termux/termux-app/blob/master/app/src/main/java/com/termux/filepicker/TermuxDocumentsProvider.java">TermuxDocumentsProvider</a>
|
||||||
*/
|
*/
|
||||||
public class IDEDocumentsProvider extends DocumentsProvider {
|
public class IDEDocumentsProvider extends DocumentsProvider {
|
||||||
|
|
||||||
private static final String ALL_MIME_TYPES = "*/*";
|
private static final String ALL_MIME_TYPES = "*/*";
|
||||||
private static final ILogger LOG = ILogger.newInstance("IDEDocumentsProvider");
|
private static final ILogger LOG = ILogger.newInstance("IDEDocumentsProvider");
|
||||||
private static final File BASE_DIR = getBaseDir();
|
private static final File BASE_DIR = getBaseDir();
|
||||||
// The default columns to return information about a root if no specific
|
// The default columns to return information about a root if no specific
|
||||||
// columns are requested in a query.
|
// columns are requested in a query.
|
||||||
private static final String[] DEFAULT_ROOT_PROJECTION =
|
private static final String[] DEFAULT_ROOT_PROJECTION =
|
||||||
new String[] {
|
new String[] {
|
||||||
Root.COLUMN_ROOT_ID,
|
Root.COLUMN_ROOT_ID,
|
||||||
Root.COLUMN_MIME_TYPES,
|
Root.COLUMN_MIME_TYPES,
|
||||||
Root.COLUMN_FLAGS,
|
Root.COLUMN_FLAGS,
|
||||||
Root.COLUMN_ICON,
|
Root.COLUMN_ICON,
|
||||||
Root.COLUMN_TITLE,
|
Root.COLUMN_TITLE,
|
||||||
Root.COLUMN_SUMMARY,
|
Root.COLUMN_SUMMARY,
|
||||||
Root.COLUMN_DOCUMENT_ID,
|
Root.COLUMN_DOCUMENT_ID,
|
||||||
Root.COLUMN_AVAILABLE_BYTES
|
Root.COLUMN_AVAILABLE_BYTES
|
||||||
};
|
};
|
||||||
// The default columns to return information about a document if no specific
|
// The default columns to return information about a document if no specific
|
||||||
// columns are requested in a query.
|
// columns are requested in a query.
|
||||||
private static final String[] DEFAULT_DOCUMENT_PROJECTION =
|
private static final String[] DEFAULT_DOCUMENT_PROJECTION =
|
||||||
new String[] {
|
new String[] {
|
||||||
Document.COLUMN_DOCUMENT_ID,
|
Document.COLUMN_DOCUMENT_ID,
|
||||||
Document.COLUMN_MIME_TYPE,
|
Document.COLUMN_MIME_TYPE,
|
||||||
Document.COLUMN_DISPLAY_NAME,
|
Document.COLUMN_DISPLAY_NAME,
|
||||||
Document.COLUMN_LAST_MODIFIED,
|
Document.COLUMN_LAST_MODIFIED,
|
||||||
Document.COLUMN_FLAGS,
|
Document.COLUMN_FLAGS,
|
||||||
Document.COLUMN_SIZE
|
Document.COLUMN_SIZE
|
||||||
};
|
};
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private static File getBaseDir() {
|
private static File getBaseDir() {
|
||||||
if (Environment.HOME != null) {
|
if (Environment.HOME != null) {
|
||||||
return Environment.HOME;
|
return Environment.HOME;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new File(Environment.DEFAULT_HOME);
|
return new File(Environment.DEFAULT_HOME);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the document id given a file. This document id must be consistent across time as other
|
* Get the document id given a file. This document id must be consistent across time as other
|
||||||
* applications may save the ID and use it to reference documents later.
|
* applications may save the ID and use it to reference documents later.
|
||||||
*
|
*
|
||||||
* <p>The reverse of @{link #getFileForDocId}.
|
* <p>The reverse of @{link #getFileForDocId}.
|
||||||
*/
|
*/
|
||||||
private static String getDocIdForFile(File file) {
|
private static String getDocIdForFile(File file) {
|
||||||
return file.getAbsolutePath();
|
return file.getAbsolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the file given a document id (the reverse of {@link #getDocIdForFile(File)}). */
|
/** Get the file given a document id (the reverse of {@link #getDocIdForFile(File)}). */
|
||||||
private static File getFileForDocId(String docId) throws FileNotFoundException {
|
private static File getFileForDocId(String docId) throws FileNotFoundException {
|
||||||
final File f = new File(docId);
|
final File f = new File(docId);
|
||||||
if (!f.exists()) throw new FileNotFoundException(f.getAbsolutePath() + " not found");
|
if (!f.exists()) throw new FileNotFoundException(f.getAbsolutePath() + " not found");
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getMimeType(File file) {
|
private static String getMimeType(File file) {
|
||||||
if (file.isDirectory()) {
|
if (file.isDirectory()) {
|
||||||
return Document.MIME_TYPE_DIR;
|
return Document.MIME_TYPE_DIR;
|
||||||
} else {
|
} else {
|
||||||
final String name = file.getName();
|
final String name = file.getName();
|
||||||
final int lastDot = name.lastIndexOf('.');
|
final int lastDot = name.lastIndexOf('.');
|
||||||
if (lastDot >= 0) {
|
if (lastDot >= 0) {
|
||||||
final String extension = name.substring(lastDot + 1).toLowerCase();
|
final String extension = name.substring(lastDot + 1).toLowerCase();
|
||||||
final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||||
if (mime != null) return mime;
|
if (mime != null) return mime;
|
||||||
}
|
}
|
||||||
return "application/octet-stream";
|
return "application/octet-stream";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Cursor queryRoots(String[] projection) {
|
public Cursor queryRoots(String[] projection) {
|
||||||
final MatrixCursor result =
|
final MatrixCursor result =
|
||||||
new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
|
new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
|
||||||
final String applicationName = getContext().getString(R.string.app_name);
|
final String applicationName = getContext().getString(R.string.app_name);
|
||||||
|
|
||||||
final MatrixCursor.RowBuilder row = result.newRow();
|
final MatrixCursor.RowBuilder row = result.newRow();
|
||||||
LOG.debug("queryRoots() before all add");
|
LOG.debug("queryRoots() before all add");
|
||||||
row.add(Root.COLUMN_ROOT_ID, getDocIdForFile(BASE_DIR));
|
row.add(Root.COLUMN_ROOT_ID, getDocIdForFile(BASE_DIR));
|
||||||
LOG.debug("queryRoots() before all add, 1");
|
LOG.debug("queryRoots() before all add, 1");
|
||||||
row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(BASE_DIR));
|
row.add(Root.COLUMN_DOCUMENT_ID, getDocIdForFile(BASE_DIR));
|
||||||
LOG.debug("queryRoots() before all add, 2");
|
LOG.debug("queryRoots() before all add, 2");
|
||||||
row.add(Root.COLUMN_SUMMARY, null);
|
row.add(Root.COLUMN_SUMMARY, null);
|
||||||
LOG.debug("queryRoots() before all add, 3");
|
LOG.debug("queryRoots() before all add, 3");
|
||||||
row.add(
|
row.add(
|
||||||
Root.COLUMN_FLAGS,
|
Root.COLUMN_FLAGS,
|
||||||
Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD);
|
Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD);
|
||||||
LOG.debug("queryRoots() before all add, 4");
|
LOG.debug("queryRoots() before all add, 4");
|
||||||
row.add(Root.COLUMN_TITLE, applicationName);
|
row.add(Root.COLUMN_TITLE, applicationName);
|
||||||
LOG.debug("queryRoots() before all add, 5");
|
LOG.debug("queryRoots() before all add, 5");
|
||||||
row.add(Root.COLUMN_MIME_TYPES, ALL_MIME_TYPES);
|
row.add(Root.COLUMN_MIME_TYPES, ALL_MIME_TYPES);
|
||||||
LOG.debug("queryRoots() before all add, 6");
|
LOG.debug("queryRoots() before all add, 6");
|
||||||
row.add(Root.COLUMN_AVAILABLE_BYTES, BASE_DIR.getFreeSpace());
|
row.add(Root.COLUMN_AVAILABLE_BYTES, BASE_DIR.getFreeSpace());
|
||||||
LOG.debug("queryRoots() before all add, 7");
|
LOG.debug("queryRoots() before all add, 7");
|
||||||
row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher);
|
row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher);
|
||||||
LOG.debug("queryRoots() before all add");
|
LOG.debug("queryRoots() before all add");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException {
|
public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException {
|
||||||
final MatrixCursor result =
|
final MatrixCursor result =
|
||||||
new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
|
new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
|
||||||
includeFile(result, documentId, null);
|
includeFile(result, documentId, null);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder)
|
public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder)
|
||||||
throws FileNotFoundException {
|
throws FileNotFoundException {
|
||||||
final MatrixCursor result =
|
final MatrixCursor result =
|
||||||
new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
|
new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
|
||||||
final File parent = getFileForDocId(parentDocumentId);
|
final File parent = getFileForDocId(parentDocumentId);
|
||||||
for (File file : parent.listFiles()) {
|
for (File file : parent.listFiles()) {
|
||||||
includeFile(result, null, file);
|
includeFile(result, null, file);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ParcelFileDescriptor openDocument(
|
public ParcelFileDescriptor openDocument(
|
||||||
final String documentId, String mode, CancellationSignal signal)
|
final String documentId, String mode, CancellationSignal signal)
|
||||||
throws FileNotFoundException {
|
throws FileNotFoundException {
|
||||||
final File file = getFileForDocId(documentId);
|
final File file = getFileForDocId(documentId);
|
||||||
final int accessMode = ParcelFileDescriptor.parseMode(mode);
|
final int accessMode = ParcelFileDescriptor.parseMode(mode);
|
||||||
return ParcelFileDescriptor.open(file, accessMode);
|
return ParcelFileDescriptor.open(file, accessMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AssetFileDescriptor openDocumentThumbnail(
|
public AssetFileDescriptor openDocumentThumbnail(
|
||||||
String documentId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException {
|
String documentId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException {
|
||||||
final File file = getFileForDocId(documentId);
|
final File file = getFileForDocId(documentId);
|
||||||
final ParcelFileDescriptor pfd =
|
final ParcelFileDescriptor pfd =
|
||||||
ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
|
ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
|
||||||
return new AssetFileDescriptor(pfd, 0, file.length());
|
return new AssetFileDescriptor(pfd, 0, file.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreate() {
|
public boolean onCreate() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String createDocument(String parentDocumentId, String mimeType, String displayName)
|
public String createDocument(String parentDocumentId, String mimeType, String displayName)
|
||||||
throws FileNotFoundException {
|
throws FileNotFoundException {
|
||||||
File newFile = new File(parentDocumentId, displayName);
|
File newFile = new File(parentDocumentId, displayName);
|
||||||
int noConflictId = 2;
|
int noConflictId = 2;
|
||||||
while (newFile.exists()) {
|
while (newFile.exists()) {
|
||||||
newFile = new File(parentDocumentId, displayName + " (" + noConflictId++ + ")");
|
newFile = new File(parentDocumentId, displayName + " (" + noConflictId++ + ")");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
boolean succeeded;
|
boolean succeeded;
|
||||||
if (Document.MIME_TYPE_DIR.equals(mimeType)) {
|
if (Document.MIME_TYPE_DIR.equals(mimeType)) {
|
||||||
succeeded = newFile.mkdir();
|
succeeded = newFile.mkdir();
|
||||||
} else {
|
} else {
|
||||||
succeeded = newFile.createNewFile();
|
succeeded = newFile.createNewFile();
|
||||||
}
|
}
|
||||||
if (!succeeded) {
|
if (!succeeded) {
|
||||||
throw new FileNotFoundException("Failed to create document with id " + newFile.getPath());
|
throw new FileNotFoundException("Failed to create document with id " + newFile.getPath());
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new FileNotFoundException("Failed to create document with id " + newFile.getPath());
|
throw new FileNotFoundException("Failed to create document with id " + newFile.getPath());
|
||||||
}
|
}
|
||||||
return newFile.getPath();
|
return newFile.getPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteDocument(String documentId) throws FileNotFoundException {
|
public void deleteDocument(String documentId) throws FileNotFoundException {
|
||||||
File file = getFileForDocId(documentId);
|
File file = getFileForDocId(documentId);
|
||||||
if (!file.delete()) {
|
if (!file.delete()) {
|
||||||
throw new FileNotFoundException("Failed to delete document with id " + documentId);
|
throw new FileNotFoundException("Failed to delete document with id " + documentId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDocumentType(String documentId) throws FileNotFoundException {
|
public String getDocumentType(String documentId) throws FileNotFoundException {
|
||||||
File file = getFileForDocId(documentId);
|
File file = getFileForDocId(documentId);
|
||||||
return getMimeType(file);
|
return getMimeType(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Cursor querySearchDocuments(String rootId, String query, String[] projection)
|
public Cursor querySearchDocuments(String rootId, String query, String[] projection)
|
||||||
throws FileNotFoundException {
|
throws FileNotFoundException {
|
||||||
final MatrixCursor result =
|
final MatrixCursor result =
|
||||||
new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
|
new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
|
||||||
final File parent = getFileForDocId(rootId);
|
final File parent = getFileForDocId(rootId);
|
||||||
|
|
||||||
// This example implementation searches file names for the query and doesn't rank search
|
// This example implementation searches file names for the query and doesn't rank search
|
||||||
// results, so we can stop as soon as we find a sufficient number of matches. Other
|
// results, so we can stop as soon as we find a sufficient number of matches. Other
|
||||||
// implementations might rank results and use other data about files, rather than the file
|
// implementations might rank results and use other data about files, rather than the file
|
||||||
// name, to produce a match.
|
// name, to produce a match.
|
||||||
final LinkedList<File> pending = new LinkedList<>();
|
final LinkedList<File> pending = new LinkedList<>();
|
||||||
pending.add(parent);
|
pending.add(parent);
|
||||||
|
|
||||||
final int MAX_SEARCH_RESULTS = 50;
|
final int MAX_SEARCH_RESULTS = 50;
|
||||||
while (!pending.isEmpty() && result.getCount() < MAX_SEARCH_RESULTS) {
|
while (!pending.isEmpty() && result.getCount() < MAX_SEARCH_RESULTS) {
|
||||||
final File file = pending.removeFirst();
|
final File file = pending.removeFirst();
|
||||||
// Avoid directories outside the $HOME directory linked with symlinks (to avoid e.g.
|
// Avoid directories outside the $HOME directory linked with symlinks (to avoid e.g.
|
||||||
// search
|
// search
|
||||||
// through the whole SD card).
|
// through the whole SD card).
|
||||||
boolean isInsideHome;
|
boolean isInsideHome;
|
||||||
try {
|
try {
|
||||||
isInsideHome = file.getCanonicalPath().startsWith(Environment.HOME.getAbsolutePath());
|
isInsideHome = file.getCanonicalPath().startsWith(Environment.HOME.getAbsolutePath());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
isInsideHome = true;
|
isInsideHome = true;
|
||||||
}
|
}
|
||||||
if (isInsideHome) {
|
if (isInsideHome) {
|
||||||
if (file.isDirectory()) {
|
if (file.isDirectory()) {
|
||||||
Collections.addAll(pending, file.listFiles());
|
Collections.addAll(pending, file.listFiles());
|
||||||
} else {
|
} else {
|
||||||
if (file.getName().toLowerCase().contains(query)) {
|
if (file.getName().toLowerCase().contains(query)) {
|
||||||
includeFile(result, null, file);
|
includeFile(result, null, file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isChildDocument(String parentDocumentId, String documentId) {
|
public boolean isChildDocument(String parentDocumentId, String documentId) {
|
||||||
return documentId.startsWith(parentDocumentId);
|
return documentId.startsWith(parentDocumentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a representation of a file to a cursor.
|
* Add a representation of a file to a cursor.
|
||||||
*
|
*
|
||||||
* @param result the cursor to modify
|
* @param result the cursor to modify
|
||||||
* @param docId the document ID representing the desired file (may be null if given file)
|
* @param docId the document ID representing the desired file (may be null if given file)
|
||||||
* @param file the File object representing the desired file (may be null if given docID)
|
* @param file the File object representing the desired file (may be null if given docID)
|
||||||
*/
|
*/
|
||||||
private void includeFile(MatrixCursor result, String docId, File file)
|
private void includeFile(MatrixCursor result, String docId, File file)
|
||||||
throws FileNotFoundException {
|
throws FileNotFoundException {
|
||||||
if (docId == null) {
|
if (docId == null) {
|
||||||
docId = getDocIdForFile(file);
|
docId = getDocIdForFile(file);
|
||||||
} else {
|
} else {
|
||||||
file = getFileForDocId(docId);
|
file = getFileForDocId(docId);
|
||||||
}
|
}
|
||||||
|
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
if (file.isDirectory()) {
|
if (file.isDirectory()) {
|
||||||
if (file.canWrite()) flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
|
if (file.canWrite()) flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
|
||||||
} else if (file.canWrite()) {
|
} else if (file.canWrite()) {
|
||||||
flags |= Document.FLAG_SUPPORTS_WRITE;
|
flags |= Document.FLAG_SUPPORTS_WRITE;
|
||||||
}
|
}
|
||||||
if (file.getParentFile().canWrite()) flags |= Document.FLAG_SUPPORTS_DELETE;
|
if (file.getParentFile().canWrite()) flags |= Document.FLAG_SUPPORTS_DELETE;
|
||||||
|
|
||||||
final String displayName = file.getName();
|
final String displayName = file.getName();
|
||||||
final String mimeType = getMimeType(file);
|
final String mimeType = getMimeType(file);
|
||||||
if (mimeType.startsWith("image/")) flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
|
if (mimeType.startsWith("image/")) flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
|
||||||
|
|
||||||
final MatrixCursor.RowBuilder row = result.newRow();
|
final MatrixCursor.RowBuilder row = result.newRow();
|
||||||
row.add(Document.COLUMN_DOCUMENT_ID, docId);
|
row.add(Document.COLUMN_DOCUMENT_ID, docId);
|
||||||
row.add(Document.COLUMN_DISPLAY_NAME, displayName);
|
row.add(Document.COLUMN_DISPLAY_NAME, displayName);
|
||||||
row.add(Document.COLUMN_SIZE, file.length());
|
row.add(Document.COLUMN_SIZE, file.length());
|
||||||
row.add(Document.COLUMN_MIME_TYPE, mimeType);
|
row.add(Document.COLUMN_MIME_TYPE, mimeType);
|
||||||
row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified());
|
row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified());
|
||||||
row.add(Document.COLUMN_FLAGS, flags);
|
row.add(Document.COLUMN_FLAGS, flags);
|
||||||
row.add(Document.COLUMN_ICON, R.mipmap.ic_launcher);
|
row.add(Document.COLUMN_ICON, R.mipmap.ic_launcher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,340 +1,340 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.fragments;
|
package com.itsaky.androidide.fragments;
|
||||||
|
|
||||||
import static com.unnamed.b.atv.view.AndroidTreeView.NODES_PATH_SEPARATOR;
|
import static com.unnamed.b.atv.view.AndroidTreeView.NODES_PATH_SEPARATOR;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.HorizontalScrollView;
|
import android.widget.HorizontalScrollView;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.transition.ChangeBounds;
|
import androidx.transition.ChangeBounds;
|
||||||
import androidx.transition.TransitionManager;
|
import androidx.transition.TransitionManager;
|
||||||
|
|
||||||
import com.blankj.utilcode.util.FileIOUtils;
|
import com.blankj.utilcode.util.FileIOUtils;
|
||||||
import com.blankj.utilcode.util.FileUtils;
|
import com.blankj.utilcode.util.FileUtils;
|
||||||
import com.blankj.utilcode.util.IntentUtils;
|
import com.blankj.utilcode.util.IntentUtils;
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||||
import com.itsaky.androidide.R;
|
import com.itsaky.androidide.R;
|
||||||
import com.itsaky.androidide.adapters.viewholders.FileTreeViewHolder;
|
import com.itsaky.androidide.adapters.viewholders.FileTreeViewHolder;
|
||||||
import com.itsaky.androidide.app.StudioApp;
|
import com.itsaky.androidide.app.StudioApp;
|
||||||
import com.itsaky.androidide.databinding.LayoutEditorFileTreeBinding;
|
import com.itsaky.androidide.databinding.LayoutEditorFileTreeBinding;
|
||||||
import com.itsaky.androidide.projects.ProjectManager;
|
import com.itsaky.androidide.projects.ProjectManager;
|
||||||
import com.itsaky.androidide.tasks.TaskExecutor;
|
import com.itsaky.androidide.tasks.TaskExecutor;
|
||||||
import com.itsaky.androidide.tasks.callables.FileTreeCallable;
|
import com.itsaky.androidide.tasks.callables.FileTreeCallable;
|
||||||
import com.itsaky.androidide.utils.Environment;
|
import com.itsaky.androidide.utils.Environment;
|
||||||
import com.itsaky.androidide.utils.ILogger;
|
import com.itsaky.androidide.utils.ILogger;
|
||||||
import com.itsaky.androidide.views.editor.CodeEditorView;
|
import com.itsaky.androidide.views.editor.CodeEditorView;
|
||||||
import com.itsaky.toaster.Toaster;
|
import com.itsaky.toaster.Toaster;
|
||||||
import com.unnamed.b.atv.model.TreeNode;
|
import com.unnamed.b.atv.model.TreeNode;
|
||||||
import com.unnamed.b.atv.view.AndroidTreeView;
|
import com.unnamed.b.atv.view.AndroidTreeView;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class FileTreeFragment extends BottomSheetDialogFragment
|
public class FileTreeFragment extends BottomSheetDialogFragment
|
||||||
implements TreeNode.TreeNodeClickListener, TreeNode.TreeNodeLongClickListener {
|
implements TreeNode.TreeNodeClickListener, TreeNode.TreeNodeLongClickListener {
|
||||||
|
|
||||||
private static final String KEY_STORED_TREE_STATE = "fileTree_state";
|
private static final String KEY_STORED_TREE_STATE = "fileTree_state";
|
||||||
private static final ILogger LOG = ILogger.newInstance("FileTreeFragment");
|
private static final ILogger LOG = ILogger.newInstance("FileTreeFragment");
|
||||||
private LayoutEditorFileTreeBinding binding;
|
private LayoutEditorFileTreeBinding binding;
|
||||||
private AndroidTreeView mFileTreeView;
|
private AndroidTreeView mFileTreeView;
|
||||||
private FileActionListener mFileActionListener;
|
private FileActionListener mFileActionListener;
|
||||||
private TreeNode mRoot;
|
private TreeNode mRoot;
|
||||||
private String mTreeState;
|
private String mTreeState;
|
||||||
|
|
||||||
public FileTreeFragment() {}
|
public FileTreeFragment() {}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static FileTreeFragment newInstance() {
|
public static FileTreeFragment newInstance() {
|
||||||
return new FileTreeFragment();
|
return new FileTreeFragment();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(@NonNull Context context) {
|
public void onAttach(@NonNull Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
mFileActionListener = (FileActionListener) context;
|
mFileActionListener = (FileActionListener) context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
saveTreeState();
|
saveTreeState();
|
||||||
outState.putString(KEY_STORED_TREE_STATE, mTreeState);
|
outState.putString(KEY_STORED_TREE_STATE, mTreeState);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveTreeState() {
|
public void saveTreeState() {
|
||||||
if (mFileTreeView != null) {
|
if (mFileTreeView != null) {
|
||||||
mTreeState = mFileTreeView.getSaveState();
|
mTreeState = mFileTreeView.getSaveState();
|
||||||
} else {
|
} else {
|
||||||
LOG.error("Unable to save tree state. TreeView is null.");
|
LOG.error("Unable to save tree state. TreeView is null.");
|
||||||
mTreeState = null;
|
mTreeState = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(
|
public View onCreateView(
|
||||||
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
binding = LayoutEditorFileTreeBinding.inflate(inflater, container, false);
|
binding = LayoutEditorFileTreeBinding.inflate(inflater, container, false);
|
||||||
return binding.getRoot();
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
if (savedInstanceState != null && savedInstanceState.containsKey(KEY_STORED_TREE_STATE)) {
|
if (savedInstanceState != null && savedInstanceState.containsKey(KEY_STORED_TREE_STATE)) {
|
||||||
mTreeState = savedInstanceState.getString(KEY_STORED_TREE_STATE, null);
|
mTreeState = savedInstanceState.getString(KEY_STORED_TREE_STATE, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
listProjectFiles();
|
listProjectFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(TreeNode node, Object p2) {
|
public void onClick(TreeNode node, Object p2) {
|
||||||
final File f = (File) p2;
|
final File f = (File) p2;
|
||||||
if (!f.exists()) {
|
if (!f.exists()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f.isFile()) {
|
if (f.isFile()) {
|
||||||
if (f.getName().endsWith(".apk")) {
|
if (f.getName().endsWith(".apk")) {
|
||||||
final var intent = IntentUtils.getInstallAppIntent(f);
|
final var intent = IntentUtils.getInstallAppIntent(f);
|
||||||
if (intent != null) {
|
if (intent != null) {
|
||||||
requireContext().startActivity(intent);
|
requireContext().startActivity(intent);
|
||||||
} else {
|
} else {
|
||||||
StudioApp.getInstance()
|
StudioApp.getInstance()
|
||||||
.toast(getString(R.string.msg_apk_install_intent_failed), Toaster.Type.ERROR);
|
.toast(getString(R.string.msg_apk_install_intent_failed), Toaster.Type.ERROR);
|
||||||
}
|
}
|
||||||
} else if (mFileActionListener != null && (FileUtils.isUtf8(f) || f.length() == 0)) {
|
} else if (mFileActionListener != null && (FileUtils.isUtf8(f) || f.length() == 0)) {
|
||||||
mFileActionListener.openFile(f);
|
mFileActionListener.openFile(f);
|
||||||
}
|
}
|
||||||
} else if (f.isDirectory() && f.exists()) {
|
} else if (f.isDirectory() && f.exists()) {
|
||||||
if (node.isExpanded()) {
|
if (node.isExpanded()) {
|
||||||
collapseNode(node);
|
collapseNode(node);
|
||||||
} else if (f.getAbsolutePath().equals(Environment.GRADLE_USER_HOME.getAbsolutePath())
|
} else if (f.getAbsolutePath().equals(Environment.GRADLE_USER_HOME.getAbsolutePath())
|
||||||
&& !node.isExpanded()) {
|
&& !node.isExpanded()) {
|
||||||
expandNode(node);
|
expandNode(node);
|
||||||
} else {
|
} else {
|
||||||
setLoading(node);
|
setLoading(node);
|
||||||
listNode(
|
listNode(
|
||||||
node,
|
node,
|
||||||
() -> {
|
() -> {
|
||||||
updateChevron(node);
|
updateChevron(node);
|
||||||
expandNode(node);
|
expandNode(node);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void collapseNode(TreeNode node) {
|
public void collapseNode(TreeNode node) {
|
||||||
if (mFileTreeView == null) {
|
if (mFileTreeView == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransitionManager.beginDelayedTransition(binding.getRoot(), new ChangeBounds());
|
TransitionManager.beginDelayedTransition(binding.getRoot(), new ChangeBounds());
|
||||||
mFileTreeView.collapseNode(node);
|
mFileTreeView.collapseNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void expandNode(TreeNode node) {
|
public void expandNode(TreeNode node) {
|
||||||
if (mFileTreeView == null) {
|
if (mFileTreeView == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransitionManager.beginDelayedTransition(binding.getRoot(), new ChangeBounds());
|
TransitionManager.beginDelayedTransition(binding.getRoot(), new ChangeBounds());
|
||||||
mFileTreeView.expandNode(node);
|
mFileTreeView.expandNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setLoading(@NonNull TreeNode node) {
|
private void setLoading(@NonNull TreeNode node) {
|
||||||
if (node.getViewHolder() instanceof FileTreeViewHolder) {
|
if (node.getViewHolder() instanceof FileTreeViewHolder) {
|
||||||
((FileTreeViewHolder) node.getViewHolder()).setLoading();
|
((FileTreeViewHolder) node.getViewHolder()).setLoading();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void listNode(@NonNull TreeNode node, Runnable whenDone) {
|
private void listNode(@NonNull TreeNode node, Runnable whenDone) {
|
||||||
|
|
||||||
if (whenDone == null) {
|
if (whenDone == null) {
|
||||||
whenDone = () -> {};
|
whenDone = () -> {};
|
||||||
}
|
}
|
||||||
|
|
||||||
node.getChildren().clear();
|
node.getChildren().clear();
|
||||||
node.setExpanded(false);
|
node.setExpanded(false);
|
||||||
|
|
||||||
final var finalWhenDone = whenDone;
|
final var finalWhenDone = whenDone;
|
||||||
TaskExecutor.execAsync(
|
TaskExecutor.execAsync(
|
||||||
() -> {
|
() -> {
|
||||||
getNodeFromFiles(node.getValue().listFiles(), node);
|
getNodeFromFiles(node.getValue().listFiles(), node);
|
||||||
TreeNode temp = node;
|
TreeNode temp = node;
|
||||||
while (temp.size() == 1) {
|
while (temp.size() == 1) {
|
||||||
temp = temp.childAt(0);
|
temp = temp.childAt(0);
|
||||||
if (!temp.getValue().isDirectory()) {
|
if (!temp.getValue().isDirectory()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
getNodeFromFiles(temp.getValue().listFiles(), temp);
|
getNodeFromFiles(temp.getValue().listFiles(), temp);
|
||||||
temp.setExpanded(true);
|
temp.setExpanded(true);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
__ -> finalWhenDone.run());
|
__ -> finalWhenDone.run());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateChevron(@NonNull TreeNode node) {
|
private void updateChevron(@NonNull TreeNode node) {
|
||||||
if (node.getViewHolder() instanceof FileTreeViewHolder) {
|
if (node.getViewHolder() instanceof FileTreeViewHolder) {
|
||||||
((FileTreeViewHolder) node.getViewHolder()).updateChevron(!node.isExpanded());
|
((FileTreeViewHolder) node.getViewHolder()).updateChevron(!node.isExpanded());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getNodeFromFiles(File[] files, TreeNode parent) {
|
private void getNodeFromFiles(File[] files, TreeNode parent) {
|
||||||
Arrays.sort(files, new FileTreeCallable.SortFileName());
|
Arrays.sort(files, new FileTreeCallable.SortFileName());
|
||||||
Arrays.sort(files, new FileTreeCallable.SortFolder());
|
Arrays.sort(files, new FileTreeCallable.SortFolder());
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
TreeNode node = new TreeNode(file);
|
TreeNode node = new TreeNode(file);
|
||||||
node.setViewHolder(new FileTreeViewHolder(getContext()));
|
node.setViewHolder(new FileTreeViewHolder(getContext()));
|
||||||
parent.addChild(node);
|
parent.addChild(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onLongClick(TreeNode node, Object value) {
|
public boolean onLongClick(TreeNode node, Object value) {
|
||||||
if (mFileActionListener != null) {
|
if (mFileActionListener != null) {
|
||||||
mFileActionListener.showFileOptions((File) value, node);
|
mFileActionListener.showFileOptions((File) value, node);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void listProjectFiles() {
|
public void listProjectFiles() {
|
||||||
final var projectDirPath = ProjectManager.INSTANCE.getProjectDirPath();
|
final var projectDirPath = ProjectManager.INSTANCE.getProjectDirPath();
|
||||||
if (projectDirPath == null) {
|
if (projectDirPath == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final File gradleProps = Environment.GRADLE_PROPS;
|
final File gradleProps = Environment.GRADLE_PROPS;
|
||||||
final File gradleHome = Environment.GRADLE_USER_HOME;
|
final File gradleHome = Environment.GRADLE_USER_HOME;
|
||||||
File projectDir = new File(projectDirPath);
|
File projectDir = new File(projectDirPath);
|
||||||
mRoot = TreeNode.root(projectDir);
|
mRoot = TreeNode.root(projectDir);
|
||||||
if (gradleHome.exists() && gradleHome.isDirectory()) {
|
if (gradleHome.exists() && gradleHome.isDirectory()) {
|
||||||
if (!gradleProps.exists()) {
|
if (!gradleProps.exists()) {
|
||||||
FileIOUtils.writeFileFromString(
|
FileIOUtils.writeFileFromString(
|
||||||
gradleProps,
|
gradleProps,
|
||||||
"# Specify global Gradle properties in this file\n"
|
"# Specify global Gradle properties in this file\n"
|
||||||
+ "# These properties will be applicable for every project you build"
|
+ "# These properties will be applicable for every project you build"
|
||||||
+ " with Gradle.");
|
+ " with Gradle.");
|
||||||
}
|
}
|
||||||
TreeNode home = new TreeNode(gradleHome);
|
TreeNode home = new TreeNode(gradleHome);
|
||||||
home.setViewHolder(new FileTreeViewHolder(getContext()));
|
home.setViewHolder(new FileTreeViewHolder(getContext()));
|
||||||
TreeNode prop = new TreeNode(gradleProps);
|
TreeNode prop = new TreeNode(gradleProps);
|
||||||
prop.setViewHolder(new FileTreeViewHolder(getContext()));
|
prop.setViewHolder(new FileTreeViewHolder(getContext()));
|
||||||
home.addChild(prop);
|
home.addChild(prop);
|
||||||
mRoot.addChild(home);
|
mRoot.addChild(home);
|
||||||
}
|
}
|
||||||
mRoot.setViewHolder(new FileTreeViewHolder(getContext()));
|
mRoot.setViewHolder(new FileTreeViewHolder(getContext()));
|
||||||
|
|
||||||
getScrollView().setVisibility(View.GONE);
|
getScrollView().setVisibility(View.GONE);
|
||||||
getLoadingProgress().setVisibility(View.VISIBLE);
|
getLoadingProgress().setVisibility(View.VISIBLE);
|
||||||
new TaskExecutor()
|
new TaskExecutor()
|
||||||
.executeAsync(
|
.executeAsync(
|
||||||
new FileTreeCallable(getContext(), mRoot, projectDir),
|
new FileTreeCallable(getContext(), mRoot, projectDir),
|
||||||
(result) -> {
|
(result) -> {
|
||||||
getScrollView().setVisibility(View.VISIBLE);
|
getScrollView().setVisibility(View.VISIBLE);
|
||||||
getLoadingProgress().setVisibility(View.GONE);
|
getLoadingProgress().setVisibility(View.GONE);
|
||||||
AndroidTreeView tree = createTreeView(mRoot);
|
AndroidTreeView tree = createTreeView(mRoot);
|
||||||
if (tree != null) {
|
if (tree != null) {
|
||||||
tree.setUseAutoToggle(false);
|
tree.setUseAutoToggle(false);
|
||||||
tree.setDefaultNodeClickListener(FileTreeFragment.this);
|
tree.setDefaultNodeClickListener(FileTreeFragment.this);
|
||||||
tree.setDefaultNodeLongClickListener(FileTreeFragment.this);
|
tree.setDefaultNodeLongClickListener(FileTreeFragment.this);
|
||||||
getScrollView().removeAllViews();
|
getScrollView().removeAllViews();
|
||||||
|
|
||||||
final var view = tree.getView();
|
final var view = tree.getView();
|
||||||
getScrollView().addView(view);
|
getScrollView().addView(view);
|
||||||
|
|
||||||
view.post(this::tryRestoreState);
|
view.post(this::tryRestoreState);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public AndroidTreeView createTreeView(TreeNode node) {
|
public AndroidTreeView createTreeView(TreeNode node) {
|
||||||
Context ctx = null;
|
Context ctx = null;
|
||||||
if (getActivity() != null) {
|
if (getActivity() != null) {
|
||||||
ctx = getActivity();
|
ctx = getActivity();
|
||||||
} else if (getContext() != null) {
|
} else if (getContext() != null) {
|
||||||
ctx = getContext();
|
ctx = getContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx == null) {
|
if (ctx == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mFileTreeView = new AndroidTreeView(ctx, node, R.drawable.bg_ripple);
|
return mFileTreeView = new AndroidTreeView(ctx, node, R.drawable.bg_ripple);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HorizontalScrollView getScrollView() {
|
public HorizontalScrollView getScrollView() {
|
||||||
return binding.filetreeHorizontalScrollView;
|
return binding.filetreeHorizontalScrollView;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProgressBar getLoadingProgress() {
|
public ProgressBar getLoadingProgress() {
|
||||||
return binding.fileTreeLoadingProgress;
|
return binding.fileTreeLoadingProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryRestoreState() {
|
private void tryRestoreState() {
|
||||||
tryRestoreState(mTreeState);
|
tryRestoreState(mTreeState);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryRestoreState(String state) {
|
private void tryRestoreState(String state) {
|
||||||
if (!TextUtils.isEmpty(state) && mFileTreeView != null) {
|
if (!TextUtils.isEmpty(state) && mFileTreeView != null) {
|
||||||
|
|
||||||
LOG.debug("Restoring tree view state:", "'" + state + "'");
|
LOG.debug("Restoring tree view state:", "'" + state + "'");
|
||||||
|
|
||||||
mFileTreeView.collapseAll();
|
mFileTreeView.collapseAll();
|
||||||
final var openNodesArray = state.split(NODES_PATH_SEPARATOR);
|
final var openNodesArray = state.split(NODES_PATH_SEPARATOR);
|
||||||
final var openNodes = new HashSet<>(Arrays.asList(openNodesArray));
|
final var openNodes = new HashSet<>(Arrays.asList(openNodesArray));
|
||||||
restoreNodeState(mRoot, openNodes);
|
restoreNodeState(mRoot, openNodes);
|
||||||
} else {
|
} else {
|
||||||
LOG.error("Unable to restore tree state", "treeState=" + state, "treeView=" + mFileTreeView);
|
LOG.error("Unable to restore tree state", "treeState=" + state, "treeView=" + mFileTreeView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void restoreNodeState(@NonNull TreeNode root, Set<String> openNodes) {
|
private void restoreNodeState(@NonNull TreeNode root, Set<String> openNodes) {
|
||||||
final var children = root.getChildren();
|
final var children = root.getChildren();
|
||||||
for (int i = 0, childrenSize = children.size(); i < childrenSize; i++) {
|
for (int i = 0, childrenSize = children.size(); i < childrenSize; i++) {
|
||||||
final var node = children.get(i);
|
final var node = children.get(i);
|
||||||
if (openNodes.contains(node.getPath())) {
|
if (openNodes.contains(node.getPath())) {
|
||||||
listNode(
|
listNode(
|
||||||
node,
|
node,
|
||||||
() -> {
|
() -> {
|
||||||
updateChevron(node);
|
updateChevron(node);
|
||||||
expandNode(node);
|
expandNode(node);
|
||||||
restoreNodeState(node, openNodes);
|
restoreNodeState(node, openNodes);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface FileActionListener {
|
public interface FileActionListener {
|
||||||
CodeEditorView openFile(File file);
|
CodeEditorView openFile(File file);
|
||||||
|
|
||||||
void showFileOptions(File file, TreeNode node);
|
void showFileOptions(File file, TreeNode node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+103
-103
@@ -1,103 +1,103 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.fragments.attr;
|
package com.itsaky.androidide.fragments.attr;
|
||||||
|
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.widget.AutoCompleteTextView;
|
import android.widget.AutoCompleteTextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.blankj.utilcode.util.ThreadUtils;
|
import com.blankj.utilcode.util.ThreadUtils;
|
||||||
import com.google.android.material.textfield.MaterialAutoCompleteTextView;
|
import com.google.android.material.textfield.MaterialAutoCompleteTextView;
|
||||||
import com.itsaky.androidide.adapters.AttrValueCompletionAdapter;
|
import com.itsaky.androidide.adapters.AttrValueCompletionAdapter;
|
||||||
import com.itsaky.androidide.utils.ILogger;
|
import com.itsaky.androidide.utils.ILogger;
|
||||||
import com.itsaky.androidide.utils.TextWatcherAdapter;
|
import com.itsaky.androidide.utils.TextWatcherAdapter;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractReferenceEditor extends BaseValueEditorFragment {
|
public abstract class AbstractReferenceEditor extends BaseValueEditorFragment {
|
||||||
|
|
||||||
private static final ILogger LOG = ILogger.newInstance("ReferenceEditor");
|
private static final ILogger LOG = ILogger.newInstance("ReferenceEditor");
|
||||||
public TextWatcherAdapter resInputWatcher;
|
public TextWatcherAdapter resInputWatcher;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notifyValueChanged(@NonNull String newValue) {
|
protected void notifyValueChanged(@NonNull String newValue) {
|
||||||
try {
|
try {
|
||||||
super.notifyValueChanged(newValue);
|
super.notifyValueChanged(newValue);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOG.error("Unable to update resource value to '" + newValue + "'", e);
|
LOG.error("Unable to update resource value to '" + newValue + "'", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setupReferenceInput(MaterialAutoCompleteTextView referenceInput) {
|
protected void setupReferenceInput(MaterialAutoCompleteTextView referenceInput) {
|
||||||
Objects.requireNonNull(referenceInput);
|
Objects.requireNonNull(referenceInput);
|
||||||
|
|
||||||
referenceInput.setText(attribute.getValue());
|
referenceInput.setText(attribute.getValue());
|
||||||
|
|
||||||
if (resInputWatcher != null) {
|
if (resInputWatcher != null) {
|
||||||
referenceInput.removeTextChangedListener(resInputWatcher);
|
referenceInput.removeTextChangedListener(resInputWatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
resInputWatcher =
|
resInputWatcher =
|
||||||
new TextWatcherAdapter() {
|
new TextWatcherAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void afterTextChanged(@NonNull Editable s) {
|
public void afterTextChanged(@NonNull Editable s) {
|
||||||
final var text = s.toString().trim();
|
final var text = s.toString().trim();
|
||||||
if (TextUtils.isEmpty(text)) {
|
if (TextUtils.isEmpty(text)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyValueChanged(text);
|
notifyValueChanged(text);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
referenceInput.addTextChangedListener(resInputWatcher);
|
referenceInput.addTextChangedListener(resInputWatcher);
|
||||||
|
|
||||||
CompletableFuture.supplyAsync(this::computeReferenceItems)
|
CompletableFuture.supplyAsync(this::computeReferenceItems)
|
||||||
.whenComplete((list, error) -> handleAutoCompleteResult(list, error, referenceInput));
|
.whenComplete((list, error) -> handleAutoCompleteResult(list, error, referenceInput));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleAutoCompleteResult(
|
protected void handleAutoCompleteResult(
|
||||||
List<String> list, Throwable error, AutoCompleteTextView referenceInput) {
|
List<String> list, Throwable error, AutoCompleteTextView referenceInput) {
|
||||||
if (list == null || list.isEmpty()) {
|
if (list == null || list.isEmpty()) {
|
||||||
LOG.error("No completion items found");
|
LOG.error("No completion items found");
|
||||||
LOG.error("Error was:", error);
|
LOG.error("Error was:", error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.debug("Found", list.size(), "resource items for completion");
|
LOG.debug("Found", list.size(), "resource items for completion");
|
||||||
|
|
||||||
ThreadUtils.runOnUiThread(
|
ThreadUtils.runOnUiThread(
|
||||||
() -> {
|
() -> {
|
||||||
final var adapter = new AttrValueCompletionAdapter(requireContext(), list);
|
final var adapter = new AttrValueCompletionAdapter(requireContext(), list);
|
||||||
referenceInput.setThreshold(1);
|
referenceInput.setThreshold(1);
|
||||||
referenceInput.setAdapter(adapter);
|
referenceInput.setAdapter(adapter);
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<String> computeReferenceItems() {
|
protected List<String> computeReferenceItems() {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,83 +1,83 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.fragments.attr;
|
package com.itsaky.androidide.fragments.attr;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.android.material.textfield.MaterialAutoCompleteTextView;
|
import com.google.android.material.textfield.MaterialAutoCompleteTextView;
|
||||||
import com.itsaky.androidide.app.StudioApp;
|
import com.itsaky.androidide.app.StudioApp;
|
||||||
import com.itsaky.androidide.databinding.LayoutReferenceAttrEditorBinding;
|
import com.itsaky.androidide.databinding.LayoutReferenceAttrEditorBinding;
|
||||||
import com.itsaky.inflater.values.FrameworkValues;
|
import com.itsaky.inflater.values.FrameworkValues;
|
||||||
import com.itsaky.inflater.values.ValuesTableFactory;
|
import com.itsaky.inflater.values.ValuesTableFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
public class ReferenceEditor extends AbstractReferenceEditor {
|
public class ReferenceEditor extends AbstractReferenceEditor {
|
||||||
|
|
||||||
private LayoutReferenceAttrEditorBinding binding;
|
private LayoutReferenceAttrEditorBinding binding;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(
|
public View onCreateView(
|
||||||
@NonNull LayoutInflater inflater,
|
@NonNull LayoutInflater inflater,
|
||||||
@Nullable ViewGroup container,
|
@Nullable ViewGroup container,
|
||||||
@Nullable Bundle savedInstanceState) {
|
@Nullable Bundle savedInstanceState) {
|
||||||
this.binding = LayoutReferenceAttrEditorBinding.inflate(inflater, container, false);
|
this.binding = LayoutReferenceAttrEditorBinding.inflate(inflater, container, false);
|
||||||
return this.binding.getRoot();
|
return this.binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
setupReferenceInput((MaterialAutoCompleteTextView) this.binding.resInput.getEditText());
|
setupReferenceInput((MaterialAutoCompleteTextView) this.binding.resInput.getEditText());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<String> computeReferenceItems() {
|
protected List<String> computeReferenceItems() {
|
||||||
final var resTable = StudioApp.getInstance().getResourceTable();
|
final var resTable = StudioApp.getInstance().getResourceTable();
|
||||||
final var list = new ArrayList<>(resTable.listResourceNames(null));
|
final var list = new ArrayList<>(resTable.listResourceNames(null));
|
||||||
|
|
||||||
final var tables = ValuesTableFactory.getAllTables();
|
final var tables = ValuesTableFactory.getAllTables();
|
||||||
for (var entry : tables.entrySet()) {
|
for (var entry : tables.entrySet()) {
|
||||||
final var resourceMap = entry.getValue().getResourceMap();
|
final var resourceMap = entry.getValue().getResourceMap();
|
||||||
for (var resourceEntries : resourceMap.entrySet()) {
|
for (var resourceEntries : resourceMap.entrySet()) {
|
||||||
final var name = resourceEntries.getKey();
|
final var name = resourceEntries.getKey();
|
||||||
list.addAll(
|
list.addAll(
|
||||||
resourceEntries.getValue().keySet().stream()
|
resourceEntries.getValue().keySet().stream()
|
||||||
.map(("@android:" + name + "/")::concat)
|
.map(("@android:" + name + "/")::concat)
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list.addAll(FrameworkValues.listAllResources());
|
list.addAll(FrameworkValues.listAllResources());
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+164
-164
@@ -1,164 +1,164 @@
|
|||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
**************************************************************************************/
|
**************************************************************************************/
|
||||||
|
|
||||||
package com.itsaky.androidide.fragments.preferences;
|
package com.itsaky.androidide.fragments.preferences;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceCategory;
|
import androidx.preference.PreferenceCategory;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
import com.blankj.utilcode.util.FileUtils;
|
import com.blankj.utilcode.util.FileUtils;
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.itsaky.androidide.R;
|
import com.itsaky.androidide.R;
|
||||||
import com.itsaky.androidide.fragments.sheets.ProgressSheet;
|
import com.itsaky.androidide.fragments.sheets.ProgressSheet;
|
||||||
import com.itsaky.androidide.tasks.TaskExecutor;
|
import com.itsaky.androidide.tasks.TaskExecutor;
|
||||||
import com.itsaky.androidide.utils.DialogUtils;
|
import com.itsaky.androidide.utils.DialogUtils;
|
||||||
import com.itsaky.androidide.utils.Environment;
|
import com.itsaky.androidide.utils.Environment;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
public class BuildPreferences extends BasePreferenceFragment
|
public class BuildPreferences extends BasePreferenceFragment
|
||||||
implements Preference.OnPreferenceClickListener {
|
implements Preference.OnPreferenceClickListener {
|
||||||
|
|
||||||
public static final String KEY_GRADLE_COMMANDS = "idepref_build_gradleCommands";
|
public static final String KEY_GRADLE_COMMANDS = "idepref_build_gradleCommands";
|
||||||
public static final String KEY_GRADLE_CLEAR_CACHE = "idepref_build_gradleClearCache";
|
public static final String KEY_GRADLE_CLEAR_CACHE = "idepref_build_gradleClearCache";
|
||||||
|
|
||||||
private ProgressSheet progressSheet;
|
private ProgressSheet progressSheet;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreatePreferences(Bundle p1, String p2) {
|
public void onCreatePreferences(Bundle p1, String p2) {
|
||||||
super.onCreatePreferences(p1, p2);
|
super.onCreatePreferences(p1, p2);
|
||||||
if (getContext() == null) return;
|
if (getContext() == null) return;
|
||||||
final PreferenceScreen screen = getPreferenceScreen();
|
final PreferenceScreen screen = getPreferenceScreen();
|
||||||
final PreferenceCategory categoryGradle = new PreferenceCategory(getContext());
|
final PreferenceCategory categoryGradle = new PreferenceCategory(getContext());
|
||||||
final Preference customCommands = new Preference(getContext());
|
final Preference customCommands = new Preference(getContext());
|
||||||
final Preference clearCache = new Preference(getContext());
|
final Preference clearCache = new Preference(getContext());
|
||||||
|
|
||||||
screen.addPreference(categoryGradle);
|
screen.addPreference(categoryGradle);
|
||||||
|
|
||||||
customCommands.setKey(KEY_GRADLE_COMMANDS);
|
customCommands.setKey(KEY_GRADLE_COMMANDS);
|
||||||
customCommands.setIcon(R.drawable.ic_bash_commands);
|
customCommands.setIcon(R.drawable.ic_bash_commands);
|
||||||
customCommands.setTitle(R.string.idepref_build_customgradlecommands_title);
|
customCommands.setTitle(R.string.idepref_build_customgradlecommands_title);
|
||||||
customCommands.setSummary(R.string.idepref_build_customgradlecommands_summary);
|
customCommands.setSummary(R.string.idepref_build_customgradlecommands_summary);
|
||||||
|
|
||||||
clearCache.setKey(KEY_GRADLE_CLEAR_CACHE);
|
clearCache.setKey(KEY_GRADLE_CLEAR_CACHE);
|
||||||
clearCache.setIcon(R.drawable.ic_delete);
|
clearCache.setIcon(R.drawable.ic_delete);
|
||||||
clearCache.setTitle(R.string.idepref_build_clearCache_title);
|
clearCache.setTitle(R.string.idepref_build_clearCache_title);
|
||||||
clearCache.setSummary(R.string.idepref_build_clearCache_summary);
|
clearCache.setSummary(R.string.idepref_build_clearCache_summary);
|
||||||
|
|
||||||
categoryGradle.setTitle(R.string.gradle);
|
categoryGradle.setTitle(R.string.gradle);
|
||||||
categoryGradle.addPreference(customCommands);
|
categoryGradle.addPreference(customCommands);
|
||||||
categoryGradle.addPreference(clearCache);
|
categoryGradle.addPreference(clearCache);
|
||||||
|
|
||||||
setPreferenceScreen(screen);
|
setPreferenceScreen(screen);
|
||||||
|
|
||||||
customCommands.setOnPreferenceClickListener(this);
|
customCommands.setOnPreferenceClickListener(this);
|
||||||
clearCache.setOnPreferenceClickListener(this);
|
clearCache.setOnPreferenceClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference p1) {
|
public boolean onPreferenceClick(Preference p1) {
|
||||||
final String key = p1.getKey();
|
final String key = p1.getKey();
|
||||||
if (key.equals(KEY_GRADLE_COMMANDS)) {
|
if (key.equals(KEY_GRADLE_COMMANDS)) {
|
||||||
showGradleCommandsDialog();
|
showGradleCommandsDialog();
|
||||||
} else if (key.equals(KEY_GRADLE_CLEAR_CACHE)) {
|
} else if (key.equals(KEY_GRADLE_CLEAR_CACHE)) {
|
||||||
showClearCacheDialog();
|
showClearCacheDialog();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showGradleCommandsDialog() {
|
private void showGradleCommandsDialog() {
|
||||||
final String[] labels = {
|
final String[] labels = {
|
||||||
"--stacktrace",
|
"--stacktrace",
|
||||||
"--info",
|
"--info",
|
||||||
"--debug",
|
"--debug",
|
||||||
"--scan",
|
"--scan",
|
||||||
"--warning-mode all",
|
"--warning-mode all",
|
||||||
"--build-cache",
|
"--build-cache",
|
||||||
"--offline"
|
"--offline"
|
||||||
};
|
};
|
||||||
final boolean[] checked = {
|
final boolean[] checked = {
|
||||||
getPrefManager().isStackTraceEnabled(),
|
getPrefManager().isStackTraceEnabled(),
|
||||||
getPrefManager().isGradleInfoEnabled(),
|
getPrefManager().isGradleInfoEnabled(),
|
||||||
getPrefManager().isGradleDebugEnabled(),
|
getPrefManager().isGradleDebugEnabled(),
|
||||||
getPrefManager().isGradleScanEnabled(),
|
getPrefManager().isGradleScanEnabled(),
|
||||||
getPrefManager().isGradleWarningEnabled(),
|
getPrefManager().isGradleWarningEnabled(),
|
||||||
getPrefManager().isGradleBuildCacheEnabled(),
|
getPrefManager().isGradleBuildCacheEnabled(),
|
||||||
getPrefManager().isGradleOfflineModeEnabled()
|
getPrefManager().isGradleOfflineModeEnabled()
|
||||||
};
|
};
|
||||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(getContext());
|
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(getContext());
|
||||||
builder.setTitle(R.string.idepref_build_customgradlecommands_title);
|
builder.setTitle(R.string.idepref_build_customgradlecommands_title);
|
||||||
builder.setMultiChoiceItems(
|
builder.setMultiChoiceItems(
|
||||||
labels,
|
labels,
|
||||||
checked,
|
checked,
|
||||||
(p1, p2, p3) -> {
|
(p1, p2, p3) -> {
|
||||||
if (p2 == 0) {
|
if (p2 == 0) {
|
||||||
getPrefManager().setGradleStacktraceEnabled(p3);
|
getPrefManager().setGradleStacktraceEnabled(p3);
|
||||||
} else if (p2 == 1) {
|
} else if (p2 == 1) {
|
||||||
getPrefManager().setGradleInfoEnabled(p3);
|
getPrefManager().setGradleInfoEnabled(p3);
|
||||||
} else if (p2 == 2) {
|
} else if (p2 == 2) {
|
||||||
getPrefManager().setGradleDebugEnabled(p3);
|
getPrefManager().setGradleDebugEnabled(p3);
|
||||||
} else if (p2 == 3) {
|
} else if (p2 == 3) {
|
||||||
getPrefManager().setGradleScanEnabled(p3);
|
getPrefManager().setGradleScanEnabled(p3);
|
||||||
} else if (p2 == 4) {
|
} else if (p2 == 4) {
|
||||||
getPrefManager().setGradleWarningEnabled(p3);
|
getPrefManager().setGradleWarningEnabled(p3);
|
||||||
} else if (p2 == 5) {
|
} else if (p2 == 5) {
|
||||||
getPrefManager().setGradleBuildCacheEnabled(p3);
|
getPrefManager().setGradleBuildCacheEnabled(p3);
|
||||||
} else if (p2 == 6) {
|
} else if (p2 == 6) {
|
||||||
getPrefManager().setGradleOfflineModeEnabled(p3);
|
getPrefManager().setGradleOfflineModeEnabled(p3);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
builder.setPositiveButton(android.R.string.ok, null);
|
builder.setPositiveButton(android.R.string.ok, null);
|
||||||
builder.setCancelable(false);
|
builder.setCancelable(false);
|
||||||
builder.create().show();
|
builder.create().show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showClearCacheDialog() {
|
private void showClearCacheDialog() {
|
||||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(getContext());
|
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(getContext());
|
||||||
builder.setTitle(R.string.idepref_build_clearCache_title);
|
builder.setTitle(R.string.idepref_build_clearCache_title);
|
||||||
builder.setMessage(R.string.msg_clear_cache);
|
builder.setMessage(R.string.msg_clear_cache);
|
||||||
builder.setCancelable(false);
|
builder.setCancelable(false);
|
||||||
builder.setPositiveButton(
|
builder.setPositiveButton(
|
||||||
R.string.yes,
|
R.string.yes,
|
||||||
(p1, p2) -> {
|
(p1, p2) -> {
|
||||||
p1.dismiss();
|
p1.dismiss();
|
||||||
getProgressSheet().show(getChildFragmentManager(), "progress_sheet");
|
getProgressSheet().show(getChildFragmentManager(), "progress_sheet");
|
||||||
new TaskExecutor().executeAsync(this::deleteCaches, __ -> getProgressSheet().dismiss());
|
new TaskExecutor().executeAsync(this::deleteCaches, __ -> getProgressSheet().dismiss());
|
||||||
});
|
});
|
||||||
builder.setNegativeButton(R.string.no, null);
|
builder.setNegativeButton(R.string.no, null);
|
||||||
builder.create().show();
|
builder.create().show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object deleteCaches() {
|
private Object deleteCaches() {
|
||||||
File file = new File(Environment.GRADLE_USER_HOME, "caches");
|
File file = new File(Environment.GRADLE_USER_HOME, "caches");
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
FileUtils.delete(file);
|
FileUtils.delete(file);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProgressSheet getProgressSheet() {
|
private ProgressSheet getProgressSheet() {
|
||||||
return progressSheet == null
|
return progressSheet == null
|
||||||
? progressSheet = new ProgressSheet().setMessage(getString(R.string.please_wait))
|
? progressSheet = new ProgressSheet().setMessage(getString(R.string.please_wait))
|
||||||
: progressSheet;
|
: progressSheet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+319
-319
@@ -1,319 +1,319 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.fragments.preferences;
|
package com.itsaky.androidide.fragments.preferences;
|
||||||
|
|
||||||
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_AUTO_SAVE;
|
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_DRAW_HEX;
|
||||||
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FLAG_LINE_BREAK;
|
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FLAG_LINE_BREAK;
|
||||||
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FLAG_PASSWORD;
|
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FLAG_PASSWORD;
|
||||||
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FLAG_WS_EMPTY_LINE;
|
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FLAG_WS_EMPTY_LINE;
|
||||||
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FLAG_WS_INNER;
|
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FLAG_WS_INNER;
|
||||||
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FLAG_WS_LEADING;
|
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FLAG_WS_LEADING;
|
||||||
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FLAG_WS_TRAILING;
|
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FLAG_WS_TRAILING;
|
||||||
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FONT_LIGATURES;
|
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FONT_LIGATURES;
|
||||||
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FONT_SIZE;
|
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_FONT_SIZE;
|
||||||
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_PRINTABLE_CHARS;
|
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_PRINTABLE_CHARS;
|
||||||
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_TAB_SIZE;
|
import static com.itsaky.androidide.managers.PreferenceManager.KEY_EDITOR_TAB_SIZE;
|
||||||
import static com.itsaky.lsp.java.models.JavaServerSettings.KEY_COMPLETIONS_MATCH_LOWER;
|
import static com.itsaky.lsp.java.models.JavaServerSettings.KEY_COMPLETIONS_MATCH_LOWER;
|
||||||
import static com.itsaky.lsp.java.models.JavaServerSettings.KEY_JAVA_PREF_GOOGLE_CODE_STYLE;
|
import static com.itsaky.lsp.java.models.JavaServerSettings.KEY_JAVA_PREF_GOOGLE_CODE_STYLE;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceCategory;
|
import androidx.preference.PreferenceCategory;
|
||||||
import androidx.preference.SwitchPreference;
|
import androidx.preference.SwitchPreference;
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.itsaky.androidide.R;
|
import com.itsaky.androidide.R;
|
||||||
import com.itsaky.androidide.databinding.LayoutTextSizeSliderBinding;
|
import com.itsaky.androidide.databinding.LayoutTextSizeSliderBinding;
|
||||||
import com.itsaky.androidide.managers.PreferenceManager;
|
import com.itsaky.androidide.managers.PreferenceManager;
|
||||||
import com.itsaky.androidide.models.ConstantsBridge;
|
import com.itsaky.androidide.models.ConstantsBridge;
|
||||||
import com.itsaky.androidide.utils.DialogUtils;
|
import com.itsaky.androidide.utils.DialogUtils;
|
||||||
|
|
||||||
public class EditorPreferences extends BasePreferenceFragment
|
public class EditorPreferences extends BasePreferenceFragment
|
||||||
implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener {
|
implements Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreatePreferences(Bundle p1, String p2) {
|
public void onCreatePreferences(Bundle p1, String p2) {
|
||||||
super.onCreatePreferences(p1, p2);
|
super.onCreatePreferences(p1, p2);
|
||||||
|
|
||||||
if (getContext() == null) {
|
if (getContext() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var screen = getPreferenceScreen();
|
final var screen = getPreferenceScreen();
|
||||||
final var commonCategory = new PreferenceCategory(getContext());
|
final var commonCategory = new PreferenceCategory(getContext());
|
||||||
final var javaCategory = new PreferenceCategory(getContext());
|
final var javaCategory = new PreferenceCategory(getContext());
|
||||||
|
|
||||||
final var fontSize = new Preference(getContext());
|
final var fontSize = new Preference(getContext());
|
||||||
final var nonPrintable = new Preference(getContext());
|
final var nonPrintable = new Preference(getContext());
|
||||||
final var tabSize = new Preference(getContext());
|
final var tabSize = new Preference(getContext());
|
||||||
final var drawHex = new SwitchPreference(getContext());
|
final var drawHex = new SwitchPreference(getContext());
|
||||||
final var wordWrap = new SwitchPreference(getContext());
|
final var wordWrap = new SwitchPreference(getContext());
|
||||||
final var magnifier = new SwitchPreference(getContext());
|
final var magnifier = new SwitchPreference(getContext());
|
||||||
final var fontLigatures = new SwitchPreference(getContext());
|
final var fontLigatures = new SwitchPreference(getContext());
|
||||||
final var autoSave = new SwitchPreference(getContext());
|
final var autoSave = new SwitchPreference(getContext());
|
||||||
final var useGoogleCodeStyle = new SwitchPreference(getContext());
|
final var useGoogleCodeStyle = new SwitchPreference(getContext());
|
||||||
final var visiblePasswordFlag = new SwitchPreference(getContext());
|
final var visiblePasswordFlag = new SwitchPreference(getContext());
|
||||||
|
|
||||||
final var completionsMatchLower = new SwitchPreference(getContext());
|
final var completionsMatchLower = new SwitchPreference(getContext());
|
||||||
|
|
||||||
screen.addPreference(commonCategory);
|
screen.addPreference(commonCategory);
|
||||||
screen.addPreference(javaCategory);
|
screen.addPreference(javaCategory);
|
||||||
|
|
||||||
fontSize.setIcon(R.drawable.ic_text_size);
|
fontSize.setIcon(R.drawable.ic_text_size);
|
||||||
fontSize.setKey(KEY_EDITOR_FONT_SIZE);
|
fontSize.setKey(KEY_EDITOR_FONT_SIZE);
|
||||||
fontSize.setTitle(R.string.idepref_editor_fontsize_title);
|
fontSize.setTitle(R.string.idepref_editor_fontsize_title);
|
||||||
fontSize.setSummary(R.string.idepref_editor_fontsize_summary);
|
fontSize.setSummary(R.string.idepref_editor_fontsize_summary);
|
||||||
|
|
||||||
wordWrap.setIcon(R.drawable.ic_wrap_text);
|
wordWrap.setIcon(R.drawable.ic_wrap_text);
|
||||||
wordWrap.setKey(PreferenceManager.KEY_EDITOR_WORD_WRAP);
|
wordWrap.setKey(PreferenceManager.KEY_EDITOR_WORD_WRAP);
|
||||||
wordWrap.setTitle(R.string.idepref_editor_word_wrap_title);
|
wordWrap.setTitle(R.string.idepref_editor_word_wrap_title);
|
||||||
wordWrap.setSummary(R.string.idepref_editor_word_wrap_summary);
|
wordWrap.setSummary(R.string.idepref_editor_word_wrap_summary);
|
||||||
|
|
||||||
magnifier.setIcon(R.drawable.ic_loupe);
|
magnifier.setIcon(R.drawable.ic_loupe);
|
||||||
magnifier.setKey(PreferenceManager.KEY_EDITOR_USE_MAGNIFER);
|
magnifier.setKey(PreferenceManager.KEY_EDITOR_USE_MAGNIFER);
|
||||||
magnifier.setTitle(R.string.idepref_editor_use_magnifier_title);
|
magnifier.setTitle(R.string.idepref_editor_use_magnifier_title);
|
||||||
magnifier.setSummary(R.string.idepref_editor_use_magnifier_summary);
|
magnifier.setSummary(R.string.idepref_editor_use_magnifier_summary);
|
||||||
|
|
||||||
nonPrintable.setIcon(R.drawable.ic_drawing);
|
nonPrintable.setIcon(R.drawable.ic_drawing);
|
||||||
nonPrintable.setKey(KEY_EDITOR_PRINTABLE_CHARS);
|
nonPrintable.setKey(KEY_EDITOR_PRINTABLE_CHARS);
|
||||||
nonPrintable.setTitle(R.string.idepref_editor_paintingflags_title);
|
nonPrintable.setTitle(R.string.idepref_editor_paintingflags_title);
|
||||||
nonPrintable.setSummary(R.string.idepref_editor_paintingflags_summary);
|
nonPrintable.setSummary(R.string.idepref_editor_paintingflags_summary);
|
||||||
|
|
||||||
tabSize.setIcon(R.drawable.ic_tab);
|
tabSize.setIcon(R.drawable.ic_tab);
|
||||||
tabSize.setKey(KEY_EDITOR_TAB_SIZE);
|
tabSize.setKey(KEY_EDITOR_TAB_SIZE);
|
||||||
tabSize.setTitle(R.string.title_tab_size);
|
tabSize.setTitle(R.string.title_tab_size);
|
||||||
tabSize.setSummary(R.string.msg_tab_size);
|
tabSize.setSummary(R.string.msg_tab_size);
|
||||||
|
|
||||||
drawHex.setIcon(R.drawable.ic_hexadecimal);
|
drawHex.setIcon(R.drawable.ic_hexadecimal);
|
||||||
drawHex.setKey(KEY_EDITOR_DRAW_HEX);
|
drawHex.setKey(KEY_EDITOR_DRAW_HEX);
|
||||||
drawHex.setTitle(R.string.idepref_editor_drawhexcolors_title);
|
drawHex.setTitle(R.string.idepref_editor_drawhexcolors_title);
|
||||||
drawHex.setSummary(R.string.idepref_editor_drawhexcolors_summary);
|
drawHex.setSummary(R.string.idepref_editor_drawhexcolors_summary);
|
||||||
|
|
||||||
fontLigatures.setIcon(R.drawable.ic_font_ligatures);
|
fontLigatures.setIcon(R.drawable.ic_font_ligatures);
|
||||||
fontLigatures.setKey(KEY_EDITOR_FONT_LIGATURES);
|
fontLigatures.setKey(KEY_EDITOR_FONT_LIGATURES);
|
||||||
fontLigatures.setTitle(getString(R.string.idepref_editor_ligatures_title));
|
fontLigatures.setTitle(getString(R.string.idepref_editor_ligatures_title));
|
||||||
fontLigatures.setSummary(getString(R.string.idepref_editor_ligatures_summary));
|
fontLigatures.setSummary(getString(R.string.idepref_editor_ligatures_summary));
|
||||||
|
|
||||||
autoSave.setIcon(R.drawable.ic_save);
|
autoSave.setIcon(R.drawable.ic_save);
|
||||||
autoSave.setKey(KEY_EDITOR_AUTO_SAVE);
|
autoSave.setKey(KEY_EDITOR_AUTO_SAVE);
|
||||||
autoSave.setTitle(getString(R.string.idepref_editor_autoSave_title));
|
autoSave.setTitle(getString(R.string.idepref_editor_autoSave_title));
|
||||||
autoSave.setSummary(getString(R.string.idepref_editor_autoSave_summary));
|
autoSave.setSummary(getString(R.string.idepref_editor_autoSave_summary));
|
||||||
|
|
||||||
completionsMatchLower.setKey(KEY_COMPLETIONS_MATCH_LOWER);
|
completionsMatchLower.setKey(KEY_COMPLETIONS_MATCH_LOWER);
|
||||||
completionsMatchLower.setIcon(R.drawable.ic_text_lower);
|
completionsMatchLower.setIcon(R.drawable.ic_text_lower);
|
||||||
completionsMatchLower.setTitle(getString(R.string.idepref_java_matchLower_title));
|
completionsMatchLower.setTitle(getString(R.string.idepref_java_matchLower_title));
|
||||||
completionsMatchLower.setSummary(getString(R.string.idepref_java_matchLower_summary));
|
completionsMatchLower.setSummary(getString(R.string.idepref_java_matchLower_summary));
|
||||||
|
|
||||||
useGoogleCodeStyle.setIcon(R.drawable.ic_format_code);
|
useGoogleCodeStyle.setIcon(R.drawable.ic_format_code);
|
||||||
useGoogleCodeStyle.setKey(KEY_JAVA_PREF_GOOGLE_CODE_STYLE);
|
useGoogleCodeStyle.setKey(KEY_JAVA_PREF_GOOGLE_CODE_STYLE);
|
||||||
useGoogleCodeStyle.setTitle(getString(R.string.idepref_java_useGoogleStyle_title));
|
useGoogleCodeStyle.setTitle(getString(R.string.idepref_java_useGoogleStyle_title));
|
||||||
useGoogleCodeStyle.setSummary(getString(R.string.idepref_java_useGoogleStyle_summary));
|
useGoogleCodeStyle.setSummary(getString(R.string.idepref_java_useGoogleStyle_summary));
|
||||||
|
|
||||||
visiblePasswordFlag.setIcon(R.drawable.ic_password_input);
|
visiblePasswordFlag.setIcon(R.drawable.ic_password_input);
|
||||||
visiblePasswordFlag.setKey(KEY_EDITOR_FLAG_PASSWORD);
|
visiblePasswordFlag.setKey(KEY_EDITOR_FLAG_PASSWORD);
|
||||||
visiblePasswordFlag.setTitle(getString(R.string.idepref_visiblePassword_title));
|
visiblePasswordFlag.setTitle(getString(R.string.idepref_visiblePassword_title));
|
||||||
visiblePasswordFlag.setSummary(getString(R.string.idepref_visiblePassword_summary));
|
visiblePasswordFlag.setSummary(getString(R.string.idepref_visiblePassword_summary));
|
||||||
|
|
||||||
commonCategory.setTitle(getString(R.string.idepref_editor_category_common));
|
commonCategory.setTitle(getString(R.string.idepref_editor_category_common));
|
||||||
commonCategory.addPreference(fontSize);
|
commonCategory.addPreference(fontSize);
|
||||||
commonCategory.addPreference(fontLigatures);
|
commonCategory.addPreference(fontLigatures);
|
||||||
commonCategory.addPreference(tabSize);
|
commonCategory.addPreference(tabSize);
|
||||||
commonCategory.addPreference(wordWrap);
|
commonCategory.addPreference(wordWrap);
|
||||||
commonCategory.addPreference(magnifier);
|
commonCategory.addPreference(magnifier);
|
||||||
commonCategory.addPreference(completionsMatchLower);
|
commonCategory.addPreference(completionsMatchLower);
|
||||||
commonCategory.addPreference(visiblePasswordFlag);
|
commonCategory.addPreference(visiblePasswordFlag);
|
||||||
commonCategory.addPreference(nonPrintable);
|
commonCategory.addPreference(nonPrintable);
|
||||||
commonCategory.addPreference(drawHex);
|
commonCategory.addPreference(drawHex);
|
||||||
commonCategory.addPreference(autoSave);
|
commonCategory.addPreference(autoSave);
|
||||||
|
|
||||||
javaCategory.setTitle(getString(R.string.idepref_editor_category_java));
|
javaCategory.setTitle(getString(R.string.idepref_editor_category_java));
|
||||||
javaCategory.addPreference(useGoogleCodeStyle);
|
javaCategory.addPreference(useGoogleCodeStyle);
|
||||||
|
|
||||||
setPreferenceScreen(screen);
|
setPreferenceScreen(screen);
|
||||||
|
|
||||||
fontSize.setOnPreferenceClickListener(this);
|
fontSize.setOnPreferenceClickListener(this);
|
||||||
fontLigatures.setOnPreferenceChangeListener(this);
|
fontLigatures.setOnPreferenceChangeListener(this);
|
||||||
nonPrintable.setOnPreferenceClickListener(this);
|
nonPrintable.setOnPreferenceClickListener(this);
|
||||||
tabSize.setOnPreferenceClickListener(this);
|
tabSize.setOnPreferenceClickListener(this);
|
||||||
drawHex.setOnPreferenceChangeListener(this);
|
drawHex.setOnPreferenceChangeListener(this);
|
||||||
autoSave.setOnPreferenceChangeListener(this);
|
autoSave.setOnPreferenceChangeListener(this);
|
||||||
completionsMatchLower.setOnPreferenceChangeListener(this);
|
completionsMatchLower.setOnPreferenceChangeListener(this);
|
||||||
useGoogleCodeStyle.setOnPreferenceChangeListener(this);
|
useGoogleCodeStyle.setOnPreferenceChangeListener(this);
|
||||||
visiblePasswordFlag.setOnPreferenceChangeListener(this);
|
visiblePasswordFlag.setOnPreferenceChangeListener(this);
|
||||||
wordWrap.setOnPreferenceChangeListener(this);
|
wordWrap.setOnPreferenceChangeListener(this);
|
||||||
magnifier.setOnPreferenceChangeListener(this);
|
magnifier.setOnPreferenceChangeListener(this);
|
||||||
|
|
||||||
fontLigatures.setChecked(getPrefManager().getBoolean(KEY_EDITOR_FONT_LIGATURES, true));
|
fontLigatures.setChecked(getPrefManager().getBoolean(KEY_EDITOR_FONT_LIGATURES, true));
|
||||||
drawHex.setChecked(getPrefManager().getBoolean(KEY_EDITOR_DRAW_HEX, true));
|
drawHex.setChecked(getPrefManager().getBoolean(KEY_EDITOR_DRAW_HEX, true));
|
||||||
autoSave.setChecked(getPrefManager().getBoolean(KEY_EDITOR_AUTO_SAVE, false));
|
autoSave.setChecked(getPrefManager().getBoolean(KEY_EDITOR_AUTO_SAVE, false));
|
||||||
completionsMatchLower.setChecked(
|
completionsMatchLower.setChecked(
|
||||||
getPrefManager().getBoolean(KEY_COMPLETIONS_MATCH_LOWER, false));
|
getPrefManager().getBoolean(KEY_COMPLETIONS_MATCH_LOWER, false));
|
||||||
useGoogleCodeStyle.setChecked(
|
useGoogleCodeStyle.setChecked(
|
||||||
getPrefManager().getBoolean(KEY_JAVA_PREF_GOOGLE_CODE_STYLE, false));
|
getPrefManager().getBoolean(KEY_JAVA_PREF_GOOGLE_CODE_STYLE, false));
|
||||||
visiblePasswordFlag.setChecked(getPrefManager().getBoolean(KEY_EDITOR_FLAG_PASSWORD, true));
|
visiblePasswordFlag.setChecked(getPrefManager().getBoolean(KEY_EDITOR_FLAG_PASSWORD, true));
|
||||||
wordWrap.setChecked(getPrefManager().getBoolean(PreferenceManager.KEY_EDITOR_WORD_WRAP, false));
|
wordWrap.setChecked(getPrefManager().getBoolean(PreferenceManager.KEY_EDITOR_WORD_WRAP, false));
|
||||||
magnifier.setChecked(
|
magnifier.setChecked(
|
||||||
getPrefManager().getBoolean(PreferenceManager.KEY_EDITOR_USE_MAGNIFER, true));
|
getPrefManager().getBoolean(PreferenceManager.KEY_EDITOR_USE_MAGNIFER, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) {
|
public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) {
|
||||||
final boolean value = (boolean) newValue;
|
final boolean value = (boolean) newValue;
|
||||||
|
|
||||||
switch (preference.getKey()) {
|
switch (preference.getKey()) {
|
||||||
case KEY_EDITOR_FLAG_PASSWORD:
|
case KEY_EDITOR_FLAG_PASSWORD:
|
||||||
ConstantsBridge.EDITOR_PREF_VISIBLE_PASSWORD_CHANGED = true;
|
ConstantsBridge.EDITOR_PREF_VISIBLE_PASSWORD_CHANGED = true;
|
||||||
break;
|
break;
|
||||||
case KEY_EDITOR_DRAW_HEX:
|
case KEY_EDITOR_DRAW_HEX:
|
||||||
ConstantsBridge.EDITOR_PREF_DRAW_HEX_CHANGED = true;
|
ConstantsBridge.EDITOR_PREF_DRAW_HEX_CHANGED = true;
|
||||||
break;
|
break;
|
||||||
case KEY_EDITOR_FONT_LIGATURES:
|
case KEY_EDITOR_FONT_LIGATURES:
|
||||||
ConstantsBridge.EDITOR_PREF_LIGATURES_CHANGED = true;
|
ConstantsBridge.EDITOR_PREF_LIGATURES_CHANGED = true;
|
||||||
break;
|
break;
|
||||||
case PreferenceManager.KEY_EDITOR_WORD_WRAP:
|
case PreferenceManager.KEY_EDITOR_WORD_WRAP:
|
||||||
ConstantsBridge.EDITOR_PREF_WORD_WRAP_CHANGED = true;
|
ConstantsBridge.EDITOR_PREF_WORD_WRAP_CHANGED = true;
|
||||||
break;
|
break;
|
||||||
case PreferenceManager.KEY_EDITOR_USE_MAGNIFER:
|
case PreferenceManager.KEY_EDITOR_USE_MAGNIFER:
|
||||||
ConstantsBridge.EDITOR_PREF_USE_MAGNIFIER_CHANGED = true;
|
ConstantsBridge.EDITOR_PREF_USE_MAGNIFIER_CHANGED = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPrefManager().putBoolean(preference.getKey(), value);
|
getPrefManager().putBoolean(preference.getKey(), value);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(@NonNull Preference preference) {
|
public boolean onPreferenceClick(@NonNull Preference preference) {
|
||||||
final String key = preference.getKey();
|
final String key = preference.getKey();
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case KEY_EDITOR_FONT_SIZE:
|
case KEY_EDITOR_FONT_SIZE:
|
||||||
showTextSizeDialog();
|
showTextSizeDialog();
|
||||||
break;
|
break;
|
||||||
case KEY_EDITOR_PRINTABLE_CHARS:
|
case KEY_EDITOR_PRINTABLE_CHARS:
|
||||||
showPrintableCharsDialog();
|
showPrintableCharsDialog();
|
||||||
break;
|
break;
|
||||||
case KEY_EDITOR_TAB_SIZE:
|
case KEY_EDITOR_TAB_SIZE:
|
||||||
showTabSizeDialog();
|
showTabSizeDialog();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showTabSizeDialog() {
|
private void showTabSizeDialog() {
|
||||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(getContext());
|
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(getContext());
|
||||||
final String[] sizes = new String[] {"2", "4", "6", "8"};
|
final String[] sizes = new String[] {"2", "4", "6", "8"};
|
||||||
|
|
||||||
int current = (getPrefManager().getEditorTabSize() / 2) - 1;
|
int current = (getPrefManager().getEditorTabSize() / 2) - 1;
|
||||||
if (current < 0 || current >= sizes.length) {
|
if (current < 0 || current >= sizes.length) {
|
||||||
current = 1;
|
current = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.setTitle(R.string.title_tab_size);
|
builder.setTitle(R.string.title_tab_size);
|
||||||
builder.setSingleChoiceItems(
|
builder.setSingleChoiceItems(
|
||||||
sizes,
|
sizes,
|
||||||
current,
|
current,
|
||||||
(d, i) -> {
|
(d, i) -> {
|
||||||
d.dismiss();
|
d.dismiss();
|
||||||
|
|
||||||
int tabSize = (i + 1) * 2;
|
int tabSize = (i + 1) * 2;
|
||||||
if (tabSize < 2 || tabSize > 8) {
|
if (tabSize < 2 || tabSize > 8) {
|
||||||
tabSize = 4;
|
tabSize = 4;
|
||||||
}
|
}
|
||||||
getPrefManager().putInt(KEY_EDITOR_TAB_SIZE, tabSize);
|
getPrefManager().putInt(KEY_EDITOR_TAB_SIZE, tabSize);
|
||||||
});
|
});
|
||||||
builder.setCancelable(true);
|
builder.setCancelable(true);
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showTextSizeDialog() {
|
private void showTextSizeDialog() {
|
||||||
final LayoutTextSizeSliderBinding binding =
|
final LayoutTextSizeSliderBinding binding =
|
||||||
LayoutTextSizeSliderBinding.inflate(LayoutInflater.from(getContext()));
|
LayoutTextSizeSliderBinding.inflate(LayoutInflater.from(getContext()));
|
||||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(getContext());
|
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(getContext());
|
||||||
float size = getPrefManager().getFloat(KEY_EDITOR_FONT_SIZE, 14);
|
float size = getPrefManager().getFloat(KEY_EDITOR_FONT_SIZE, 14);
|
||||||
if (size < 6 || size > 32) {
|
if (size < 6 || size > 32) {
|
||||||
size = 14;
|
size = 14;
|
||||||
}
|
}
|
||||||
changeTextSize(binding, size);
|
changeTextSize(binding, size);
|
||||||
|
|
||||||
binding.slider.setLabelFormatter(p1 -> String.valueOf((int) p1));
|
binding.slider.setLabelFormatter(p1 -> String.valueOf((int) p1));
|
||||||
builder.setTitle(R.string.title_change_text_size);
|
builder.setTitle(R.string.title_change_text_size);
|
||||||
builder.setMessage(R.string.msg_editor_font_size);
|
builder.setMessage(R.string.msg_editor_font_size);
|
||||||
builder.setView(binding.getRoot());
|
builder.setView(binding.getRoot());
|
||||||
builder.setPositiveButton(
|
builder.setPositiveButton(
|
||||||
android.R.string.ok,
|
android.R.string.ok,
|
||||||
(p1, p2) -> {
|
(p1, p2) -> {
|
||||||
p1.dismiss();
|
p1.dismiss();
|
||||||
float s = binding.slider.getValue();
|
float s = binding.slider.getValue();
|
||||||
changeTextSize(binding, s);
|
changeTextSize(binding, s);
|
||||||
});
|
});
|
||||||
builder.setNeutralButton(R.string.reset, (p1, p2) -> changeTextSize(binding, 14));
|
builder.setNeutralButton(R.string.reset, (p1, p2) -> changeTextSize(binding, 14));
|
||||||
builder.setCancelable(false);
|
builder.setCancelable(false);
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void changeTextSize(LayoutTextSizeSliderBinding binding, float size) {
|
private void changeTextSize(LayoutTextSizeSliderBinding binding, float size) {
|
||||||
getPrefManager().putFloat(KEY_EDITOR_FONT_SIZE, size);
|
getPrefManager().putFloat(KEY_EDITOR_FONT_SIZE, size);
|
||||||
binding.slider.setValue(size);
|
binding.slider.setValue(size);
|
||||||
ConstantsBridge.EDITOR_PREF_SIZE_CHANGED = true;
|
ConstantsBridge.EDITOR_PREF_SIZE_CHANGED = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showPrintableCharsDialog() {
|
private void showPrintableCharsDialog() {
|
||||||
String[] labels = {
|
String[] labels = {
|
||||||
"Leading whitespaces",
|
"Leading whitespaces",
|
||||||
"Trailing whitespaces",
|
"Trailing whitespaces",
|
||||||
"Inner whitespaces",
|
"Inner whitespaces",
|
||||||
"Whitespaces in empty lines",
|
"Whitespaces in empty lines",
|
||||||
"Line breaks"
|
"Line breaks"
|
||||||
};
|
};
|
||||||
final boolean[] checked = {
|
final boolean[] checked = {
|
||||||
getPrefManager().getBoolean(KEY_EDITOR_FLAG_WS_LEADING, true),
|
getPrefManager().getBoolean(KEY_EDITOR_FLAG_WS_LEADING, true),
|
||||||
getPrefManager().getBoolean(KEY_EDITOR_FLAG_WS_TRAILING, false),
|
getPrefManager().getBoolean(KEY_EDITOR_FLAG_WS_TRAILING, false),
|
||||||
getPrefManager().getBoolean(KEY_EDITOR_FLAG_WS_INNER, true),
|
getPrefManager().getBoolean(KEY_EDITOR_FLAG_WS_INNER, true),
|
||||||
getPrefManager().getBoolean(KEY_EDITOR_FLAG_WS_EMPTY_LINE, true),
|
getPrefManager().getBoolean(KEY_EDITOR_FLAG_WS_EMPTY_LINE, true),
|
||||||
getPrefManager().getBoolean(KEY_EDITOR_FLAG_LINE_BREAK, true)
|
getPrefManager().getBoolean(KEY_EDITOR_FLAG_LINE_BREAK, true)
|
||||||
};
|
};
|
||||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(getContext());
|
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(getContext());
|
||||||
builder.setTitle(R.string.idepref_editor_paintingflags_title);
|
builder.setTitle(R.string.idepref_editor_paintingflags_title);
|
||||||
builder.setMultiChoiceItems(
|
builder.setMultiChoiceItems(
|
||||||
labels,
|
labels,
|
||||||
checked,
|
checked,
|
||||||
(dialog, which, isChecked) -> {
|
(dialog, which, isChecked) -> {
|
||||||
if (which == 0) {
|
if (which == 0) {
|
||||||
getPrefManager().putBoolean(KEY_EDITOR_FLAG_WS_LEADING, isChecked);
|
getPrefManager().putBoolean(KEY_EDITOR_FLAG_WS_LEADING, isChecked);
|
||||||
} else if (which == 1) {
|
} else if (which == 1) {
|
||||||
getPrefManager().putBoolean(KEY_EDITOR_FLAG_WS_TRAILING, isChecked);
|
getPrefManager().putBoolean(KEY_EDITOR_FLAG_WS_TRAILING, isChecked);
|
||||||
} else if (which == 2) {
|
} else if (which == 2) {
|
||||||
getPrefManager().putBoolean(KEY_EDITOR_FLAG_WS_INNER, isChecked);
|
getPrefManager().putBoolean(KEY_EDITOR_FLAG_WS_INNER, isChecked);
|
||||||
} else if (which == 3) {
|
} else if (which == 3) {
|
||||||
getPrefManager().putBoolean(KEY_EDITOR_FLAG_WS_EMPTY_LINE, isChecked);
|
getPrefManager().putBoolean(KEY_EDITOR_FLAG_WS_EMPTY_LINE, isChecked);
|
||||||
} else if (which == 4) {
|
} else if (which == 4) {
|
||||||
getPrefManager().putBoolean(KEY_EDITOR_FLAG_LINE_BREAK, isChecked);
|
getPrefManager().putBoolean(KEY_EDITOR_FLAG_LINE_BREAK, isChecked);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstantsBridge.EDITOR_PREF_FLAGS_CHANGED = true;
|
ConstantsBridge.EDITOR_PREF_FLAGS_CHANGED = true;
|
||||||
});
|
});
|
||||||
builder.setPositiveButton(android.R.string.ok, null);
|
builder.setPositiveButton(android.R.string.ok, null);
|
||||||
builder.setCancelable(false);
|
builder.setCancelable(false);
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+192
-192
@@ -1,192 +1,192 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.fragments.sheets;
|
package com.itsaky.androidide.fragments.sheets;
|
||||||
|
|
||||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_BOOLEAN;
|
import static com.itsaky.attrinfo.models.Attr.FORMAT_BOOLEAN;
|
||||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_COLOR;
|
import static com.itsaky.attrinfo.models.Attr.FORMAT_COLOR;
|
||||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_DIMENSION;
|
import static com.itsaky.attrinfo.models.Attr.FORMAT_DIMENSION;
|
||||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_ENUM;
|
import static com.itsaky.attrinfo.models.Attr.FORMAT_ENUM;
|
||||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_FLAG;
|
import static com.itsaky.attrinfo.models.Attr.FORMAT_FLAG;
|
||||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_FLOAT;
|
import static com.itsaky.attrinfo.models.Attr.FORMAT_FLOAT;
|
||||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_FRACTION;
|
import static com.itsaky.attrinfo.models.Attr.FORMAT_FRACTION;
|
||||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_INTEGER;
|
import static com.itsaky.attrinfo.models.Attr.FORMAT_INTEGER;
|
||||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_REFERENCE;
|
import static com.itsaky.attrinfo.models.Attr.FORMAT_REFERENCE;
|
||||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_STRING;
|
import static com.itsaky.attrinfo.models.Attr.FORMAT_STRING;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||||
import com.itsaky.androidide.adapters.AttrValueFormatTabAdapter;
|
import com.itsaky.androidide.adapters.AttrValueFormatTabAdapter;
|
||||||
import com.itsaky.androidide.databinding.LayoutAttrValueEditorBinding;
|
import com.itsaky.androidide.databinding.LayoutAttrValueEditorBinding;
|
||||||
import com.itsaky.androidide.fragments.attr.BaseValueEditorFragment;
|
import com.itsaky.androidide.fragments.attr.BaseValueEditorFragment;
|
||||||
import com.itsaky.androidide.fragments.attr.BooleanEditor;
|
import com.itsaky.androidide.fragments.attr.BooleanEditor;
|
||||||
import com.itsaky.androidide.fragments.attr.ColorEditor;
|
import com.itsaky.androidide.fragments.attr.ColorEditor;
|
||||||
import com.itsaky.androidide.fragments.attr.DimensionEditor;
|
import com.itsaky.androidide.fragments.attr.DimensionEditor;
|
||||||
import com.itsaky.androidide.fragments.attr.EnumEditor;
|
import com.itsaky.androidide.fragments.attr.EnumEditor;
|
||||||
import com.itsaky.androidide.fragments.attr.FlagEditor;
|
import com.itsaky.androidide.fragments.attr.FlagEditor;
|
||||||
import com.itsaky.androidide.fragments.attr.FloatEditor;
|
import com.itsaky.androidide.fragments.attr.FloatEditor;
|
||||||
import com.itsaky.androidide.fragments.attr.FractionEditor;
|
import com.itsaky.androidide.fragments.attr.FractionEditor;
|
||||||
import com.itsaky.androidide.fragments.attr.IntegerEditor;
|
import com.itsaky.androidide.fragments.attr.IntegerEditor;
|
||||||
import com.itsaky.androidide.fragments.attr.ReferenceEditor;
|
import com.itsaky.androidide.fragments.attr.ReferenceEditor;
|
||||||
import com.itsaky.androidide.fragments.attr.StringEditor;
|
import com.itsaky.androidide.fragments.attr.StringEditor;
|
||||||
import com.itsaky.androidide.models.XMLAttribute;
|
import com.itsaky.androidide.models.XMLAttribute;
|
||||||
import com.itsaky.attrinfo.models.Attr;
|
import com.itsaky.attrinfo.models.Attr;
|
||||||
import com.itsaky.inflater.IAttribute;
|
import com.itsaky.inflater.IAttribute;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sheet for editing value of an attribute.
|
* Sheet for editing value of an attribute.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
public class AttrValueEditorSheet extends BottomSheetDialogFragment
|
public class AttrValueEditorSheet extends BottomSheetDialogFragment
|
||||||
implements BaseValueEditorFragment.OnValueChangeListener {
|
implements BaseValueEditorFragment.OnValueChangeListener {
|
||||||
|
|
||||||
private static final String KEY_ATTRIBUTE = "attrEditorSheet_attribute";
|
private static final String KEY_ATTRIBUTE = "attrEditorSheet_attribute";
|
||||||
private BaseValueEditorFragment.OnValueChangeListener valueChangeListener;
|
private BaseValueEditorFragment.OnValueChangeListener valueChangeListener;
|
||||||
private LayoutAttrValueEditorBinding binding;
|
private LayoutAttrValueEditorBinding binding;
|
||||||
private AttrValueFormatTabAdapter adapter;
|
private AttrValueFormatTabAdapter adapter;
|
||||||
private XMLAttribute attribute;
|
private XMLAttribute attribute;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static AttrValueEditorSheet newInstance(final XMLAttribute attribute) {
|
public static AttrValueEditorSheet newInstance(final XMLAttribute attribute) {
|
||||||
Objects.requireNonNull(attribute);
|
Objects.requireNonNull(attribute);
|
||||||
|
|
||||||
final var args = new Bundle();
|
final var args = new Bundle();
|
||||||
args.putParcelable(KEY_ATTRIBUTE, attribute);
|
args.putParcelable(KEY_ATTRIBUTE, attribute);
|
||||||
|
|
||||||
final var fragment = new AttrValueEditorSheet();
|
final var fragment = new AttrValueEditorSheet();
|
||||||
fragment.setArguments(args);
|
fragment.setArguments(args);
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(@NonNull Context context) {
|
public void onAttach(@NonNull Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
this.valueChangeListener = (BaseValueEditorFragment.OnValueChangeListener) getParentFragment();
|
this.valueChangeListener = (BaseValueEditorFragment.OnValueChangeListener) getParentFragment();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(
|
public View onCreateView(
|
||||||
@NonNull LayoutInflater inflater,
|
@NonNull LayoutInflater inflater,
|
||||||
@Nullable ViewGroup container,
|
@Nullable ViewGroup container,
|
||||||
@Nullable Bundle savedInstanceState) {
|
@Nullable Bundle savedInstanceState) {
|
||||||
this.binding = LayoutAttrValueEditorBinding.inflate(inflater, container, false);
|
this.binding = LayoutAttrValueEditorBinding.inflate(inflater, container, false);
|
||||||
return binding.getRoot();
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
if (attribute == null) {
|
if (attribute == null) {
|
||||||
this.attribute = requireArguments().getParcelable(KEY_ATTRIBUTE);
|
this.attribute = requireArguments().getParcelable(KEY_ATTRIBUTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
Objects.requireNonNull(this.attribute);
|
Objects.requireNonNull(this.attribute);
|
||||||
|
|
||||||
final var namespace = this.attribute.getNamespace();
|
final var namespace = this.attribute.getNamespace();
|
||||||
final var formatText = Attr.createFormatText(attribute.getFormat());
|
final var formatText = Attr.createFormatText(attribute.getFormat());
|
||||||
this.binding.attributeName.setText(
|
this.binding.attributeName.setText(
|
||||||
String.format("%s:%s", namespace.getPrefix(), attribute.getAttributeName()));
|
String.format("%s:%s", namespace.getPrefix(), attribute.getAttributeName()));
|
||||||
this.binding.attributeFormat.setText(formatText);
|
this.binding.attributeFormat.setText(formatText);
|
||||||
|
|
||||||
setupTabs(formatText);
|
setupTabs(formatText);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
private void setupTabs(@NonNull String formatText) {
|
private void setupTabs(@NonNull String formatText) {
|
||||||
this.binding.tabs.removeAllTabs();
|
this.binding.tabs.removeAllTabs();
|
||||||
this.binding.pager.setSaveEnabled(false);
|
this.binding.pager.setSaveEnabled(false);
|
||||||
|
|
||||||
if (this.adapter != null) {
|
if (this.adapter != null) {
|
||||||
this.adapter.removeAll();
|
this.adapter.removeAll();
|
||||||
this.adapter.notifyDataSetChanged();
|
this.adapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.adapter = new AttrValueFormatTabAdapter(getChildFragmentManager(), attribute);
|
this.adapter = new AttrValueFormatTabAdapter(getChildFragmentManager(), attribute);
|
||||||
|
|
||||||
final var formats = formatText.split("\\|");
|
final var formats = formatText.split("\\|");
|
||||||
for (var formatName : formats) {
|
for (var formatName : formats) {
|
||||||
if (TextUtils.isEmpty(formatName) || formatName.length() < 2) {
|
if (TextUtils.isEmpty(formatName) || formatName.length() < 2) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var frag = getFragmentClass(formatName);
|
final var frag = getFragmentClass(formatName);
|
||||||
if (frag != null) {
|
if (frag != null) {
|
||||||
this.adapter.addFragment(frag, formatName);
|
this.adapter.addFragment(frag, formatName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.pager.setAdapter(this.adapter);
|
binding.pager.setAdapter(this.adapter);
|
||||||
binding.tabs.setupWithViewPager(binding.pager);
|
binding.tabs.setupWithViewPager(binding.pager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
private Class<? extends BaseValueEditorFragment> getFragmentClass(@NonNull String name) {
|
private Class<? extends BaseValueEditorFragment> getFragmentClass(@NonNull String name) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case FORMAT_REFERENCE:
|
case FORMAT_REFERENCE:
|
||||||
return ReferenceEditor.class;
|
return ReferenceEditor.class;
|
||||||
case FORMAT_COLOR:
|
case FORMAT_COLOR:
|
||||||
return ColorEditor.class;
|
return ColorEditor.class;
|
||||||
case FORMAT_BOOLEAN:
|
case FORMAT_BOOLEAN:
|
||||||
return BooleanEditor.class;
|
return BooleanEditor.class;
|
||||||
case FORMAT_DIMENSION:
|
case FORMAT_DIMENSION:
|
||||||
return DimensionEditor.class;
|
return DimensionEditor.class;
|
||||||
case FORMAT_FLOAT:
|
case FORMAT_FLOAT:
|
||||||
return FloatEditor.class;
|
return FloatEditor.class;
|
||||||
case FORMAT_INTEGER:
|
case FORMAT_INTEGER:
|
||||||
return IntegerEditor.class;
|
return IntegerEditor.class;
|
||||||
case FORMAT_FRACTION:
|
case FORMAT_FRACTION:
|
||||||
return FractionEditor.class;
|
return FractionEditor.class;
|
||||||
case FORMAT_STRING:
|
case FORMAT_STRING:
|
||||||
return StringEditor.class;
|
return StringEditor.class;
|
||||||
case FORMAT_ENUM:
|
case FORMAT_ENUM:
|
||||||
return EnumEditor.class;
|
return EnumEditor.class;
|
||||||
case FORMAT_FLAG:
|
case FORMAT_FLAG:
|
||||||
return FlagEditor.class;
|
return FlagEditor.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAttribute(XMLAttribute attribute) {
|
public void setAttribute(XMLAttribute attribute) {
|
||||||
Objects.requireNonNull(attribute);
|
Objects.requireNonNull(attribute);
|
||||||
this.attribute = attribute;
|
this.attribute = attribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onValueChanged(IAttribute attribute, String newValue) {
|
public void onValueChanged(IAttribute attribute, String newValue) {
|
||||||
if (valueChangeListener != null) {
|
if (valueChangeListener != null) {
|
||||||
valueChangeListener.onValueChanged(attribute, newValue);
|
valueChangeListener.onValueChanged(attribute, newValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,169 +1,169 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.handlers
|
package com.itsaky.androidide.handlers
|
||||||
|
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.text.Layout.Alignment.ALIGN_CENTER
|
import android.text.Layout.Alignment.ALIGN_CENTER
|
||||||
import android.text.Layout.Alignment.ALIGN_NORMAL
|
import android.text.Layout.Alignment.ALIGN_NORMAL
|
||||||
import android.text.SpannableStringBuilder
|
import android.text.SpannableStringBuilder
|
||||||
import android.text.style.AlignmentSpan
|
import android.text.style.AlignmentSpan
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.webkit.URLUtil
|
import android.webkit.URLUtil
|
||||||
import androidx.core.view.GravityCompat
|
import androidx.core.view.GravityCompat
|
||||||
import com.itsaky.androidide.EditorActivity
|
import com.itsaky.androidide.EditorActivity
|
||||||
import com.itsaky.androidide.R.string
|
import com.itsaky.androidide.R.string
|
||||||
import com.itsaky.androidide.managers.PreferenceManager
|
import com.itsaky.androidide.managers.PreferenceManager
|
||||||
import com.itsaky.androidide.services.GradleBuildService
|
import com.itsaky.androidide.services.GradleBuildService
|
||||||
import com.itsaky.androidide.tooling.events.ProgressEvent
|
import com.itsaky.androidide.tooling.events.ProgressEvent
|
||||||
import com.itsaky.androidide.tooling.events.StatusEvent
|
import com.itsaky.androidide.tooling.events.StatusEvent
|
||||||
import com.itsaky.androidide.tooling.events.download.FileDownloadFinishEvent
|
import com.itsaky.androidide.tooling.events.download.FileDownloadFinishEvent
|
||||||
import com.itsaky.androidide.tooling.events.download.FileDownloadOperationDescriptor
|
import com.itsaky.androidide.tooling.events.download.FileDownloadOperationDescriptor
|
||||||
import com.itsaky.androidide.tooling.events.task.TaskProgressEvent
|
import com.itsaky.androidide.tooling.events.task.TaskProgressEvent
|
||||||
import com.itsaky.androidide.utils.DialogUtils
|
import com.itsaky.androidide.utils.DialogUtils
|
||||||
import com.itsaky.androidide.utils.ILogger
|
import com.itsaky.androidide.utils.ILogger
|
||||||
import com.itsaky.androidide.utils.StudioUtils
|
import com.itsaky.androidide.utils.StudioUtils
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles events received from [GradleBuildService] updates [EditorActivity].
|
* Handles events received from [GradleBuildService] updates [EditorActivity].
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
class EditorEventListener : GradleBuildService.EventListener {
|
class EditorEventListener : GradleBuildService.EventListener {
|
||||||
|
|
||||||
private var activityReference: WeakReference<EditorActivity?> = WeakReference(null)
|
private var activityReference: WeakReference<EditorActivity?> = WeakReference(null)
|
||||||
private val log = ILogger.newInstance(javaClass.simpleName)
|
private val log = ILogger.newInstance(javaClass.simpleName)
|
||||||
|
|
||||||
fun setActivity(activity: EditorActivity) {
|
fun setActivity(activity: EditorActivity) {
|
||||||
this.activityReference = WeakReference(activity)
|
this.activityReference = WeakReference(activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun prepareBuild() {
|
override fun prepareBuild() {
|
||||||
val isFirstBuild =
|
val isFirstBuild =
|
||||||
activity()
|
activity()
|
||||||
.app.prefManager.getBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, true)
|
.app.prefManager.getBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, true)
|
||||||
activity()
|
activity()
|
||||||
.setStatus(
|
.setStatus(
|
||||||
activity()
|
activity()
|
||||||
.getString(if (isFirstBuild) string.preparing_first else string.preparing))
|
.getString(if (isFirstBuild) string.preparing_first else string.preparing))
|
||||||
|
|
||||||
if (isFirstBuild) {
|
if (isFirstBuild) {
|
||||||
activity().showFirstBuildNotice()
|
activity().showFirstBuildNotice()
|
||||||
}
|
}
|
||||||
|
|
||||||
activity().binding.buildProgressIndicator.visibility = View.VISIBLE
|
activity().binding.buildProgressIndicator.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBuildSuccessful(tasks: MutableList<String>) {
|
override fun onBuildSuccessful(tasks: MutableList<String>) {
|
||||||
analyzeCurrentFile()
|
analyzeCurrentFile()
|
||||||
appendOutputSeparator()
|
appendOutputSeparator()
|
||||||
|
|
||||||
activity().app.prefManager.putBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false)
|
activity().app.prefManager.putBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false)
|
||||||
activity().binding.buildProgressIndicator.visibility = View.GONE
|
activity().binding.buildProgressIndicator.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onProgressEvent(event: ProgressEvent) {
|
override fun onProgressEvent(event: ProgressEvent) {
|
||||||
if (event is FileDownloadFinishEvent) {
|
if (event is FileDownloadFinishEvent) {
|
||||||
activity().setStatus("")
|
activity().setStatus("")
|
||||||
} else if (event is TaskProgressEvent) {
|
} else if (event is TaskProgressEvent) {
|
||||||
activity()
|
activity()
|
||||||
.setStatus(activity().getString(string.msg_running_task, event.descriptor.taskPath))
|
.setStatus(activity().getString(string.msg_running_task, event.descriptor.taskPath))
|
||||||
} else if (event is StatusEvent && event.descriptor is FileDownloadOperationDescriptor) {
|
} else if (event is StatusEvent && event.descriptor is FileDownloadOperationDescriptor) {
|
||||||
val total = StudioUtils.bytesToSizeString(event.total)
|
val total = StudioUtils.bytesToSizeString(event.total)
|
||||||
val progress = StudioUtils.bytesToSizeString(event.progress)
|
val progress = StudioUtils.bytesToSizeString(event.progress)
|
||||||
val fileName =
|
val fileName =
|
||||||
URLUtil.guessFileName(
|
URLUtil.guessFileName(
|
||||||
(event.descriptor as FileDownloadOperationDescriptor).uri.path, null, null)
|
(event.descriptor as FileDownloadOperationDescriptor).uri.path, null, null)
|
||||||
|
|
||||||
val status = SpannableStringBuilder()
|
val status = SpannableStringBuilder()
|
||||||
status.append(
|
status.append(
|
||||||
"[$progress/$total]",
|
"[$progress/$total]",
|
||||||
AlignmentSpan.Standard(ALIGN_NORMAL),
|
AlignmentSpan.Standard(ALIGN_NORMAL),
|
||||||
SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE)
|
SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
status.append(
|
status.append(
|
||||||
" Download $fileName",
|
" Download $fileName",
|
||||||
AlignmentSpan.Standard(ALIGN_CENTER),
|
AlignmentSpan.Standard(ALIGN_CENTER),
|
||||||
SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE)
|
SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
activity().setStatus(status, GravityCompat.START)
|
activity().setStatus(status, GravityCompat.START)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun appendOutputSeparator() {
|
private fun appendOutputSeparator() {
|
||||||
activity().appendBuildOut("\n\n")
|
activity().appendBuildOut("\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBuildFailed(tasks: MutableList<String>) {
|
override fun onBuildFailed(tasks: MutableList<String>) {
|
||||||
analyzeCurrentFile()
|
analyzeCurrentFile()
|
||||||
appendOutputSeparator()
|
appendOutputSeparator()
|
||||||
|
|
||||||
activity().app.prefManager.putBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false)
|
activity().app.prefManager.putBoolean(PreferenceManager.KEY_IS_FIRST_PROJECT_BUILD, false)
|
||||||
activity().binding.buildProgressIndicator.visibility = View.GONE
|
activity().binding.buildProgressIndicator.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOutput(line: String?) {
|
override fun onOutput(line: String?) {
|
||||||
activity().appendBuildOut(line)
|
activity().appendBuildOut(line)
|
||||||
|
|
||||||
// TODO This can be handled better when ProgressEvents are received from Tooling API server
|
// TODO This can be handled better when ProgressEvents are received from Tooling API server
|
||||||
if (line!!.contains("BUILD SUCCESSFUL") || line.contains("BUILD FAILED")) {
|
if (line!!.contains("BUILD SUCCESSFUL") || line.contains("BUILD FAILED")) {
|
||||||
activity().setStatus(line)
|
activity().setStatus(line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun analyzeCurrentFile() {
|
private fun analyzeCurrentFile() {
|
||||||
val editorView = activity().currentEditor
|
val editorView = activity().currentEditor
|
||||||
if (editorView != null) {
|
if (editorView != null) {
|
||||||
val editor = editorView.editor
|
val editor = editorView.editor
|
||||||
editor?.analyze()
|
editor?.analyze()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun activity(): EditorActivity {
|
fun activity(): EditorActivity {
|
||||||
return activityReference.get()
|
return activityReference.get()
|
||||||
?: throw IllegalStateException("Activity reference has been destroyed!")
|
?: throw IllegalStateException("Activity reference has been destroyed!")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun installApks(apks: Set<File>?) {
|
private fun installApks(apks: Set<File>?) {
|
||||||
if (apks == null || apks.isEmpty()) {
|
if (apks == null || apks.isEmpty()) {
|
||||||
IDEHandler.LOG.error("Cannot install APKs: $apks")
|
IDEHandler.LOG.error("Cannot install APKs: $apks")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (apks.size == 1) {
|
if (apks.size == 1) {
|
||||||
activity().install(apks.iterator().next())
|
activity().install(apks.iterator().next())
|
||||||
} else {
|
} else {
|
||||||
IDEHandler.LOG.info("Multiple APKs found. Let the user select...")
|
IDEHandler.LOG.info("Multiple APKs found. Let the user select...")
|
||||||
val files: List<File> = ArrayList(apks)
|
val files: List<File> = ArrayList(apks)
|
||||||
val builder = DialogUtils.newMaterialDialogBuilder(activity())
|
val builder = DialogUtils.newMaterialDialogBuilder(activity())
|
||||||
builder.setTitle(activity().getString(string.title_install_apks))
|
builder.setTitle(activity().getString(string.title_install_apks))
|
||||||
builder.setItems(getNames(files)) { d: DialogInterface, w: Int ->
|
builder.setItems(getNames(files)) { d: DialogInterface, w: Int ->
|
||||||
d.dismiss()
|
d.dismiss()
|
||||||
activity().install(files[w])
|
activity().install(files[w])
|
||||||
}
|
}
|
||||||
builder.show()
|
builder.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNames(apks: Collection<File>): Array<String?> {
|
private fun getNames(apks: Collection<File>): Array<String?> {
|
||||||
val names = arrayOfNulls<String>(apks.size)
|
val names = arrayOfNulls<String>(apks.size)
|
||||||
for ((i, apk) in apks.withIndex()) {
|
for ((i, apk) in apks.withIndex()) {
|
||||||
names[i] = apk.name
|
names[i] = apk.name
|
||||||
}
|
}
|
||||||
|
|
||||||
return names
|
return names
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +1,55 @@
|
|||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
**************************************************************************************/
|
**************************************************************************************/
|
||||||
package com.itsaky.androidide.handlers;
|
package com.itsaky.androidide.handlers;
|
||||||
|
|
||||||
import com.itsaky.androidide.EditorActivity;
|
import com.itsaky.androidide.EditorActivity;
|
||||||
import com.itsaky.androidide.utils.ILogger;
|
import com.itsaky.androidide.utils.ILogger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A handler is an implementation that handles a specific feature, data or anything else in
|
* A handler is an implementation that handles a specific feature, data or anything else in
|
||||||
* AndroidIDE
|
* AndroidIDE
|
||||||
*/
|
*/
|
||||||
public abstract class IDEHandler {
|
public abstract class IDEHandler {
|
||||||
|
|
||||||
protected static final ILogger LOG = ILogger.instance();
|
protected static final ILogger LOG = ILogger.instance();
|
||||||
|
|
||||||
protected Provider provider;
|
protected Provider provider;
|
||||||
|
|
||||||
public IDEHandler(Provider provider) {
|
public IDEHandler(Provider provider) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void start();
|
public abstract void start();
|
||||||
|
|
||||||
public abstract void stop();
|
public abstract void stop();
|
||||||
|
|
||||||
protected EditorActivity activity() {
|
protected EditorActivity activity() {
|
||||||
return provider.provideEditorActivity();
|
return provider.provideEditorActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An interface to communicate between a handler and its client */
|
/** An interface to communicate between a handler and its client */
|
||||||
public interface Provider {
|
public interface Provider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by handler to get a reference to {@link EditorActivity}
|
* Called by handler to get a reference to {@link EditorActivity}
|
||||||
*
|
*
|
||||||
* @throws NullPointerException is this is required
|
* @throws NullPointerException is this is required
|
||||||
*/
|
*/
|
||||||
EditorActivity provideEditorActivity();
|
EditorActivity provideEditorActivity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,128 +1,128 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.language;
|
package com.itsaky.androidide.language;
|
||||||
|
|
||||||
import com.itsaky.androidide.projects.ProjectManager;
|
import com.itsaky.androidide.projects.ProjectManager;
|
||||||
import com.itsaky.androidide.tooling.api.model.IdeGradleProject;
|
import com.itsaky.androidide.tooling.api.model.IdeGradleProject;
|
||||||
import com.itsaky.androidide.utils.ILogger;
|
import com.itsaky.androidide.utils.ILogger;
|
||||||
import com.itsaky.lsp.api.ILanguageServer;
|
import com.itsaky.lsp.api.ILanguageServer;
|
||||||
import com.itsaky.lsp.models.CompletionItem;
|
import com.itsaky.lsp.models.CompletionItem;
|
||||||
import com.itsaky.lsp.models.CompletionParams;
|
import com.itsaky.lsp.models.CompletionParams;
|
||||||
import com.itsaky.lsp.models.CompletionResult;
|
import com.itsaky.lsp.models.CompletionResult;
|
||||||
import com.itsaky.lsp.models.Position;
|
import com.itsaky.lsp.models.Position;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import io.github.rosemoe.sora.lang.completion.CompletionCancelledException;
|
import io.github.rosemoe.sora.lang.completion.CompletionCancelledException;
|
||||||
import io.github.rosemoe.sora.lang.completion.CompletionHelper;
|
import io.github.rosemoe.sora.lang.completion.CompletionHelper;
|
||||||
import io.github.rosemoe.sora.text.CharPosition;
|
import io.github.rosemoe.sora.text.CharPosition;
|
||||||
import io.github.rosemoe.sora.text.ContentReference;
|
import io.github.rosemoe.sora.text.ContentReference;
|
||||||
import io.github.rosemoe.sora.util.MyCharacter;
|
import io.github.rosemoe.sora.util.MyCharacter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common implementation of completion provider which requests completions to provided language
|
* Common implementation of completion provider which requests completions to provided language
|
||||||
* server.
|
* server.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
public class CommonCompletionProvider {
|
public class CommonCompletionProvider {
|
||||||
|
|
||||||
private static final ILogger LOG = ILogger.newInstance("CommonCompletionProvider");
|
private static final ILogger LOG = ILogger.newInstance("CommonCompletionProvider");
|
||||||
private final ILanguageServer server;
|
private final ILanguageServer server;
|
||||||
private CompletableFuture<CompletionResult> future;
|
private CompletableFuture<CompletionResult> future;
|
||||||
|
|
||||||
public CommonCompletionProvider(ILanguageServer server) {
|
public CommonCompletionProvider(ILanguageServer server) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean checkJavaCompletionChar(char c) {
|
public static boolean checkJavaCompletionChar(char c) {
|
||||||
return MyCharacter.isJavaIdentifierPart(c) || c == '.';
|
return MyCharacter.isJavaIdentifierPart(c) || c == '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean checkXMLCompletionChar(char c) {
|
public static boolean checkXMLCompletionChar(char c) {
|
||||||
return MyCharacter.isJavaIdentifierPart(c) || c == '<' || c == '/';
|
return MyCharacter.isJavaIdentifierPart(c) || c == '<' || c == '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes completion items using the provided language server instance.
|
* Computes completion items using the provided language server instance.
|
||||||
*
|
*
|
||||||
* @param content The reference to the content of the editor.
|
* @param content The reference to the content of the editor.
|
||||||
* @param file The file to compute completions for.
|
* @param file The file to compute completions for.
|
||||||
* @param position The position of the cursor in the content.
|
* @param position The position of the cursor in the content.
|
||||||
* @return The computed completion items. May return an empty list if the there was an error
|
* @return The computed completion items. May return an empty list if the there was an error
|
||||||
* computing the completion items.
|
* computing the completion items.
|
||||||
*/
|
*/
|
||||||
public List<CompletionItem> complete(
|
public List<CompletionItem> complete(
|
||||||
ContentReference content,
|
ContentReference content,
|
||||||
Path file,
|
Path file,
|
||||||
CharPosition position,
|
CharPosition position,
|
||||||
Predicate<Character> prefixMatcher) {
|
Predicate<Character> prefixMatcher) {
|
||||||
if (this.future != null && !this.future.isDone()) {
|
if (this.future != null && !this.future.isDone()) {
|
||||||
try {
|
try {
|
||||||
this.future.cancel(true);
|
this.future.cancel(true);
|
||||||
} catch (CancellationException e) {
|
} catch (CancellationException e) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.future =
|
this.future =
|
||||||
CompletableFuture.supplyAsync(
|
CompletableFuture.supplyAsync(
|
||||||
() -> {
|
() -> {
|
||||||
final var prefix =
|
final var prefix =
|
||||||
CompletionHelper.computePrefix(content, position, prefixMatcher::test);
|
CompletionHelper.computePrefix(content, position, prefixMatcher::test);
|
||||||
final var completer = server.getCompletionProvider();
|
final var completer = server.getCompletionProvider();
|
||||||
|
|
||||||
if (!completer.canComplete(file)) {
|
if (!completer.canComplete(file)) {
|
||||||
return CompletionResult.EMPTY;
|
return CompletionResult.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdeGradleProject fileModule = null;
|
IdeGradleProject fileModule = null;
|
||||||
try {
|
try {
|
||||||
fileModule = ProjectManager.INSTANCE.findModuleForFile(file.toFile()).get();
|
fileModule = ProjectManager.INSTANCE.findModuleForFile(file.toFile()).get();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOG.error("Unable to find module for current file", e);
|
LOG.error("Unable to find module for current file", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
final var params =
|
final var params =
|
||||||
new CompletionParams(
|
new CompletionParams(
|
||||||
new Position(position.line, position.column, position.index), file);
|
new Position(position.line, position.column, position.index), file);
|
||||||
params.setContent(content);
|
params.setContent(content);
|
||||||
params.setPrefix(prefix);
|
params.setPrefix(prefix);
|
||||||
params.setModule(fileModule);
|
params.setModule(fileModule);
|
||||||
return completer.complete(params);
|
return completer.complete(params);
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final var items = future.get ().getItems ();
|
final var items = future.get ().getItems ();
|
||||||
return items;
|
return items;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
// Do not log if completion was interrupted or cancelled
|
// Do not log if completion was interrupted or cancelled
|
||||||
if (!(e instanceof InterruptedException || e instanceof CompletionCancelledException)) {
|
if (!(e instanceof InterruptedException || e instanceof CompletionCancelledException)) {
|
||||||
LOG.error("Unable to compute completions", e);
|
LOG.error("Unable to compute completions", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,47 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.language;
|
package com.itsaky.androidide.language;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.itsaky.lsp.models.DiagnosticItem;
|
import com.itsaky.lsp.models.DiagnosticItem;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for analyze managers.
|
* Base class for analyze managers.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
public interface IAnalyzeManager {
|
public interface IAnalyzeManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the diagnostic items.
|
* Update the diagnostic items.
|
||||||
*
|
*
|
||||||
* @param diagnostics The new list of diagnostics.
|
* @param diagnostics The new list of diagnostics.
|
||||||
*/
|
*/
|
||||||
default void updateDiagnostics(@NonNull List<DiagnosticItem> diagnostics) {}
|
default void updateDiagnostics(@NonNull List<DiagnosticItem> diagnostics) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the diagnostic items.
|
* Get the diagnostic items.
|
||||||
*
|
*
|
||||||
* @return The diagnostic items. Must not be <code>null</code>.
|
* @return The diagnostic items. Must not be <code>null</code>.
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
List<DiagnosticItem> getDiagnostics();
|
List<DiagnosticItem> getDiagnostics();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,154 +1,154 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.language.xml;
|
package com.itsaky.androidide.language.xml;
|
||||||
|
|
||||||
import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.OPERATOR;
|
import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.OPERATOR;
|
||||||
import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.forComment;
|
import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.forComment;
|
||||||
import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.get;
|
import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.get;
|
||||||
import static io.github.rosemoe.sora.widget.schemes.EditorColorScheme.LITERAL;
|
import static io.github.rosemoe.sora.widget.schemes.EditorColorScheme.LITERAL;
|
||||||
|
|
||||||
import com.itsaky.androidide.lexers.xml.XMLLexer;
|
import com.itsaky.androidide.lexers.xml.XMLLexer;
|
||||||
import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE;
|
import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE;
|
||||||
import com.itsaky.androidide.utils.CharSequenceReader;
|
import com.itsaky.androidide.utils.CharSequenceReader;
|
||||||
import com.itsaky.androidide.utils.ILogger;
|
import com.itsaky.androidide.utils.ILogger;
|
||||||
|
|
||||||
import org.antlr.v4.runtime.CharStreams;
|
import org.antlr.v4.runtime.CharStreams;
|
||||||
import org.antlr.v4.runtime.CodePointCharStream;
|
import org.antlr.v4.runtime.CodePointCharStream;
|
||||||
import org.antlr.v4.runtime.Token;
|
import org.antlr.v4.runtime.Token;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
import io.github.rosemoe.sora.lang.analysis.SimpleAnalyzeManager;
|
import io.github.rosemoe.sora.lang.analysis.SimpleAnalyzeManager;
|
||||||
import io.github.rosemoe.sora.lang.styling.CodeBlock;
|
import io.github.rosemoe.sora.lang.styling.CodeBlock;
|
||||||
import io.github.rosemoe.sora.lang.styling.MappedSpans;
|
import io.github.rosemoe.sora.lang.styling.MappedSpans;
|
||||||
import io.github.rosemoe.sora.lang.styling.Styles;
|
import io.github.rosemoe.sora.lang.styling.Styles;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple analyzer implementation for the XML files.
|
* Simple analyzer implementation for the XML files.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
public class XMLAnalyzer extends SimpleAnalyzeManager<Void> {
|
public class XMLAnalyzer extends SimpleAnalyzeManager<Void> {
|
||||||
|
|
||||||
private static final ILogger LOG = ILogger.newInstance("XMLAnalyzer");
|
private static final ILogger LOG = ILogger.newInstance("XMLAnalyzer");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Styles analyze(StringBuilder text, Delegate<Void> delegate) {
|
protected Styles analyze(StringBuilder text, Delegate<Void> delegate) {
|
||||||
final var styles = new Styles();
|
final var styles = new Styles();
|
||||||
final var colors = new MappedSpans.Builder();
|
final var colors = new MappedSpans.Builder();
|
||||||
|
|
||||||
CodePointCharStream stream;
|
CodePointCharStream stream;
|
||||||
try {
|
try {
|
||||||
stream = CharStreams.fromReader(new CharSequenceReader(text));
|
stream = CharStreams.fromReader(new CharSequenceReader(text));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.error("Unable to create stream for analyze", e);
|
LOG.error("Unable to create stream for analyze", e);
|
||||||
return styles;
|
return styles;
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLLexer lexer = new XMLLexer(stream);
|
XMLLexer lexer = new XMLLexer(stream);
|
||||||
Token token;
|
Token token;
|
||||||
int previous = 0;
|
int previous = 0;
|
||||||
int line, column, lastLine = 1;
|
int line, column, lastLine = 1;
|
||||||
var first = true;
|
var first = true;
|
||||||
|
|
||||||
final var stack = new Stack<CodeBlock>();
|
final var stack = new Stack<CodeBlock>();
|
||||||
|
|
||||||
while (!delegate.isCancelled()) {
|
while (!delegate.isCancelled()) {
|
||||||
token = lexer.nextToken();
|
token = lexer.nextToken();
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.getType() == XMLLexer.EOF) {
|
if (token.getType() == XMLLexer.EOF) {
|
||||||
lastLine = token.getLine() - 1;
|
lastLine = token.getLine() - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
line = token.getLine() - 1;
|
line = token.getLine() - 1;
|
||||||
column = token.getCharPositionInLine();
|
column = token.getCharPositionInLine();
|
||||||
lastLine = line;
|
lastLine = line;
|
||||||
|
|
||||||
switch (token.getType()) {
|
switch (token.getType()) {
|
||||||
case XMLLexer.S:
|
case XMLLexer.S:
|
||||||
case XMLLexer.SEA_WS:
|
case XMLLexer.SEA_WS:
|
||||||
if (first) {
|
if (first) {
|
||||||
colors.addNormalIfNull();
|
colors.addNormalIfNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case XMLLexer.COMMENT:
|
case XMLLexer.COMMENT:
|
||||||
colors.addIfNeeded(line, column, forComment());
|
colors.addIfNeeded(line, column, forComment());
|
||||||
break;
|
break;
|
||||||
case XMLLexer.OPEN:
|
case XMLLexer.OPEN:
|
||||||
case XMLLexer.OPEN_SLASH:
|
case XMLLexer.OPEN_SLASH:
|
||||||
case XMLLexer.CLOSE:
|
case XMLLexer.CLOSE:
|
||||||
case XMLLexer.SLASH:
|
case XMLLexer.SLASH:
|
||||||
case XMLLexer.SPECIAL_CLOSE:
|
case XMLLexer.SPECIAL_CLOSE:
|
||||||
case XMLLexer.EQUALS:
|
case XMLLexer.EQUALS:
|
||||||
case XMLLexer.COLON:
|
case XMLLexer.COLON:
|
||||||
case XMLLexer.XMLDeclOpen:
|
case XMLLexer.XMLDeclOpen:
|
||||||
colors.addIfNeeded(line, column, get(OPERATOR));
|
colors.addIfNeeded(line, column, get(OPERATOR));
|
||||||
break;
|
break;
|
||||||
case XMLLexer.SLASH_CLOSE:
|
case XMLLexer.SLASH_CLOSE:
|
||||||
colors.addIfNeeded(line, column, get(OPERATOR));
|
colors.addIfNeeded(line, column, get(OPERATOR));
|
||||||
final var closeBlock = stack.pop();
|
final var closeBlock = stack.pop();
|
||||||
closeBlock.endLine = line;
|
closeBlock.endLine = line;
|
||||||
closeBlock.endColumn = column;
|
closeBlock.endColumn = column;
|
||||||
styles.addCodeBlock(closeBlock);
|
styles.addCodeBlock(closeBlock);
|
||||||
break;
|
break;
|
||||||
case XMLLexer.STRING:
|
case XMLLexer.STRING:
|
||||||
colors.addIfNeeded(line, column, LITERAL);
|
colors.addIfNeeded(line, column, LITERAL);
|
||||||
break;
|
break;
|
||||||
case XMLLexer.Name:
|
case XMLLexer.Name:
|
||||||
var type = SchemeAndroidIDE.TEXT_NORMAL;
|
var type = SchemeAndroidIDE.TEXT_NORMAL;
|
||||||
if (previous == XMLLexer.OPEN) {
|
if (previous == XMLLexer.OPEN) {
|
||||||
type = SchemeAndroidIDE.XML_TAG;
|
type = SchemeAndroidIDE.XML_TAG;
|
||||||
final var block = styles.obtainNewBlock();
|
final var block = styles.obtainNewBlock();
|
||||||
block.startLine = line;
|
block.startLine = line;
|
||||||
block.startColumn = column;
|
block.startColumn = column;
|
||||||
stack.push(block);
|
stack.push(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previous == XMLLexer.OPEN_SLASH) {
|
if (previous == XMLLexer.OPEN_SLASH) {
|
||||||
type = SchemeAndroidIDE.XML_TAG;
|
type = SchemeAndroidIDE.XML_TAG;
|
||||||
final var block = stack.pop();
|
final var block = stack.pop();
|
||||||
block.endLine = line;
|
block.endLine = line;
|
||||||
block.endColumn = column;
|
block.endColumn = column;
|
||||||
styles.addCodeBlock(block);
|
styles.addCodeBlock(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
colors.addIfNeeded(line, column, get(type));
|
colors.addIfNeeded(line, column, get(type));
|
||||||
break;
|
break;
|
||||||
case XMLLexer.TEXT:
|
case XMLLexer.TEXT:
|
||||||
default:
|
default:
|
||||||
colors.addIfNeeded(line, column, get(SchemeAndroidIDE.TEXT_NORMAL));
|
colors.addIfNeeded(line, column, get(SchemeAndroidIDE.TEXT_NORMAL));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
if (token.getType() != XMLLexer.SEA_WS) {
|
if (token.getType() != XMLLexer.SEA_WS) {
|
||||||
previous = token.getType();
|
previous = token.getType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
colors.determine(lastLine);
|
colors.determine(lastLine);
|
||||||
|
|
||||||
styles.spans = colors.build();
|
styles.spans = colors.build();
|
||||||
|
|
||||||
return styles;
|
return styles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,147 +1,147 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.language.xml;
|
package com.itsaky.androidide.language.xml;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.itsaky.androidide.app.StudioApp;
|
import com.itsaky.androidide.app.StudioApp;
|
||||||
import com.itsaky.androidide.language.CommonCompletionProvider;
|
import com.itsaky.androidide.language.CommonCompletionProvider;
|
||||||
import com.itsaky.androidide.language.IDELanguage;
|
import com.itsaky.androidide.language.IDELanguage;
|
||||||
import com.itsaky.androidide.lexers.xml.XMLLexer;
|
import com.itsaky.androidide.lexers.xml.XMLLexer;
|
||||||
import com.itsaky.androidide.utils.ILogger;
|
import com.itsaky.androidide.utils.ILogger;
|
||||||
import com.itsaky.androidide.utils.JavaCharacter;
|
import com.itsaky.androidide.utils.JavaCharacter;
|
||||||
import com.itsaky.androidide.views.editor.IDEEditor;
|
import com.itsaky.androidide.views.editor.IDEEditor;
|
||||||
import com.itsaky.lsp.api.ILanguageServer;
|
import com.itsaky.lsp.api.ILanguageServer;
|
||||||
|
|
||||||
import org.antlr.v4.runtime.CharStreams;
|
import org.antlr.v4.runtime.CharStreams;
|
||||||
import org.antlr.v4.runtime.Token;
|
import org.antlr.v4.runtime.Token;
|
||||||
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import io.github.rosemoe.sora.lang.analysis.AnalyzeManager;
|
import io.github.rosemoe.sora.lang.analysis.AnalyzeManager;
|
||||||
import io.github.rosemoe.sora.lang.completion.CompletionCancelledException;
|
import io.github.rosemoe.sora.lang.completion.CompletionCancelledException;
|
||||||
import io.github.rosemoe.sora.lang.completion.CompletionPublisher;
|
import io.github.rosemoe.sora.lang.completion.CompletionPublisher;
|
||||||
import io.github.rosemoe.sora.lang.smartEnter.NewlineHandler;
|
import io.github.rosemoe.sora.lang.smartEnter.NewlineHandler;
|
||||||
import io.github.rosemoe.sora.text.CharPosition;
|
import io.github.rosemoe.sora.text.CharPosition;
|
||||||
import io.github.rosemoe.sora.text.ContentReference;
|
import io.github.rosemoe.sora.text.ContentReference;
|
||||||
import io.github.rosemoe.sora.widget.SymbolPairMatch;
|
import io.github.rosemoe.sora.widget.SymbolPairMatch;
|
||||||
|
|
||||||
public class XMLLanguage extends IDELanguage {
|
public class XMLLanguage extends IDELanguage {
|
||||||
|
|
||||||
private static final ILogger LOG = ILogger.newInstance("XMLLanguage");
|
private static final ILogger LOG = ILogger.newInstance("XMLLanguage");
|
||||||
private final CommonCompletionProvider completer;
|
private final CommonCompletionProvider completer;
|
||||||
private final NewlineHandler[] newlineHandlers;
|
private final NewlineHandler[] newlineHandlers;
|
||||||
private XMLAnalyzer analyzer;
|
private XMLAnalyzer analyzer;
|
||||||
|
|
||||||
public XMLLanguage() {
|
public XMLLanguage() {
|
||||||
this.completer = new CommonCompletionProvider(getLanguageServer());
|
this.completer = new CommonCompletionProvider(getLanguageServer());
|
||||||
this.analyzer = new XMLAnalyzer();
|
this.analyzer = new XMLAnalyzer();
|
||||||
this.newlineHandlers = new NewlineHandler[0];
|
this.newlineHandlers = new NewlineHandler[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAutoCompleteChar(char ch) {
|
public boolean isAutoCompleteChar(char ch) {
|
||||||
return JavaCharacter.isJavaIdentifierPart(ch) || ch == '<' || ch == '/';
|
return JavaCharacter.isJavaIdentifierPart(ch) || ch == '<' || ch == '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getIndentAdvance(@NonNull String content) {
|
public int getIndentAdvance(@NonNull String content) {
|
||||||
try {
|
try {
|
||||||
XMLLexer lexer = new XMLLexer(CharStreams.fromReader(new StringReader(content)));
|
XMLLexer lexer = new XMLLexer(CharStreams.fromReader(new StringReader(content)));
|
||||||
Token token;
|
Token token;
|
||||||
int advance = 0;
|
int advance = 0;
|
||||||
while (((token = lexer.nextToken()) != null && token.getType() != token.EOF)) {
|
while (((token = lexer.nextToken()) != null && token.getType() != token.EOF)) {
|
||||||
switch (token.getType()) {
|
switch (token.getType()) {
|
||||||
case XMLLexer.OPEN:
|
case XMLLexer.OPEN:
|
||||||
advance++;
|
advance++;
|
||||||
break;
|
break;
|
||||||
case XMLLexer.CLOSE:
|
case XMLLexer.CLOSE:
|
||||||
case XMLLexer.SLASH_CLOSE:
|
case XMLLexer.SLASH_CLOSE:
|
||||||
advance--;
|
advance--;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
advance = Math.max(0, advance);
|
advance = Math.max(0, advance);
|
||||||
return advance * getTabSize();
|
return advance * getTabSize();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOG.error("Failed to compute indent advance", e);
|
LOG.error("Failed to compute indent advance", e);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SymbolPairMatch getSymbolPairs() {
|
public SymbolPairMatch getSymbolPairs() {
|
||||||
return new SymbolPairMatch.DefaultSymbolPairs();
|
return new SymbolPairMatch.DefaultSymbolPairs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public AnalyzeManager getAnalyzeManager() {
|
public AnalyzeManager getAnalyzeManager() {
|
||||||
return analyzer;
|
return analyzer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getInterruptionLevel() {
|
public int getInterruptionLevel() {
|
||||||
return INTERRUPTION_LEVEL_STRONG;
|
return INTERRUPTION_LEVEL_STRONG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void requireAutoComplete(
|
public void requireAutoComplete(
|
||||||
@NonNull ContentReference content,
|
@NonNull ContentReference content,
|
||||||
@NonNull CharPosition position,
|
@NonNull CharPosition position,
|
||||||
@NonNull CompletionPublisher publisher,
|
@NonNull CompletionPublisher publisher,
|
||||||
@NonNull Bundle extraArguments)
|
@NonNull Bundle extraArguments)
|
||||||
throws CompletionCancelledException {
|
throws CompletionCancelledException {
|
||||||
if (!extraArguments.containsKey(IDEEditor.KEY_FILE)) {
|
if (!extraArguments.containsKey(IDEEditor.KEY_FILE)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var file = Paths.get(extraArguments.getString(IDEEditor.KEY_FILE));
|
final var file = Paths.get(extraArguments.getString(IDEEditor.KEY_FILE));
|
||||||
publisher.setUpdateThreshold(0);
|
publisher.setUpdateThreshold(0);
|
||||||
publisher.addItems(
|
publisher.addItems(
|
||||||
new ArrayList<>(
|
new ArrayList<>(
|
||||||
completer.complete(
|
completer.complete(
|
||||||
content, file, position, CommonCompletionProvider::checkXMLCompletionChar)));
|
content, file, position, CommonCompletionProvider::checkXMLCompletionChar)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getIndentAdvance(@NonNull ContentReference content, int line, int column) {
|
public int getIndentAdvance(@NonNull ContentReference content, int line, int column) {
|
||||||
final var text = content.getLine(line).substring(0, column);
|
final var text = content.getLine(line).substring(0, column);
|
||||||
return getIndentAdvance(text.trim());
|
return getIndentAdvance(text.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ILanguageServer getLanguageServer() {
|
protected ILanguageServer getLanguageServer() {
|
||||||
return StudioApp.getInstance().getXMLLanguageServer();
|
return StudioApp.getInstance().getXMLLanguageServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NewlineHandler[] getNewlineHandlers() {
|
public NewlineHandler[] getNewlineHandlers() {
|
||||||
return newlineHandlers;
|
return newlineHandlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
analyzer = null;
|
analyzer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,407 +1,407 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.lsp;
|
package com.itsaky.androidide.lsp;
|
||||||
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.blankj.utilcode.util.FileIOUtils;
|
import com.blankj.utilcode.util.FileIOUtils;
|
||||||
import com.blankj.utilcode.util.FileUtils;
|
import com.blankj.utilcode.util.FileUtils;
|
||||||
import com.blankj.utilcode.util.ThreadUtils;
|
import com.blankj.utilcode.util.ThreadUtils;
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.itsaky.androidide.EditorActivity;
|
import com.itsaky.androidide.EditorActivity;
|
||||||
import com.itsaky.androidide.R;
|
import com.itsaky.androidide.R;
|
||||||
import com.itsaky.androidide.adapters.DiagnosticsAdapter;
|
import com.itsaky.androidide.adapters.DiagnosticsAdapter;
|
||||||
import com.itsaky.androidide.adapters.SearchListAdapter;
|
import com.itsaky.androidide.adapters.SearchListAdapter;
|
||||||
import com.itsaky.androidide.app.StudioApp;
|
import com.itsaky.androidide.app.StudioApp;
|
||||||
import com.itsaky.androidide.fragments.sheets.ProgressSheet;
|
import com.itsaky.androidide.fragments.sheets.ProgressSheet;
|
||||||
import com.itsaky.androidide.interfaces.EditorActivityProvider;
|
import com.itsaky.androidide.interfaces.EditorActivityProvider;
|
||||||
import com.itsaky.androidide.language.IDELanguage;
|
import com.itsaky.androidide.language.IDELanguage;
|
||||||
import com.itsaky.androidide.models.DiagnosticGroup;
|
import com.itsaky.androidide.models.DiagnosticGroup;
|
||||||
import com.itsaky.androidide.models.SearchResult;
|
import com.itsaky.androidide.models.SearchResult;
|
||||||
import com.itsaky.androidide.tasks.TaskExecutor;
|
import com.itsaky.androidide.tasks.TaskExecutor;
|
||||||
import com.itsaky.androidide.utils.DialogUtils;
|
import com.itsaky.androidide.utils.DialogUtils;
|
||||||
import com.itsaky.androidide.utils.ILogger;
|
import com.itsaky.androidide.utils.ILogger;
|
||||||
import com.itsaky.androidide.utils.LSPUtils;
|
import com.itsaky.androidide.utils.LSPUtils;
|
||||||
import com.itsaky.androidide.views.editor.CodeEditorView;
|
import com.itsaky.androidide.views.editor.CodeEditorView;
|
||||||
import com.itsaky.androidide.views.editor.IDEEditor;
|
import com.itsaky.androidide.views.editor.IDEEditor;
|
||||||
import com.itsaky.lsp.api.ILanguageClient;
|
import com.itsaky.lsp.api.ILanguageClient;
|
||||||
import com.itsaky.lsp.models.CodeActionItem;
|
import com.itsaky.lsp.models.CodeActionItem;
|
||||||
import com.itsaky.lsp.models.Command;
|
import com.itsaky.lsp.models.Command;
|
||||||
import com.itsaky.lsp.models.DiagnosticItem;
|
import com.itsaky.lsp.models.DiagnosticItem;
|
||||||
import com.itsaky.lsp.models.DiagnosticResult;
|
import com.itsaky.lsp.models.DiagnosticResult;
|
||||||
import com.itsaky.lsp.models.Location;
|
import com.itsaky.lsp.models.Location;
|
||||||
import com.itsaky.lsp.models.Range;
|
import com.itsaky.lsp.models.Range;
|
||||||
import com.itsaky.lsp.models.TextEdit;
|
import com.itsaky.lsp.models.TextEdit;
|
||||||
import com.itsaky.toaster.Toaster;
|
import com.itsaky.toaster.Toaster;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import io.github.rosemoe.sora.text.Content;
|
import io.github.rosemoe.sora.text.Content;
|
||||||
|
|
||||||
/** AndroidIDE specific implementation of the LanguageClient */
|
/** AndroidIDE specific implementation of the LanguageClient */
|
||||||
public class IDELanguageClientImpl implements ILanguageClient {
|
public class IDELanguageClientImpl implements ILanguageClient {
|
||||||
|
|
||||||
protected static final Gson gson = new Gson();
|
protected static final Gson gson = new Gson();
|
||||||
protected static final ILogger LOG = ILogger.newInstance("AbstractLanguageClient");
|
protected static final ILogger LOG = ILogger.newInstance("AbstractLanguageClient");
|
||||||
private static IDELanguageClientImpl mInstance;
|
private static IDELanguageClientImpl mInstance;
|
||||||
private final Map<File, List<DiagnosticItem>> diagnostics = new HashMap<>();
|
private final Map<File, List<DiagnosticItem>> diagnostics = new HashMap<>();
|
||||||
protected EditorActivityProvider activityProvider;
|
protected EditorActivityProvider activityProvider;
|
||||||
|
|
||||||
private IDELanguageClientImpl(EditorActivityProvider provider) {
|
private IDELanguageClientImpl(EditorActivityProvider provider) {
|
||||||
setActivityProvider(provider);
|
setActivityProvider(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IDELanguageClientImpl getInstance() {
|
public static IDELanguageClientImpl getInstance() {
|
||||||
if (mInstance == null) {
|
if (mInstance == null) {
|
||||||
throw new IllegalStateException("Client not initialized");
|
throw new IllegalStateException("Client not initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
return mInstance;
|
return mInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IDELanguageClientImpl initialize(EditorActivityProvider provider) {
|
public static IDELanguageClientImpl initialize(EditorActivityProvider provider) {
|
||||||
if (mInstance != null) {
|
if (mInstance != null) {
|
||||||
throw new IllegalStateException("Client is already initialized");
|
throw new IllegalStateException("Client is already initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
mInstance = new IDELanguageClientImpl(provider);
|
mInstance = new IDELanguageClientImpl(provider);
|
||||||
|
|
||||||
return getInstance();
|
return getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void shutdown() {
|
public static void shutdown() {
|
||||||
mInstance = null;
|
mInstance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isInitialized() {
|
public static boolean isInitialized() {
|
||||||
return mInstance != null;
|
return mInstance != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setActivityProvider(EditorActivityProvider provider) {
|
public void setActivityProvider(EditorActivityProvider provider) {
|
||||||
this.activityProvider = provider;
|
this.activityProvider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected EditorActivity activity() {
|
protected EditorActivity activity() {
|
||||||
if (activityProvider == null) return null;
|
if (activityProvider == null) return null;
|
||||||
return activityProvider.provide();
|
return activityProvider.provide();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodeEditorView findEditorByFile(File file) {
|
private CodeEditorView findEditorByFile(File file) {
|
||||||
return activity().getEditorForFile(file);
|
return activity().getEditorForFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void hideDiagnostics() {
|
public void hideDiagnostics() {
|
||||||
if (activity() == null || activity().getDiagnosticBinding() == null) {
|
if (activity() == null || activity().getDiagnosticBinding() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
activity().getDiagnosticBinding().getRoot().setVisibility(View.GONE);
|
activity().getDiagnosticBinding().getRoot().setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hideBottomDiagnosticView(final File file) {
|
private void hideBottomDiagnosticView(final File file) {
|
||||||
if (activity() == null || file == null) {
|
if (activity() == null || file == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var frag = findEditorByFile(file);
|
final var frag = findEditorByFile(file);
|
||||||
if (frag == null || frag.getBinding() == null) {
|
if (frag == null || frag.getBinding() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
frag.getBinding().diagnosticTextContainer.setVisibility(View.GONE);
|
frag.getBinding().diagnosticTextContainer.setVisibility(View.GONE);
|
||||||
frag.getBinding().diagnosticText.setVisibility(View.GONE);
|
frag.getBinding().diagnosticText.setVisibility(View.GONE);
|
||||||
frag.getBinding().diagnosticText.setClickable(false);
|
frag.getBinding().diagnosticText.setClickable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void publishDiagnostics(DiagnosticResult result) {
|
public void publishDiagnostics(DiagnosticResult result) {
|
||||||
boolean error = result == null;
|
boolean error = result == null;
|
||||||
activity().handleDiagnosticsResultVisibility(error || result.getDiagnostics().isEmpty());
|
activity().handleDiagnosticsResultVisibility(error || result.getDiagnostics().isEmpty());
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
File file = result.getFile().toFile();
|
File file = result.getFile().toFile();
|
||||||
if (!file.exists() || !file.isFile()) return;
|
if (!file.exists() || !file.isFile()) return;
|
||||||
|
|
||||||
final var editorView = activity().getEditorForFile(file);
|
final var editorView = activity().getEditorForFile(file);
|
||||||
if (editorView != null) {
|
if (editorView != null) {
|
||||||
final var editor = editorView.getEditor();
|
final var editor = editorView.getEditor();
|
||||||
if (editor != null) {
|
if (editor != null) {
|
||||||
final var editorLanguage = editor.getEditorLanguage();
|
final var editorLanguage = editor.getEditorLanguage();
|
||||||
if (editorLanguage instanceof IDELanguage) {
|
if (editorLanguage instanceof IDELanguage) {
|
||||||
((IDELanguage) editorLanguage).setDiagnostics(result.getDiagnostics());
|
((IDELanguage) editorLanguage).setDiagnostics(result.getDiagnostics());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostics.put(file, result.getDiagnostics());
|
diagnostics.put(file, result.getDiagnostics());
|
||||||
activity().setDiagnosticsAdapter(newDiagnosticsAdapter());
|
activity().setDiagnosticsAdapter(newDiagnosticsAdapter());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called by {@link IDEEditor IDEEditor} to show locations in EditorActivity */
|
/** Called by {@link IDEEditor IDEEditor} to show locations in EditorActivity */
|
||||||
public void showLocations(List<Location> locations) {
|
public void showLocations(List<Location> locations) {
|
||||||
|
|
||||||
// Cannot show anything if the activity() is null
|
// Cannot show anything if the activity() is null
|
||||||
if (activity() == null) {
|
if (activity() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean error = locations == null || locations.isEmpty();
|
boolean error = locations == null || locations.isEmpty();
|
||||||
activity().handleSearchResultVisibility(error);
|
activity().handleSearchResultVisibility(error);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
activity().setSearchResultAdapter(new SearchListAdapter(null, null, null));
|
activity().setSearchResultAdapter(new SearchListAdapter(null, null, null));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Map<File, List<SearchResult>> results = new HashMap<>();
|
final Map<File, List<SearchResult>> results = new HashMap<>();
|
||||||
for (int i = 0; i < locations.size(); i++) {
|
for (int i = 0; i < locations.size(); i++) {
|
||||||
try {
|
try {
|
||||||
final Location loc = locations.get(i);
|
final Location loc = locations.get(i);
|
||||||
if (loc == null) {
|
if (loc == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final File file = loc.getFile().toFile();
|
final File file = loc.getFile().toFile();
|
||||||
if (!file.exists() || !file.isFile()) continue;
|
if (!file.exists() || !file.isFile()) continue;
|
||||||
var frag = findEditorByFile(file);
|
var frag = findEditorByFile(file);
|
||||||
Content content;
|
Content content;
|
||||||
if (frag != null && frag.getEditor() != null) content = frag.getEditor().getText();
|
if (frag != null && frag.getEditor() != null) content = frag.getEditor().getText();
|
||||||
else content = new Content(FileIOUtils.readFile2String(file));
|
else content = new Content(FileIOUtils.readFile2String(file));
|
||||||
final List<SearchResult> matches =
|
final List<SearchResult> matches =
|
||||||
results.containsKey(file) ? results.get(file) : new ArrayList<>();
|
results.containsKey(file) ? results.get(file) : new ArrayList<>();
|
||||||
Objects.requireNonNull(matches)
|
Objects.requireNonNull(matches)
|
||||||
.add(
|
.add(
|
||||||
new SearchResult(
|
new SearchResult(
|
||||||
loc.getRange(),
|
loc.getRange(),
|
||||||
file,
|
file,
|
||||||
content.getLineString(loc.getRange().getStart().getLine()),
|
content.getLineString(loc.getRange().getStart().getLine()),
|
||||||
content
|
content
|
||||||
.subContent(
|
.subContent(
|
||||||
loc.getRange().getStart().getLine(),
|
loc.getRange().getStart().getLine(),
|
||||||
loc.getRange().getStart().getColumn(),
|
loc.getRange().getStart().getColumn(),
|
||||||
loc.getRange().getEnd().getLine(),
|
loc.getRange().getEnd().getLine(),
|
||||||
loc.getRange().getEnd().getColumn())
|
loc.getRange().getEnd().getColumn())
|
||||||
.toString()));
|
.toString()));
|
||||||
results.put(file, matches);
|
results.put(file, matches);
|
||||||
} catch (Throwable th) {
|
} catch (Throwable th) {
|
||||||
LOG.error("Failed to show file location", th);
|
LOG.error("Failed to show file location", th);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
activity().handleSearchResults(results);
|
activity().handleSearchResults(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void performCodeAction(File file, CodeActionItem actionItem) {
|
public void performCodeAction(File file, CodeActionItem actionItem) {
|
||||||
final var editor = activity().getEditorForFile(file);
|
final var editor = activity().getEditorForFile(file);
|
||||||
if (editor != null) {
|
if (editor != null) {
|
||||||
performCodeAction(editor.getEditor(), actionItem);
|
performCodeAction(editor.getEditor(), actionItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform the given {@link CodeActionItem}
|
* Perform the given {@link CodeActionItem}
|
||||||
*
|
*
|
||||||
* @param editor The {@link IDEEditor} that invoked the code action request. This is required to
|
* @param editor The {@link IDEEditor} that invoked the code action request. This is required to
|
||||||
* reduce the time finding the code action from the edits.
|
* reduce the time finding the code action from the edits.
|
||||||
* @param action The action to perform
|
* @param action The action to perform
|
||||||
*/
|
*/
|
||||||
public void performCodeAction(IDEEditor editor, CodeActionItem action) {
|
public void performCodeAction(IDEEditor editor, CodeActionItem action) {
|
||||||
if (activity() == null || editor == null || action == null) {
|
if (activity() == null || editor == null || action == null) {
|
||||||
LOG.error(
|
LOG.error(
|
||||||
"Unable to perform code action",
|
"Unable to perform code action",
|
||||||
"activity=" + activity(),
|
"activity=" + activity(),
|
||||||
"editor=" + editor,
|
"editor=" + editor,
|
||||||
"action=" + action);
|
"action=" + action);
|
||||||
StudioApp.getInstance().toast(R.string.msg_cannot_perform_fix, Toaster.Type.ERROR);
|
StudioApp.getInstance().toast(R.string.msg_cannot_perform_fix, Toaster.Type.ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ProgressSheet progress = new ProgressSheet();
|
final ProgressSheet progress = new ProgressSheet();
|
||||||
progress.setSubMessageEnabled(false);
|
progress.setSubMessageEnabled(false);
|
||||||
progress.setWelcomeTextEnabled(false);
|
progress.setWelcomeTextEnabled(false);
|
||||||
progress.setCancelable(false);
|
progress.setCancelable(false);
|
||||||
progress.setMessage(activity().getString(R.string.msg_performing_actions));
|
progress.setMessage(activity().getString(R.string.msg_performing_actions));
|
||||||
progress.show(activity().getSupportFragmentManager(), "quick_fix_progress");
|
progress.show(activity().getSupportFragmentManager(), "quick_fix_progress");
|
||||||
|
|
||||||
new TaskExecutor()
|
new TaskExecutor()
|
||||||
.executeAsyncProvideError(
|
.executeAsyncProvideError(
|
||||||
() -> performCodeActionAsync(editor, action),
|
() -> performCodeActionAsync(editor, action),
|
||||||
(result, throwable) -> {
|
(result, throwable) -> {
|
||||||
ThreadUtils.runOnUiThread(progress::dismiss);
|
ThreadUtils.runOnUiThread(progress::dismiss);
|
||||||
if (result == null || throwable != null || !result) {
|
if (result == null || throwable != null || !result) {
|
||||||
LOG.error(
|
LOG.error(
|
||||||
"Unable to perform code action", "result=" + result, "throwable=" + throwable);
|
"Unable to perform code action", "result=" + result, "throwable=" + throwable);
|
||||||
StudioApp.getInstance().toast(R.string.msg_cannot_perform_fix, Toaster.Type.ERROR);
|
StudioApp.getInstance().toast(R.string.msg_cannot_perform_fix, Toaster.Type.ERROR);
|
||||||
} else {
|
} else {
|
||||||
editor.executeCommand(action.getCommand());
|
editor.executeCommand(action.getCommand());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<DiagnosticGroup> mapAsGroup(Map<File, List<DiagnosticItem>> diags) {
|
private List<DiagnosticGroup> mapAsGroup(Map<File, List<DiagnosticItem>> diags) {
|
||||||
List<DiagnosticGroup> groups = new ArrayList<>();
|
List<DiagnosticGroup> groups = new ArrayList<>();
|
||||||
if (diags == null || diags.size() <= 0) return groups;
|
if (diags == null || diags.size() <= 0) return groups;
|
||||||
for (File file : diags.keySet()) {
|
for (File file : diags.keySet()) {
|
||||||
var fileDiags = diags.get(file);
|
var fileDiags = diags.get(file);
|
||||||
if (fileDiags == null || fileDiags.size() <= 0) continue;
|
if (fileDiags == null || fileDiags.size() <= 0) continue;
|
||||||
DiagnosticGroup group = new DiagnosticGroup(R.drawable.ic_language_java, file, fileDiags);
|
DiagnosticGroup group = new DiagnosticGroup(R.drawable.ic_language_java, file, fileDiags);
|
||||||
groups.add(group);
|
groups.add(group);
|
||||||
}
|
}
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showAvailableQuickfixes(IDEEditor editor, List<CodeActionItem> actions) {
|
private void showAvailableQuickfixes(IDEEditor editor, List<CodeActionItem> actions) {
|
||||||
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(activity());
|
final MaterialAlertDialogBuilder builder = DialogUtils.newMaterialDialogBuilder(activity());
|
||||||
builder.setTitle(R.string.msg_code_actions);
|
builder.setTitle(R.string.msg_code_actions);
|
||||||
builder.setItems(
|
builder.setItems(
|
||||||
asArray(actions),
|
asArray(actions),
|
||||||
(d, w) -> {
|
(d, w) -> {
|
||||||
d.dismiss();
|
d.dismiss();
|
||||||
hideDiagnostics();
|
hideDiagnostics();
|
||||||
hideBottomDiagnosticView(editor.getFile());
|
hideBottomDiagnosticView(editor.getFile());
|
||||||
performCodeAction(editor, actions.get(w));
|
performCodeAction(editor, actions.get(w));
|
||||||
});
|
});
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CharSequence[] asArray(List<CodeActionItem> actions) {
|
private CharSequence[] asArray(List<CodeActionItem> actions) {
|
||||||
final String[] arr = new String[actions.size()];
|
final String[] arr = new String[actions.size()];
|
||||||
for (int i = 0; i < actions.size(); i++) {
|
for (int i = 0; i < actions.size(); i++) {
|
||||||
arr[i] = actions.get(i).getTitle();
|
arr[i] = actions.get(i).getTitle();
|
||||||
}
|
}
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Boolean performCodeActionAsync(final IDEEditor editor, final CodeActionItem action) {
|
private Boolean performCodeActionAsync(final IDEEditor editor, final CodeActionItem action) {
|
||||||
LOG.debug("Performing code action:", action);
|
LOG.debug("Performing code action:", action);
|
||||||
final var changes = action.getChanges();
|
final var changes = action.getChanges();
|
||||||
if (changes.isEmpty()) {
|
if (changes.isEmpty()) {
|
||||||
return Boolean.FALSE;
|
return Boolean.FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var change : changes) {
|
for (var change : changes) {
|
||||||
final var path = change.getFile();
|
final var path = change.getFile();
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final File file = path.toFile();
|
final File file = path.toFile();
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TextEdit edit : change.getEdits()) {
|
for (TextEdit edit : change.getEdits()) {
|
||||||
final String editorFilepath =
|
final String editorFilepath =
|
||||||
editor.getFile() == null ? "" : editor.getFile().getAbsolutePath();
|
editor.getFile() == null ? "" : editor.getFile().getAbsolutePath();
|
||||||
if (file.getAbsolutePath().equals(editorFilepath)) {
|
if (file.getAbsolutePath().equals(editorFilepath)) {
|
||||||
// Edit is in the same editor which requested the code action
|
// Edit is in the same editor which requested the code action
|
||||||
editInEditor(editor, edit);
|
editInEditor(editor, edit);
|
||||||
} else {
|
} else {
|
||||||
var openedFrag = findEditorByFile(file);
|
var openedFrag = findEditorByFile(file);
|
||||||
|
|
||||||
if (openedFrag != null && openedFrag.getEditor() != null) {
|
if (openedFrag != null && openedFrag.getEditor() != null) {
|
||||||
// Edit is in another 'opened' file
|
// Edit is in another 'opened' file
|
||||||
editInEditor(openedFrag.getEditor(), edit);
|
editInEditor(openedFrag.getEditor(), edit);
|
||||||
} else {
|
} else {
|
||||||
// Edit is in some other file which is not opened
|
// Edit is in some other file which is not opened
|
||||||
// We should open that file and perform the edit
|
// We should open that file and perform the edit
|
||||||
openedFrag = activity().openFile(file);
|
openedFrag = activity().openFile(file);
|
||||||
if (openedFrag != null && openedFrag.getEditor() != null) {
|
if (openedFrag != null && openedFrag.getEditor() != null) {
|
||||||
editInEditor(openedFrag.getEditor(), edit);
|
editInEditor(openedFrag.getEditor(), edit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Boolean.TRUE;
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void execCommand(IDEEditor editor, Command command) {
|
private void execCommand(IDEEditor editor, Command command) {
|
||||||
editor.executeCommand(command);
|
editor.executeCommand(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void editInEditor(final IDEEditor editor, final TextEdit edit) {
|
private void editInEditor(final IDEEditor editor, final TextEdit edit) {
|
||||||
final Range range = edit.getRange();
|
final Range range = edit.getRange();
|
||||||
final int startLine = range.getStart().getLine();
|
final int startLine = range.getStart().getLine();
|
||||||
final int startCol = range.getStart().getColumn();
|
final int startCol = range.getStart().getColumn();
|
||||||
final int endLine = range.getEnd().getLine();
|
final int endLine = range.getEnd().getLine();
|
||||||
final int endCol = range.getEnd().getColumn();
|
final int endCol = range.getEnd().getColumn();
|
||||||
|
|
||||||
activity()
|
activity()
|
||||||
.runOnUiThread(
|
.runOnUiThread(
|
||||||
() -> {
|
() -> {
|
||||||
if (startLine == endLine && startCol == endCol) {
|
if (startLine == endLine && startCol == endCol) {
|
||||||
editor.getText().insert(startLine, startCol, edit.getNewText());
|
editor.getText().insert(startLine, startCol, edit.getNewText());
|
||||||
} else {
|
} else {
|
||||||
editor.getText().replace(startLine, startCol, endLine, endCol, edit.getNewText());
|
editor.getText().replace(startLine, startCol, endLine, endCol, edit.getNewText());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public DiagnosticsAdapter newDiagnosticsAdapter() {
|
public DiagnosticsAdapter newDiagnosticsAdapter() {
|
||||||
return new DiagnosticsAdapter(mapAsGroup(this.diagnostics), activity());
|
return new DiagnosticsAdapter(mapAsGroup(this.diagnostics), activity());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public com.itsaky.lsp.models.ShowDocumentResult showDocument(
|
public com.itsaky.lsp.models.ShowDocumentResult showDocument(
|
||||||
com.itsaky.lsp.models.ShowDocumentParams params) {
|
com.itsaky.lsp.models.ShowDocumentParams params) {
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
final var result = new com.itsaky.lsp.models.ShowDocumentResult(false);
|
final var result = new com.itsaky.lsp.models.ShowDocumentResult(false);
|
||||||
if (activity() == null) {
|
if (activity() == null) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params != null) {
|
if (params != null) {
|
||||||
File file = params.getFile().toFile();
|
File file = params.getFile().toFile();
|
||||||
if (file.exists() && file.isFile() && FileUtils.isUtf8(file)) {
|
if (file.exists() && file.isFile() && FileUtils.isUtf8(file)) {
|
||||||
final var range = params.getSelection();
|
final var range = params.getSelection();
|
||||||
var frag =
|
var frag =
|
||||||
activity().getEditorAtIndex(activity().getBinding().tabs.getSelectedTabPosition());
|
activity().getEditorAtIndex(activity().getBinding().tabs.getSelectedTabPosition());
|
||||||
if (frag != null
|
if (frag != null
|
||||||
&& frag.getFile() != null
|
&& frag.getFile() != null
|
||||||
&& frag.getEditor() != null
|
&& frag.getEditor() != null
|
||||||
&& frag.getFile().getAbsolutePath().equals(file.getAbsolutePath())) {
|
&& frag.getFile().getAbsolutePath().equals(file.getAbsolutePath())) {
|
||||||
if (LSPUtils.isEqual(range.getStart(), range.getEnd())) {
|
if (LSPUtils.isEqual(range.getStart(), range.getEnd())) {
|
||||||
frag.getEditor().setSelection(range.getStart().getLine(), range.getStart().getColumn());
|
frag.getEditor().setSelection(range.getStart().getLine(), range.getStart().getColumn());
|
||||||
} else {
|
} else {
|
||||||
frag.getEditor().setSelection(range);
|
frag.getEditor().setSelection(range);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
activity().openFileAndSelect(file, range);
|
activity().openFileAndSelect(file, range);
|
||||||
}
|
}
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.setSuccess(success);
|
result.setSuccess(success);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,335 +1,335 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.models;
|
package com.itsaky.androidide.models;
|
||||||
|
|
||||||
import static com.itsaky.androidide.utils.ILogger.newInstance;
|
import static com.itsaky.androidide.utils.ILogger.newInstance;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
import com.itsaky.androidide.utils.ILogger;
|
import com.itsaky.androidide.utils.ILogger;
|
||||||
import com.itsaky.androidide.utils.JSONUtility;
|
import com.itsaky.androidide.utils.JSONUtility;
|
||||||
import com.itsaky.androidide.utils.ListingFileRedirect;
|
import com.itsaky.androidide.utils.ListingFileRedirect;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class ApkMetadata {
|
public class ApkMetadata {
|
||||||
|
|
||||||
private static final ILogger LOG = newInstance("ApkMetadata");
|
private static final ILogger LOG = newInstance("ApkMetadata");
|
||||||
|
|
||||||
@SerializedName("version")
|
@SerializedName("version")
|
||||||
private int version;
|
private int version;
|
||||||
|
|
||||||
@SerializedName("artifactType")
|
@SerializedName("artifactType")
|
||||||
private ArtifactType artifactType;
|
private ArtifactType artifactType;
|
||||||
|
|
||||||
@SerializedName("applicationId")
|
@SerializedName("applicationId")
|
||||||
private String applicationId;
|
private String applicationId;
|
||||||
|
|
||||||
@SerializedName("variantName")
|
@SerializedName("variantName")
|
||||||
private String variantName;
|
private String variantName;
|
||||||
|
|
||||||
@SerializedName("elements")
|
@SerializedName("elements")
|
||||||
private List<Element> elements;
|
private List<Element> elements;
|
||||||
|
|
||||||
@SerializedName("elementType")
|
@SerializedName("elementType")
|
||||||
private String elementType;
|
private String elementType;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static File findApkFile(@NonNull File listingFIle) {
|
public static File findApkFile(@NonNull File listingFIle) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// This sometimes might be a redirect to the listing file
|
// This sometimes might be a redirect to the listing file
|
||||||
// So we have to handle this case too.
|
// So we have to handle this case too.
|
||||||
final var redirectedFile = ListingFileRedirect.maybeExtractRedirectedFile(listingFIle);
|
final var redirectedFile = ListingFileRedirect.maybeExtractRedirectedFile(listingFIle);
|
||||||
if (redirectedFile != null) {
|
if (redirectedFile != null) {
|
||||||
listingFIle = redirectedFile;
|
listingFIle = redirectedFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var dir = listingFIle.getParentFile();
|
final var dir = listingFIle.getParentFile();
|
||||||
final var metadata =
|
final var metadata =
|
||||||
JSONUtility.gson.fromJson(new FileReader(listingFIle), ApkMetadata.class);
|
JSONUtility.gson.fromJson(new FileReader(listingFIle), ApkMetadata.class);
|
||||||
if (!isValid(metadata)) {
|
if (!isValid(metadata)) {
|
||||||
LOG.warn("Invalid APK metadata:", metadata);
|
LOG.warn("Invalid APK metadata:", metadata);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Element element : metadata.getElements()) {
|
for (Element element : metadata.getElements()) {
|
||||||
if (element == null || element.getOutputFile() == null) {
|
if (element == null || element.getOutputFile() == null) {
|
||||||
LOG.warn("No output file specified in APK metadata element:", element);
|
LOG.warn("No output file specified in APK metadata element:", element);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.getOutputFile().endsWith(".apk")) {
|
if (element.getOutputFile().endsWith(".apk")) {
|
||||||
final File apk = new File(dir, element.getOutputFile());
|
final File apk = new File(dir, element.getOutputFile());
|
||||||
if (apk.exists() && apk.isFile()) {
|
if (apk.exists() && apk.isFile()) {
|
||||||
LOG.info("Found apk in metadata:", apk);
|
LOG.info("Found apk in metadata:", apk);
|
||||||
return apk;
|
return apk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
LOG.error("Metadata file not found...", e);
|
LOG.error("Metadata file not found...", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isValid(ApkMetadata metadata) {
|
private static boolean isValid(ApkMetadata metadata) {
|
||||||
|
|
||||||
// Null checks
|
// Null checks
|
||||||
if (metadata == null
|
if (metadata == null
|
||||||
|| metadata.getArtifactType() == null
|
|| metadata.getArtifactType() == null
|
||||||
|| metadata.getArtifactType().getType() == null
|
|| metadata.getArtifactType().getType() == null
|
||||||
|| metadata.getElements() == null) {
|
|| metadata.getElements() == null) {
|
||||||
LOG.warn("APK metadata null check failed. Metadata:", metadata);
|
LOG.warn("APK metadata null check failed. Metadata:", metadata);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ArtifactType type = metadata.getArtifactType();
|
final ArtifactType type = metadata.getArtifactType();
|
||||||
final List<Element> elements = metadata.getElements();
|
final List<Element> elements = metadata.getElements();
|
||||||
|
|
||||||
if (!type.getType().equals(ArtifactType.TYPE_APK)) {
|
if (!type.getType().equals(ArtifactType.TYPE_APK)) {
|
||||||
LOG.warn("Artifact is not of type APK. Metadata:", metadata);
|
LOG.warn("Artifact is not of type APK. Metadata:", metadata);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elements.isEmpty()) {
|
if (elements.isEmpty()) {
|
||||||
LOG.warn("No output elements found for metadata:", metadata);
|
LOG.warn("No output elements found for metadata:", metadata);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean atLeastOneApk = false;
|
boolean atLeastOneApk = false;
|
||||||
for (Element element : elements) {
|
for (Element element : elements) {
|
||||||
if (element == null
|
if (element == null
|
||||||
|| element.getOutputFile() == null
|
|| element.getOutputFile() == null
|
||||||
|| !element.getOutputFile().endsWith(".apk")) {
|
|| !element.getOutputFile().endsWith(".apk")) {
|
||||||
LOG.warn("Skipping output element because file is not APK:", element);
|
LOG.warn("Skipping output element because file is not APK:", element);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.getOutputFile().endsWith(".apk")) {
|
if (element.getOutputFile().endsWith(".apk")) {
|
||||||
atLeastOneApk = true;
|
atLeastOneApk = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.debug("Output metadata validation succeeded");
|
LOG.debug("Output metadata validation succeeded");
|
||||||
return atLeastOneApk;
|
return atLeastOneApk;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Element> getElements() {
|
public List<Element> getElements() {
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArtifactType getArtifactType() {
|
public ArtifactType getArtifactType() {
|
||||||
return artifactType;
|
return artifactType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setArtifactType(ArtifactType artifactType) {
|
public void setArtifactType(ArtifactType artifactType) {
|
||||||
this.artifactType = artifactType;
|
this.artifactType = artifactType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setElements(List<Element> elements) {
|
public void setElements(List<Element> elements) {
|
||||||
this.elements = elements;
|
this.elements = elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getVersion() {
|
public int getVersion() {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVersion(int version) {
|
public void setVersion(int version) {
|
||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getApplicationId() {
|
public String getApplicationId() {
|
||||||
return applicationId;
|
return applicationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setApplicationId(String applicationId) {
|
public void setApplicationId(String applicationId) {
|
||||||
this.applicationId = applicationId;
|
this.applicationId = applicationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getVariantName() {
|
public String getVariantName() {
|
||||||
return variantName;
|
return variantName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVariantName(String variantName) {
|
public void setVariantName(String variantName) {
|
||||||
this.variantName = variantName;
|
this.variantName = variantName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getElementType() {
|
public String getElementType() {
|
||||||
return elementType;
|
return elementType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setElementType(String elementType) {
|
public void setElementType(String elementType) {
|
||||||
this.elementType = elementType;
|
this.elementType = elementType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ApkMetadata{"
|
return "ApkMetadata{"
|
||||||
+ "version="
|
+ "version="
|
||||||
+ version
|
+ version
|
||||||
+ ", artifactType="
|
+ ", artifactType="
|
||||||
+ artifactType
|
+ artifactType
|
||||||
+ ", applicationId='"
|
+ ", applicationId='"
|
||||||
+ applicationId
|
+ applicationId
|
||||||
+ '\''
|
+ '\''
|
||||||
+ ", variantName='"
|
+ ", variantName='"
|
||||||
+ variantName
|
+ variantName
|
||||||
+ '\''
|
+ '\''
|
||||||
+ ", elements="
|
+ ", elements="
|
||||||
+ elements
|
+ elements
|
||||||
+ ", elementType='"
|
+ ", elementType='"
|
||||||
+ elementType
|
+ elementType
|
||||||
+ '\''
|
+ '\''
|
||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ArtifactType {
|
public static class ArtifactType {
|
||||||
|
|
||||||
public static String TYPE_APK = "APK";
|
public static String TYPE_APK = "APK";
|
||||||
|
|
||||||
@SerializedName("type")
|
@SerializedName("type")
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
@SerializedName("kind")
|
@SerializedName("kind")
|
||||||
private String kind;
|
private String kind;
|
||||||
|
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setType(String type) {
|
public void setType(String type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getKind() {
|
public String getKind() {
|
||||||
return kind;
|
return kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setKind(String kind) {
|
public void setKind(String kind) {
|
||||||
this.kind = kind;
|
this.kind = kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ArtifactType{" + "type='" + type + '\'' + ", kind='" + kind + '\'' + '}';
|
return "ArtifactType{" + "type='" + type + '\'' + ", kind='" + kind + '\'' + '}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Element {
|
public static class Element {
|
||||||
|
|
||||||
@SerializedName("type")
|
@SerializedName("type")
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
@SerializedName("filters")
|
@SerializedName("filters")
|
||||||
private List<Object> filters;
|
private List<Object> filters;
|
||||||
|
|
||||||
@SerializedName("attributes")
|
@SerializedName("attributes")
|
||||||
private List<Object> attributes;
|
private List<Object> attributes;
|
||||||
|
|
||||||
@SerializedName("versionCode")
|
@SerializedName("versionCode")
|
||||||
private int versionCode;
|
private int versionCode;
|
||||||
|
|
||||||
@SerializedName("versionName")
|
@SerializedName("versionName")
|
||||||
private String versionName;
|
private String versionName;
|
||||||
|
|
||||||
@SerializedName("outputFile")
|
@SerializedName("outputFile")
|
||||||
private String outputFile;
|
private String outputFile;
|
||||||
|
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setType(String type) {
|
public void setType(String type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Object> getFilters() {
|
public List<Object> getFilters() {
|
||||||
return filters;
|
return filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFilters(List<Object> filters) {
|
public void setFilters(List<Object> filters) {
|
||||||
this.filters = filters;
|
this.filters = filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Object> getAttributes() {
|
public List<Object> getAttributes() {
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAttributes(List<Object> attributes) {
|
public void setAttributes(List<Object> attributes) {
|
||||||
this.attributes = attributes;
|
this.attributes = attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getVersionCode() {
|
public int getVersionCode() {
|
||||||
return versionCode;
|
return versionCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVersionCode(int versionCode) {
|
public void setVersionCode(int versionCode) {
|
||||||
this.versionCode = versionCode;
|
this.versionCode = versionCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getVersionName() {
|
public String getVersionName() {
|
||||||
return versionName;
|
return versionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVersionName(String versionName) {
|
public void setVersionName(String versionName) {
|
||||||
this.versionName = versionName;
|
this.versionName = versionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOutputFile() {
|
public String getOutputFile() {
|
||||||
return outputFile;
|
return outputFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOutputFile(String outputFile) {
|
public void setOutputFile(String outputFile) {
|
||||||
this.outputFile = outputFile;
|
this.outputFile = outputFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Element{"
|
return "Element{"
|
||||||
+ "type='"
|
+ "type='"
|
||||||
+ type
|
+ type
|
||||||
+ '\''
|
+ '\''
|
||||||
+ ", filters="
|
+ ", filters="
|
||||||
+ filters
|
+ filters
|
||||||
+ ", attributes="
|
+ ", attributes="
|
||||||
+ attributes
|
+ attributes
|
||||||
+ ", versionCode="
|
+ ", versionCode="
|
||||||
+ versionCode
|
+ versionCode
|
||||||
+ ", versionName='"
|
+ ", versionName='"
|
||||||
+ versionName
|
+ versionName
|
||||||
+ '\''
|
+ '\''
|
||||||
+ ", outputFile='"
|
+ ", outputFile='"
|
||||||
+ outputFile
|
+ outputFile
|
||||||
+ '\''
|
+ '\''
|
||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,155 +1,155 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.projects
|
package com.itsaky.androidide.projects
|
||||||
|
|
||||||
import com.itsaky.androidide.tooling.api.IProject
|
import com.itsaky.androidide.tooling.api.IProject
|
||||||
import com.itsaky.androidide.tooling.api.IProject.Type
|
import com.itsaky.androidide.tooling.api.IProject.Type
|
||||||
import com.itsaky.androidide.tooling.api.messages.VariantDataRequest
|
import com.itsaky.androidide.tooling.api.messages.VariantDataRequest
|
||||||
import com.itsaky.androidide.tooling.api.messages.result.SimpleModuleData
|
import com.itsaky.androidide.tooling.api.messages.result.SimpleModuleData
|
||||||
import com.itsaky.androidide.tooling.api.messages.result.SimpleVariantData
|
import com.itsaky.androidide.tooling.api.messages.result.SimpleVariantData
|
||||||
import com.itsaky.androidide.tooling.api.model.IdeAndroidModule
|
import com.itsaky.androidide.tooling.api.model.IdeAndroidModule
|
||||||
import com.itsaky.androidide.tooling.api.model.IdeGradleProject
|
import com.itsaky.androidide.tooling.api.model.IdeGradleProject
|
||||||
import com.itsaky.androidide.tooling.api.model.IdeGradleTask
|
import com.itsaky.androidide.tooling.api.model.IdeGradleTask
|
||||||
import com.itsaky.androidide.utils.ILogger
|
import com.itsaky.androidide.utils.ILogger
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.*
|
import java.util.concurrent.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A project which lazily caches some required properties of the given project.
|
* A project which lazily caches some required properties of the given project.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
class CachingProject(val project: IProject) : IProject {
|
class CachingProject(val project: IProject) : IProject {
|
||||||
|
|
||||||
private val log = ILogger.newInstance(javaClass.simpleName)
|
private val log = ILogger.newInstance(javaClass.simpleName)
|
||||||
|
|
||||||
private val mName: String by lazy { this.project.name.get() }
|
private val mName: String by lazy { this.project.name.get() }
|
||||||
private val mDescription: String by lazy { this.project.description.get() }
|
private val mDescription: String by lazy { this.project.description.get() }
|
||||||
private val mProjectPath: String by lazy { this.project.projectPath.get() }
|
private val mProjectPath: String by lazy { this.project.projectPath.get() }
|
||||||
private val mProjectDir: File by lazy { this.project.projectDir.get() }
|
private val mProjectDir: File by lazy { this.project.projectDir.get() }
|
||||||
private val mBuildDir: File by lazy { this.project.buildDir.get() }
|
private val mBuildDir: File by lazy { this.project.buildDir.get() }
|
||||||
private val mBuildScript: File by lazy { this.project.buildScript.get() }
|
private val mBuildScript: File by lazy { this.project.buildScript.get() }
|
||||||
private val mProjectType: Type by lazy { this.project.type.get() }
|
private val mProjectType: Type by lazy { this.project.type.get() }
|
||||||
|
|
||||||
private var mFirstAppModule: IdeAndroidModule? = null
|
private var mFirstAppModule: IdeAndroidModule? = null
|
||||||
private val mCachedVariants: MutableMap<VariantDataRequest, SimpleVariantData> = mutableMapOf()
|
private val mCachedVariants: MutableMap<VariantDataRequest, SimpleVariantData> = mutableMapOf()
|
||||||
private val mModules: MutableList<SimpleModuleData> = mutableListOf()
|
private val mModules: MutableList<SimpleModuleData> = mutableListOf()
|
||||||
|
|
||||||
override fun isProjectInitialized(): CompletableFuture<Boolean> {
|
override fun isProjectInitialized(): CompletableFuture<Boolean> {
|
||||||
return CompletableFuture.completedFuture(true)
|
return CompletableFuture.completedFuture(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getName(): CompletableFuture<String> {
|
override fun getName(): CompletableFuture<String> {
|
||||||
return CompletableFuture.completedFuture(this.mName)
|
return CompletableFuture.completedFuture(this.mName)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDescription(): CompletableFuture<String> {
|
override fun getDescription(): CompletableFuture<String> {
|
||||||
return CompletableFuture.completedFuture(mDescription)
|
return CompletableFuture.completedFuture(mDescription)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getProjectPath(): CompletableFuture<String> {
|
override fun getProjectPath(): CompletableFuture<String> {
|
||||||
return CompletableFuture.completedFuture(mProjectPath)
|
return CompletableFuture.completedFuture(mProjectPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getType(): CompletableFuture<Type> {
|
override fun getType(): CompletableFuture<Type> {
|
||||||
return CompletableFuture.completedFuture(mProjectType)
|
return CompletableFuture.completedFuture(mProjectType)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getProjectDir(): CompletableFuture<File> {
|
override fun getProjectDir(): CompletableFuture<File> {
|
||||||
return CompletableFuture.completedFuture(mProjectDir)
|
return CompletableFuture.completedFuture(mProjectDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getBuildDir(): CompletableFuture<File> {
|
override fun getBuildDir(): CompletableFuture<File> {
|
||||||
return CompletableFuture.completedFuture(mBuildDir)
|
return CompletableFuture.completedFuture(mBuildDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getBuildScript(): CompletableFuture<File> {
|
override fun getBuildScript(): CompletableFuture<File> {
|
||||||
return CompletableFuture.completedFuture(mBuildScript)
|
return CompletableFuture.completedFuture(mBuildScript)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTasks(): CompletableFuture<MutableList<IdeGradleTask>> {
|
override fun getTasks(): CompletableFuture<MutableList<IdeGradleTask>> {
|
||||||
return this.project.tasks
|
return this.project.tasks
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getModules(): CompletableFuture<MutableList<IdeGradleProject>> {
|
override fun getModules(): CompletableFuture<MutableList<IdeGradleProject>> {
|
||||||
return this.project.modules
|
return this.project.modules
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun listModules(): CompletableFuture<MutableList<SimpleModuleData>> {
|
override fun listModules(): CompletableFuture<MutableList<SimpleModuleData>> {
|
||||||
return if (this.mModules.isNotEmpty()) {
|
return if (this.mModules.isNotEmpty()) {
|
||||||
log.debug("Using cached module data...")
|
log.debug("Using cached module data...")
|
||||||
CompletableFuture.completedFuture(mModules)
|
CompletableFuture.completedFuture(mModules)
|
||||||
} else {
|
} else {
|
||||||
return this.project.listModules().whenComplete { modules, err ->
|
return this.project.listModules().whenComplete { modules, err ->
|
||||||
if (err != null || modules == null) {
|
if (err != null || modules == null) {
|
||||||
log.debug("Unable to fetch module data from tooling server", err)
|
log.debug("Unable to fetch module data from tooling server", err)
|
||||||
return@whenComplete
|
return@whenComplete
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modules.isEmpty()) {
|
if (modules.isEmpty()) {
|
||||||
log.debug("Empty module data returned by tooling server. Ignoring...")
|
log.debug("Empty module data returned by tooling server. Ignoring...")
|
||||||
return@whenComplete
|
return@whenComplete
|
||||||
}
|
}
|
||||||
|
|
||||||
mModules.clear()
|
mModules.clear()
|
||||||
mModules.addAll(modules)
|
mModules.addAll(modules)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getVariantData(request: VariantDataRequest): CompletableFuture<SimpleVariantData> {
|
override fun getVariantData(request: VariantDataRequest): CompletableFuture<SimpleVariantData> {
|
||||||
val cached = mCachedVariants[request]
|
val cached = mCachedVariants[request]
|
||||||
if (cached != null) {
|
if (cached != null) {
|
||||||
return CompletableFuture.completedFuture(cached)
|
return CompletableFuture.completedFuture(cached)
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.project.getVariantData(request).whenComplete { t, u ->
|
return this.project.getVariantData(request).whenComplete { t, u ->
|
||||||
if (t == null) {
|
if (t == null) {
|
||||||
log.warn(
|
log.warn(
|
||||||
"Unable to get variant data for " +
|
"Unable to get variant data for " +
|
||||||
"variant ${request.variantName} ('${request.projectPath}') from tooling server",
|
"variant ${request.variantName} ('${request.projectPath}') from tooling server",
|
||||||
u)
|
u)
|
||||||
return@whenComplete
|
return@whenComplete
|
||||||
}
|
}
|
||||||
|
|
||||||
mCachedVariants[request] = t
|
mCachedVariants[request] = t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun findByPath(path: String): CompletableFuture<IdeGradleProject> {
|
override fun findByPath(path: String): CompletableFuture<IdeGradleProject> {
|
||||||
return this.project.findByPath(path)
|
return this.project.findByPath(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun findAndroidModules(): CompletableFuture<MutableList<IdeAndroidModule>> {
|
override fun findAndroidModules(): CompletableFuture<MutableList<IdeAndroidModule>> {
|
||||||
return this.project.findAndroidModules()
|
return this.project.findAndroidModules()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun findFirstAndroidModule(): CompletableFuture<IdeAndroidModule> {
|
override fun findFirstAndroidModule(): CompletableFuture<IdeAndroidModule> {
|
||||||
return this.project.findFirstAndroidModule()
|
return this.project.findFirstAndroidModule()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun findFirstAndroidAppModule(): CompletableFuture<IdeAndroidModule> {
|
override fun findFirstAndroidAppModule(): CompletableFuture<IdeAndroidModule> {
|
||||||
if (mFirstAppModule != null) {
|
if (mFirstAppModule != null) {
|
||||||
return CompletableFuture.completedFuture(mFirstAppModule)
|
return CompletableFuture.completedFuture(mFirstAppModule)
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.project.findFirstAndroidAppModule().whenComplete { module, _ ->
|
return this.project.findFirstAndroidAppModule().whenComplete { module, _ ->
|
||||||
this.mFirstAppModule = module
|
this.mFirstAppModule = module
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,207 +1,207 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.projects
|
package com.itsaky.androidide.projects
|
||||||
|
|
||||||
import com.itsaky.androidide.app.StudioApp
|
import com.itsaky.androidide.app.StudioApp
|
||||||
import com.itsaky.androidide.services.BuildService
|
import com.itsaky.androidide.services.BuildService
|
||||||
import com.itsaky.androidide.tooling.api.IProject
|
import com.itsaky.androidide.tooling.api.IProject
|
||||||
import com.itsaky.androidide.tooling.api.model.IdeAndroidModule
|
import com.itsaky.androidide.tooling.api.model.IdeAndroidModule
|
||||||
import com.itsaky.androidide.tooling.api.model.IdeGradleProject
|
import com.itsaky.androidide.tooling.api.model.IdeGradleProject
|
||||||
import com.itsaky.androidide.tooling.api.model.IdeJavaModule
|
import com.itsaky.androidide.tooling.api.model.IdeJavaModule
|
||||||
import com.itsaky.androidide.tooling.api.model.IdeModule
|
import com.itsaky.androidide.tooling.api.model.IdeModule
|
||||||
import com.itsaky.androidide.tooling.api.util.ProjectDataCollector
|
import com.itsaky.androidide.tooling.api.util.ProjectDataCollector
|
||||||
import com.itsaky.androidide.utils.ILogger
|
import com.itsaky.androidide.utils.ILogger
|
||||||
import com.itsaky.lsp.java.models.JavaServerConfiguration
|
import com.itsaky.lsp.java.models.JavaServerConfiguration
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.util.concurrent.*
|
import java.util.concurrent.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages projects in AndroidIDE.
|
* Manages projects in AndroidIDE.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
object ProjectManager {
|
object ProjectManager {
|
||||||
private val log = ILogger.newInstance(javaClass.simpleName)
|
private val log = ILogger.newInstance(javaClass.simpleName)
|
||||||
|
|
||||||
var rootProject: IProject? = null
|
var rootProject: IProject? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
field = if (value == null) null else CachingProject(value)
|
field = if (value == null) null else CachingProject(value)
|
||||||
|
|
||||||
// Cache the module data in advance for future use
|
// Cache the module data in advance for future use
|
||||||
if (field != null) {
|
if (field != null) {
|
||||||
field!!.listModules()
|
field!!.listModules()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var projectPath: String? = null
|
var projectPath: String? = null
|
||||||
|
|
||||||
fun isInitialized() = this.rootProject != null && this.rootProject!!.isProjectInitialized.get()
|
fun isInitialized() = this.rootProject != null && this.rootProject!!.isProjectInitialized.get()
|
||||||
|
|
||||||
fun checkInit(): Boolean {
|
fun checkInit(): Boolean {
|
||||||
if (isInitialized()) {
|
if (isInitialized()) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
log.warn("Project is not initialized yet!")
|
log.warn("Project is not initialized yet!")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getProjectDir(): File? = if (!checkInit()) null else File(getProjectDirPath()!!)
|
fun getProjectDir(): File? = if (!checkInit()) null else File(getProjectDirPath()!!)
|
||||||
|
|
||||||
fun getProjectDirPath(): String? {
|
fun getProjectDirPath(): String? {
|
||||||
return projectPath
|
return projectPath
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateSources(builder: BuildService?) {
|
fun generateSources(builder: BuildService?) {
|
||||||
if (builder == null) {
|
if (builder == null) {
|
||||||
log.warn("Cannot generate sources. BuildService is null.")
|
log.warn("Cannot generate sources. BuildService is null.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
getApplicationModule().whenCompleteAsync { app, _ ->
|
getApplicationModule().whenCompleteAsync { app, _ ->
|
||||||
if (app == null) {
|
if (app == null) {
|
||||||
log.warn(
|
log.warn(
|
||||||
"Cannot run resource and source generation task. No application module found.")
|
"Cannot run resource and source generation task. No application module found.")
|
||||||
return@whenCompleteAsync
|
return@whenCompleteAsync
|
||||||
}
|
}
|
||||||
|
|
||||||
val debug = app.simpleVariants.firstOrNull { it.name == "debug" }
|
val debug = app.simpleVariants.firstOrNull { it.name == "debug" }
|
||||||
if (debug == null) {
|
if (debug == null) {
|
||||||
log.warn("No debug variant found in application project ${app.name}")
|
log.warn("No debug variant found in application project ${app.name}")
|
||||||
return@whenCompleteAsync
|
return@whenCompleteAsync
|
||||||
}
|
}
|
||||||
|
|
||||||
val mainArtifact = app.simpleVariants.first { it.name == "debug" }.mainArtifact
|
val mainArtifact = app.simpleVariants.first { it.name == "debug" }.mainArtifact
|
||||||
val genResourcesTask = mainArtifact.resGenTaskName
|
val genResourcesTask = mainArtifact.resGenTaskName
|
||||||
val genSourcesTask = mainArtifact.sourceGenTaskName
|
val genSourcesTask = mainArtifact.sourceGenTaskName
|
||||||
builder
|
builder
|
||||||
.executeProjectTasks(
|
.executeProjectTasks(
|
||||||
app.projectPath,
|
app.projectPath,
|
||||||
genResourcesTask ?: "",
|
genResourcesTask ?: "",
|
||||||
genSourcesTask,
|
genSourcesTask,
|
||||||
|
|
||||||
// If view binding is enabled, generate the view binding classes too
|
// If view binding is enabled, generate the view binding classes too
|
||||||
if (app.viewBindingOptions != null && app.viewBindingOptions!!.isEnabled)
|
if (app.viewBindingOptions != null && app.viewBindingOptions!!.isEnabled)
|
||||||
"dataBindingGenBaseClassesDebug"
|
"dataBindingGenBaseClassesDebug"
|
||||||
else "")
|
else "")
|
||||||
.whenComplete { result, taskErr ->
|
.whenComplete { result, taskErr ->
|
||||||
if (!result.isSuccessful || taskErr != null) {
|
if (!result.isSuccessful || taskErr != null) {
|
||||||
log.warn(
|
log.warn(
|
||||||
"Execution for tasks '$genResourcesTask' and '$genSourcesTask' failed.",
|
"Execution for tasks '$genResourcesTask' and '$genSourcesTask' failed.",
|
||||||
taskErr ?: "")
|
taskErr ?: "")
|
||||||
} else {
|
} else {
|
||||||
notifyProjectUpdate()
|
notifyProjectUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getApplicationModule(): CompletableFuture<IdeAndroidModule?> {
|
fun getApplicationModule(): CompletableFuture<IdeAndroidModule?> {
|
||||||
if (rootProject == null) {
|
if (rootProject == null) {
|
||||||
log.error(
|
log.error(
|
||||||
"No root project instance is set. Is the project initialization process finished?")
|
"No root project instance is set. Is the project initialization process finished?")
|
||||||
return CompletableFuture.completedFuture(null)
|
return CompletableFuture.completedFuture(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
return rootProject!!.findFirstAndroidAppModule().whenComplete { app, err ->
|
return rootProject!!.findFirstAndroidAppModule().whenComplete { app, err ->
|
||||||
if (app == null || err != null) {
|
if (app == null || err != null) {
|
||||||
log.debug("An error occurred while fetching model for application module.")
|
log.debug("An error occurred while fetching model for application module.")
|
||||||
return@whenComplete
|
return@whenComplete
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getApplicationResDirectories(): CompletableFuture<List<File>?> {
|
fun getApplicationResDirectories(): CompletableFuture<List<File>?> {
|
||||||
return getApplicationModule().thenApplyAsync {
|
return getApplicationModule().thenApplyAsync {
|
||||||
if (it == null) null else collectResDirectories(it)
|
if (it == null) null else collectResDirectories(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun notifyProjectUpdate() {
|
fun notifyProjectUpdate() {
|
||||||
log.debug("Updating class paths in language servers...")
|
log.debug("Updating class paths in language servers...")
|
||||||
getApplicationModule().whenCompleteAsync { it, _ ->
|
getApplicationModule().whenCompleteAsync { it, _ ->
|
||||||
if (it == null) {
|
if (it == null) {
|
||||||
log.debug("Cannot find application module. Unable to update class paths to LSP.")
|
log.debug("Cannot find application module. Unable to update class paths to LSP.")
|
||||||
return@whenCompleteAsync
|
return@whenCompleteAsync
|
||||||
}
|
}
|
||||||
|
|
||||||
val server = StudioApp.getInstance().javaLanguageServer
|
val server = StudioApp.getInstance().javaLanguageServer
|
||||||
val classPaths = collectClassPaths(it)
|
val classPaths = collectClassPaths(it)
|
||||||
val sourceDirs = collectSourceDirs(it)
|
val sourceDirs = collectSourceDirs(it)
|
||||||
val configuration = JavaServerConfiguration(classPaths, sourceDirs)
|
val configuration = JavaServerConfiguration(classPaths, sourceDirs)
|
||||||
server.configurationChanged(configuration)
|
server.configurationChanged(configuration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun collectResDirectories(android: IdeAndroidModule) =
|
fun collectResDirectories(android: IdeAndroidModule) =
|
||||||
ProjectDataCollector.collectResDirectories(this.rootProject!!, android)
|
ProjectDataCollector.collectResDirectories(this.rootProject!!, android)
|
||||||
|
|
||||||
fun collectClassPaths(app: IdeAndroidModule) =
|
fun collectClassPaths(app: IdeAndroidModule) =
|
||||||
ProjectDataCollector.collectClassPaths(this.rootProject!!, app)
|
ProjectDataCollector.collectClassPaths(this.rootProject!!, app)
|
||||||
|
|
||||||
fun collectSourceDirs(app: IdeAndroidModule): Set<Path> =
|
fun collectSourceDirs(app: IdeAndroidModule): Set<Path> =
|
||||||
ProjectDataCollector.collectSourceDirs(this.rootProject!!, app)
|
ProjectDataCollector.collectSourceDirs(this.rootProject!!, app)
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun collectProjectDependencies(project: IProject, app: IdeAndroidModule) =
|
fun collectProjectDependencies(project: IProject, app: IdeAndroidModule) =
|
||||||
ProjectDataCollector.collectProjectDependencies(project, app)
|
ProjectDataCollector.collectProjectDependencies(project, app)
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun collectSourceDirs(projects: List<IdeModule>) =
|
fun collectSourceDirs(projects: List<IdeModule>) =
|
||||||
ProjectDataCollector.collectSourceDirs(projects)
|
ProjectDataCollector.collectSourceDirs(projects)
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun collectSources(java: IdeJavaModule) = ProjectDataCollector.collectSources(java)
|
fun collectSources(java: IdeJavaModule) = ProjectDataCollector.collectSources(java)
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun collectSources(android: IdeAndroidModule) = ProjectDataCollector.collectSources(android)
|
fun collectSources(android: IdeAndroidModule) = ProjectDataCollector.collectSources(android)
|
||||||
|
|
||||||
fun findModuleForFile(file: File): CompletableFuture<IdeGradleProject?> {
|
fun findModuleForFile(file: File): CompletableFuture<IdeGradleProject?> {
|
||||||
if (!checkInit()) {
|
if (!checkInit()) {
|
||||||
return CompletableFuture.completedFuture(null)
|
return CompletableFuture.completedFuture(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
val notAvailable = ":::::"
|
val notAvailable = ":::::"
|
||||||
return rootProject!!
|
return rootProject!!
|
||||||
.listModules()
|
.listModules()
|
||||||
.thenApplyAsync { modules ->
|
.thenApplyAsync { modules ->
|
||||||
val path = file.canonicalPath
|
val path = file.canonicalPath
|
||||||
|
|
||||||
var longestPath = ""
|
var longestPath = ""
|
||||||
for (module in modules) {
|
for (module in modules) {
|
||||||
val modulePath = module.projectDir.canonicalPath
|
val modulePath = module.projectDir.canonicalPath
|
||||||
if (path.startsWith(modulePath)) {
|
if (path.startsWith(modulePath)) {
|
||||||
if (longestPath.length < modulePath.length) {
|
if (longestPath.length < modulePath.length) {
|
||||||
longestPath = modulePath
|
longestPath = modulePath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (longestPath.isEmpty()) {
|
if (longestPath.isEmpty()) {
|
||||||
return@thenApplyAsync notAvailable
|
return@thenApplyAsync notAvailable
|
||||||
}
|
}
|
||||||
|
|
||||||
return@thenApplyAsync longestPath
|
return@thenApplyAsync longestPath
|
||||||
}
|
}
|
||||||
.thenApplyAsync {
|
.thenApplyAsync {
|
||||||
if (it == notAvailable) {
|
if (it == notAvailable) {
|
||||||
return@thenApplyAsync null
|
return@thenApplyAsync null
|
||||||
} else return@thenApplyAsync rootProject!!.findByPath(it).get()
|
} else return@thenApplyAsync rootProject!!.findByPath(it).get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,312 +1,312 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.projects;
|
package com.itsaky.androidide.projects;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.itsaky.androidide.utils.ILogger;
|
import com.itsaky.androidide.utils.ILogger;
|
||||||
import com.itsaky.inflater.IResourceTable;
|
import com.itsaky.inflater.IResourceTable;
|
||||||
import com.itsaky.inflater.values.ValuesTableFactory;
|
import com.itsaky.inflater.values.ValuesTableFactory;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class ProjectResourceTable implements IResourceTable {
|
public class ProjectResourceTable implements IResourceTable {
|
||||||
|
|
||||||
private static final ILogger LOG = ILogger.newInstance("ProjectResourceFinder");
|
private static final ILogger LOG = ILogger.newInstance("ProjectResourceFinder");
|
||||||
private File resDir;
|
private File resDir;
|
||||||
private File color;
|
private File color;
|
||||||
private File layout;
|
private File layout;
|
||||||
private File[] drawables;
|
private File[] drawables;
|
||||||
private File[] mipmaps;
|
private File[] mipmaps;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File findDrawable(@NonNull String name) {
|
public File findDrawable(@NonNull String name) {
|
||||||
for (File drawable : drawables) {
|
for (File drawable : drawables) {
|
||||||
final File file = findFileWithName(drawable.listFiles(), name);
|
final File file = findFileWithName(drawable.listFiles(), name);
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File findLayout(@NonNull String name) {
|
public File findLayout(@NonNull String name) {
|
||||||
return findFileWithName(this.layout.listFiles(), name);
|
return findFileWithName(this.layout.listFiles(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String findString(@NonNull String name) {
|
public String findString(@NonNull String name) {
|
||||||
final var table = ValuesTableFactory.getTable(resDir);
|
final var table = ValuesTableFactory.getTable(resDir);
|
||||||
|
|
||||||
if (table == null) {
|
if (table == null) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var resource = table.findString(name);
|
final var resource = table.findString(name);
|
||||||
if (resource == null) {
|
if (resource == null) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var value = resource.getValue();
|
final var value = resource.getValue();
|
||||||
if (value.startsWith("@string/")) {
|
if (value.startsWith("@string/")) {
|
||||||
var ref = value.substring("@string/".length());
|
var ref = value.substring("@string/".length());
|
||||||
if (name.equals(ref)) {
|
if (name.equals(ref)) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String findBoolean(@NonNull String name) {
|
public String findBoolean(@NonNull String name) {
|
||||||
final var table = ValuesTableFactory.getTable(resDir);
|
final var table = ValuesTableFactory.getTable(resDir);
|
||||||
|
|
||||||
if (table == null) {
|
if (table == null) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var resource = table.findBoolean(name);
|
final var resource = table.findBoolean(name);
|
||||||
if (resource == null) {
|
if (resource == null) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var val = resource.getValue();
|
final var val = resource.getValue();
|
||||||
if (val.startsWith("@bool/")) {
|
if (val.startsWith("@bool/")) {
|
||||||
final var ref = val.substring("@bool/".length());
|
final var ref = val.substring("@bool/".length());
|
||||||
if (ref.equals(name)) {
|
if (ref.equals(name)) {
|
||||||
// recursive reference
|
// recursive reference
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String findInteger(@NonNull String name) {
|
public String findInteger(@NonNull String name) {
|
||||||
final var table = ValuesTableFactory.getTable(resDir);
|
final var table = ValuesTableFactory.getTable(resDir);
|
||||||
|
|
||||||
if (table == null) {
|
if (table == null) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var resource = table.findInteger(name);
|
final var resource = table.findInteger(name);
|
||||||
if (resource == null) {
|
if (resource == null) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var val = resource.getValue();
|
final var val = resource.getValue();
|
||||||
if (val.startsWith("@integer/")) {
|
if (val.startsWith("@integer/")) {
|
||||||
final var ref = val.substring("@integer/".length());
|
final var ref = val.substring("@integer/".length());
|
||||||
if (ref.equals(name)) {
|
if (ref.equals(name)) {
|
||||||
// recursive reference
|
// recursive reference
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String findColor(@NonNull String name) {
|
public String findColor(@NonNull String name) {
|
||||||
final var table = ValuesTableFactory.getTable(resDir);
|
final var table = ValuesTableFactory.getTable(resDir);
|
||||||
|
|
||||||
if (table == null) {
|
if (table == null) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var resource = table.findColor(name);
|
final var resource = table.findColor(name);
|
||||||
if (resource == null) {
|
if (resource == null) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var value = resource.getValue();
|
final var value = resource.getValue();
|
||||||
if (value.startsWith("@color/")) {
|
if (value.startsWith("@color/")) {
|
||||||
var ref = value.substring("@color/".length());
|
var ref = value.substring("@color/".length());
|
||||||
if (name.equals(ref)) {
|
if (name.equals(ref)) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] findArray(@NonNull String name) {
|
public String[] findArray(@NonNull String name) {
|
||||||
final var table = ValuesTableFactory.getTable(resDir);
|
final var table = ValuesTableFactory.getTable(resDir);
|
||||||
if (table == null) {
|
if (table == null) {
|
||||||
return new String[] {name};
|
return new String[] {name};
|
||||||
}
|
}
|
||||||
|
|
||||||
final var resource = table.findArray(name);
|
final var resource = table.findArray(name);
|
||||||
if (resource == null) {
|
if (resource == null) {
|
||||||
return new String[] {name};
|
return new String[] {name};
|
||||||
}
|
}
|
||||||
|
|
||||||
return resource.getValues();
|
return resource.getValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String findDimension(@NonNull String name) {
|
public String findDimension(@NonNull String name) {
|
||||||
final var table = ValuesTableFactory.getTable(resDir);
|
final var table = ValuesTableFactory.getTable(resDir);
|
||||||
|
|
||||||
if (table == null) {
|
if (table == null) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var resource = table.findDimension(name);
|
final var resource = table.findDimension(name);
|
||||||
if (resource == null) {
|
if (resource == null) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
final var value = resource.getValue();
|
final var value = resource.getValue();
|
||||||
if (value.startsWith("@dimen/")) {
|
if (value.startsWith("@dimen/")) {
|
||||||
var ref = value.substring("@dimen/".length());
|
var ref = value.substring("@dimen/".length());
|
||||||
if (name.equals(ref)) {
|
if (name.equals(ref)) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Collection<String> listResourceNames(@Nullable String type) {
|
public Collection<String> listResourceNames(@Nullable String type) {
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
return listAllResourceNames();
|
return listAllResourceNames();
|
||||||
} else {
|
} else {
|
||||||
final var set = new HashSet<String>();
|
final var set = new HashSet<String>();
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "drawable":
|
case "drawable":
|
||||||
for (var folder : this.drawables) {
|
for (var folder : this.drawables) {
|
||||||
listAndAddTo(set, folder, type);
|
listAndAddTo(set, folder, type);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "layout":
|
case "layout":
|
||||||
listAndAddTo(set, this.layout, type);
|
listAndAddTo(set, this.layout, type);
|
||||||
break;
|
break;
|
||||||
case "color":
|
case "color":
|
||||||
listAndAddTo(set, this.color, type);
|
listAndAddTo(set, this.color, type);
|
||||||
break;
|
break;
|
||||||
case "mipmap":
|
case "mipmap":
|
||||||
for (var folder : this.mipmaps) {
|
for (var folder : this.mipmaps) {
|
||||||
listAndAddTo(set, folder, type);
|
listAndAddTo(set, folder, type);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void listAndAddTo(HashSet<String> set, @NonNull File dir, String type) {
|
private void listAndAddTo(HashSet<String> set, @NonNull File dir, String type) {
|
||||||
final var files = dir.listFiles();
|
final var files = dir.listFiles();
|
||||||
if (files == null) {
|
if (files == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var file : files) {
|
for (var file : files) {
|
||||||
var name = file.getName();
|
var name = file.getName();
|
||||||
if (!name.contains(".")) {
|
if (!name.contains(".")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = name.substring(0, name.lastIndexOf('.'));
|
name = name.substring(0, name.lastIndexOf('.'));
|
||||||
name = String.format(Locale.ROOT, "@%s/%s", type, name);
|
name = String.format(Locale.ROOT, "@%s/%s", type, name);
|
||||||
set.add(name);
|
set.add(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Collection<String> listAllResourceNames() {
|
private Collection<String> listAllResourceNames() {
|
||||||
final var set = new HashSet<>(listResourceNames("color"));
|
final var set = new HashSet<>(listResourceNames("color"));
|
||||||
set.addAll(listResourceNames("drawable"));
|
set.addAll(listResourceNames("drawable"));
|
||||||
set.addAll(listResourceNames("mipmap"));
|
set.addAll(listResourceNames("mipmap"));
|
||||||
set.addAll(listResourceNames("layout"));
|
set.addAll(listResourceNames("layout"));
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setInflatingFile(@NonNull File file) {
|
public void setInflatingFile(@NonNull File file) {
|
||||||
if (file.getParentFile() == null) {
|
if (file.getParentFile() == null) {
|
||||||
throw new IllegalArgumentException("Invalid inflating file");
|
throw new IllegalArgumentException("Invalid inflating file");
|
||||||
}
|
}
|
||||||
|
|
||||||
setupDirectories(
|
setupDirectories(
|
||||||
file // layout file
|
file // layout file
|
||||||
.getParentFile() // layout dir
|
.getParentFile() // layout dir
|
||||||
.getParentFile()); // res dir
|
.getParentFile()); // res dir
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupDirectories(File resDir) {
|
private void setupDirectories(File resDir) {
|
||||||
|
|
||||||
if (resDir == null) {
|
if (resDir == null) {
|
||||||
LOG.error("Null resource directory passed to resource finder. Ignoring.");
|
LOG.error("Null resource directory passed to resource finder. Ignoring.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resDir = resDir;
|
this.resDir = resDir;
|
||||||
this.color = new File(resDir, "color");
|
this.color = new File(resDir, "color");
|
||||||
this.layout = new File(resDir, "layout");
|
this.layout = new File(resDir, "layout");
|
||||||
|
|
||||||
final File[] drawables = resDir.listFiles(new NameStartsWith("drawable"));
|
final File[] drawables = resDir.listFiles(new NameStartsWith("drawable"));
|
||||||
this.drawables = drawables == null ? new File[0] : drawables;
|
this.drawables = drawables == null ? new File[0] : drawables;
|
||||||
|
|
||||||
final File[] mipmaps = resDir.listFiles(new NameStartsWith("mipmap"));
|
final File[] mipmaps = resDir.listFiles(new NameStartsWith("mipmap"));
|
||||||
this.mipmaps = mipmaps == null ? new File[0] : mipmaps;
|
this.mipmaps = mipmaps == null ? new File[0] : mipmaps;
|
||||||
}
|
}
|
||||||
|
|
||||||
private File findFileWithName(File[] files, String name) {
|
private File findFileWithName(File[] files, String name) {
|
||||||
if (files == null || name == null) {
|
if (files == null || name == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
var simpleName = file.getName();
|
var simpleName = file.getName();
|
||||||
|
|
||||||
if (simpleName.startsWith(name)) {
|
if (simpleName.startsWith(name)) {
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class NameStartsWith implements FileFilter {
|
private static class NameStartsWith implements FileFilter {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
public NameStartsWith(String name) {
|
public NameStartsWith(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(@NonNull File file) {
|
public boolean accept(@NonNull File file) {
|
||||||
return file.getName().startsWith(name);
|
return file.getName().startsWith(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,71 +1,71 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.services
|
package com.itsaky.androidide.services
|
||||||
|
|
||||||
import com.itsaky.androidide.tooling.api.messages.result.BuildCancellationRequestResult
|
import com.itsaky.androidide.tooling.api.messages.result.BuildCancellationRequestResult
|
||||||
import com.itsaky.androidide.tooling.api.messages.result.InitializeResult
|
import com.itsaky.androidide.tooling.api.messages.result.InitializeResult
|
||||||
import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult
|
import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult
|
||||||
import java.util.concurrent.*
|
import java.util.concurrent.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A build service provides API to initialize project, execute builds, query a build, cancel running
|
* A build service provides API to initialize project, execute builds, query a build, cancel running
|
||||||
* builds, etc.
|
* builds, etc.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
interface BuildService {
|
interface BuildService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the project.
|
* Initialize the project.
|
||||||
*
|
*
|
||||||
* @param rootDir The root directory of the project to initialize.
|
* @param rootDir The root directory of the project to initialize.
|
||||||
* @return A [CompletableFuture] which returns an [InitializeResult] when the project
|
* @return A [CompletableFuture] which returns an [InitializeResult] when the project
|
||||||
* initialization process finishes.
|
* initialization process finishes.
|
||||||
*/
|
*/
|
||||||
fun initializeProject(rootDir: String): CompletableFuture<InitializeResult>
|
fun initializeProject(rootDir: String): CompletableFuture<InitializeResult>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the given tasks.
|
* Execute the given tasks.
|
||||||
*
|
*
|
||||||
* @param tasks The tasks to execute. If the fully qualified path of the task is not specified,
|
* @param tasks The tasks to execute. If the fully qualified path of the task is not specified,
|
||||||
* then it will be executed in the root project directory.
|
* then it will be executed in the root project directory.
|
||||||
* @return A [CompletableFuture] which returns a list of [TaskExecutionResult]. The result
|
* @return A [CompletableFuture] which returns a list of [TaskExecutionResult]. The result
|
||||||
* contains a list of tasks that were executed and the result of the whole execution.
|
* contains a list of tasks that were executed and the result of the whole execution.
|
||||||
* @see BuildService.executeProjectTasks
|
* @see BuildService.executeProjectTasks
|
||||||
*/
|
*/
|
||||||
fun executeTasks(vararg tasks: String): CompletableFuture<TaskExecutionResult>
|
fun executeTasks(vararg tasks: String): CompletableFuture<TaskExecutionResult>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the given tasks of the given project.
|
* Execute the given tasks of the given project.
|
||||||
*
|
*
|
||||||
* @param projectPath The path of the project. All the tasks will be executed in this project.
|
* @param projectPath The path of the project. All the tasks will be executed in this project.
|
||||||
* @param tasks The tasks to execute. These may or may not be fully qualified names of the
|
* @param tasks The tasks to execute. These may or may not be fully qualified names of the
|
||||||
* project. If the task name is not fully qualified, then it will be executed in the given
|
* project. If the task name is not fully qualified, then it will be executed in the given
|
||||||
* project path. For example, if the project path is ':app' and the task is 'assembleDebug',
|
* project path. For example, if the project path is ':app' and the task is 'assembleDebug',
|
||||||
* then, ':app:assembleDebug' task will be executed.
|
* then, ':app:assembleDebug' task will be executed.
|
||||||
* @return A [CompletableFuture] which returns a list of [TaskExecutionResult]. The result
|
* @return A [CompletableFuture] which returns a list of [TaskExecutionResult]. The result
|
||||||
* contains a list of tasks that were executed and the result of the whole execution.
|
* contains a list of tasks that were executed and the result of the whole execution.
|
||||||
*/
|
*/
|
||||||
fun executeProjectTasks(
|
fun executeProjectTasks(
|
||||||
projectPath: String,
|
projectPath: String,
|
||||||
vararg tasks: String
|
vararg tasks: String
|
||||||
): CompletableFuture<TaskExecutionResult>
|
): CompletableFuture<TaskExecutionResult>
|
||||||
|
|
||||||
/** Cancel any running build. */
|
/** Cancel any running build. */
|
||||||
fun cancelCurrentBuild(): CompletableFuture<BuildCancellationRequestResult>
|
fun cancelCurrentBuild(): CompletableFuture<BuildCancellationRequestResult>
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,88 +1,88 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.ui.edit;
|
package com.itsaky.androidide.ui.edit;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.itsaky.attrinfo.models.Attr;
|
import com.itsaky.attrinfo.models.Attr;
|
||||||
import com.itsaky.inflater.IAttribute;
|
import com.itsaky.inflater.IAttribute;
|
||||||
import com.itsaky.lsp.util.StringUtils;
|
import com.itsaky.lsp.util.StringUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles editing dimension attributes.
|
* Handles editing dimension attributes.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
public class DimensionSuggestionProvider extends BaseSuggestionProvider {
|
public class DimensionSuggestionProvider extends BaseSuggestionProvider {
|
||||||
|
|
||||||
/** The dimension units that will be suggested. */
|
/** The dimension units that will be suggested. */
|
||||||
private final List<String> dimensions = new ArrayList<>();
|
private final List<String> dimensions = new ArrayList<>();
|
||||||
|
|
||||||
public DimensionSuggestionProvider(File layout) {
|
public DimensionSuggestionProvider(File layout) {
|
||||||
super(layout);
|
super(layout);
|
||||||
|
|
||||||
this.dimensions.add("dp");
|
this.dimensions.add("dp");
|
||||||
this.dimensions.add("sp");
|
this.dimensions.add("sp");
|
||||||
this.dimensions.add("px");
|
this.dimensions.add("px");
|
||||||
this.dimensions.add("pt");
|
this.dimensions.add("pt");
|
||||||
this.dimensions.add("in");
|
this.dimensions.add("in");
|
||||||
this.dimensions.add("mm");
|
this.dimensions.add("mm");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkFormat(int format) {
|
public boolean checkFormat(int format) {
|
||||||
return (format & Attr.DIMENSION) != 0;
|
return (format & Attr.DIMENSION) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull List<String> suggest(IAttribute attribute, @NonNull String prefix) {
|
public @NonNull List<String> suggest(IAttribute attribute, @NonNull String prefix) {
|
||||||
final var list = new ArrayList<String>();
|
final var list = new ArrayList<String>();
|
||||||
if (prefix.length() > 0 && Character.isDigit(prefix.charAt(0))) {
|
if (prefix.length() > 0 && Character.isDigit(prefix.charAt(0))) {
|
||||||
// Fixed dimension values
|
// Fixed dimension values
|
||||||
// e.g. 10dp
|
// e.g. 10dp
|
||||||
|
|
||||||
var val = extractDimensionVal(prefix);
|
var val = extractDimensionVal(prefix);
|
||||||
for (var unit : this.dimensions) {
|
for (var unit : this.dimensions) {
|
||||||
final var dimension = val + unit;
|
final var dimension = val + unit;
|
||||||
if (StringUtils.matchesFuzzy(dimension, prefix, true)) {
|
if (StringUtils.matchesFuzzy(dimension, prefix, true)) {
|
||||||
list.add(dimension);
|
list.add(dimension);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int extractDimensionVal(@NonNull String prefix) {
|
private int extractDimensionVal(@NonNull String prefix) {
|
||||||
StringBuilder s = new StringBuilder();
|
StringBuilder s = new StringBuilder();
|
||||||
var i = 0;
|
var i = 0;
|
||||||
while (i < prefix.length()) {
|
while (i < prefix.length()) {
|
||||||
if (Character.isDigit(prefix.charAt(i))) {
|
if (Character.isDigit(prefix.charAt(i))) {
|
||||||
s.append(prefix.charAt(i));
|
s.append(prefix.charAt(i));
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Integer.parseInt(s.toString());
|
return Integer.parseInt(s.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,84 +1,84 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.utils
|
package com.itsaky.androidide.utils
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.itsaky.androidide.actions.ActionItem
|
import com.itsaky.androidide.actions.ActionItem
|
||||||
import com.itsaky.androidide.actions.ActionsRegistry
|
import com.itsaky.androidide.actions.ActionsRegistry
|
||||||
import com.itsaky.androidide.actions.build.CancelBuildAction
|
import com.itsaky.androidide.actions.build.CancelBuildAction
|
||||||
import com.itsaky.androidide.actions.build.ProjectSyncAction
|
import com.itsaky.androidide.actions.build.ProjectSyncAction
|
||||||
import com.itsaky.androidide.actions.build.QuickRunAction
|
import com.itsaky.androidide.actions.build.QuickRunAction
|
||||||
import com.itsaky.androidide.actions.build.RunActionMenu
|
import com.itsaky.androidide.actions.build.RunActionMenu
|
||||||
import com.itsaky.androidide.actions.editor.CopyAction
|
import com.itsaky.androidide.actions.editor.CopyAction
|
||||||
import com.itsaky.androidide.actions.editor.CutAction
|
import com.itsaky.androidide.actions.editor.CutAction
|
||||||
import com.itsaky.androidide.actions.editor.ExpandSelectionAction
|
import com.itsaky.androidide.actions.editor.ExpandSelectionAction
|
||||||
import com.itsaky.androidide.actions.editor.PasteAction
|
import com.itsaky.androidide.actions.editor.PasteAction
|
||||||
import com.itsaky.androidide.actions.editor.SelectAllAction
|
import com.itsaky.androidide.actions.editor.SelectAllAction
|
||||||
import com.itsaky.androidide.actions.editor.find.GoToNextAction
|
import com.itsaky.androidide.actions.editor.find.GoToNextAction
|
||||||
import com.itsaky.androidide.actions.editor.find.GoToPreviousAction
|
import com.itsaky.androidide.actions.editor.find.GoToPreviousAction
|
||||||
import com.itsaky.androidide.actions.editor.find.ReplaceAction
|
import com.itsaky.androidide.actions.editor.find.ReplaceAction
|
||||||
import com.itsaky.androidide.actions.etc.DaemonStatusAction
|
import com.itsaky.androidide.actions.etc.DaemonStatusAction
|
||||||
import com.itsaky.androidide.actions.etc.FileTreeAction
|
import com.itsaky.androidide.actions.etc.FileTreeAction
|
||||||
import com.itsaky.androidide.actions.etc.FindActionMenu
|
import com.itsaky.androidide.actions.etc.FindActionMenu
|
||||||
import com.itsaky.androidide.actions.etc.PreviewLayoutAction
|
import com.itsaky.androidide.actions.etc.PreviewLayoutAction
|
||||||
import com.itsaky.androidide.actions.file.FormatCodeAction
|
import com.itsaky.androidide.actions.file.FormatCodeAction
|
||||||
import com.itsaky.androidide.actions.file.SaveFileAction
|
import com.itsaky.androidide.actions.file.SaveFileAction
|
||||||
import com.itsaky.androidide.actions.text.RedoAction
|
import com.itsaky.androidide.actions.text.RedoAction
|
||||||
import com.itsaky.androidide.actions.text.UndoAction
|
import com.itsaky.androidide.actions.text.UndoAction
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes care of registering actions to the actions registry for the editor activity.
|
* Takes care of registering actions to the actions registry for the editor activity.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
class EditorActivityActions {
|
class EditorActivityActions {
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun register(context: Context) {
|
fun register(context: Context) {
|
||||||
val registry = ActionsRegistry.getInstance()
|
val registry = ActionsRegistry.getInstance()
|
||||||
|
|
||||||
// Toolbar actions
|
// Toolbar actions
|
||||||
registry.registerAction(UndoAction(context))
|
registry.registerAction(UndoAction(context))
|
||||||
registry.registerAction(RedoAction(context))
|
registry.registerAction(RedoAction(context))
|
||||||
registry.registerAction(QuickRunAction(context))
|
registry.registerAction(QuickRunAction(context))
|
||||||
registry.registerAction(RunActionMenu(context))
|
registry.registerAction(RunActionMenu(context))
|
||||||
registry.registerAction(SaveFileAction(context))
|
registry.registerAction(SaveFileAction(context))
|
||||||
registry.registerAction(PreviewLayoutAction(context))
|
registry.registerAction(PreviewLayoutAction(context))
|
||||||
registry.registerAction(FindActionMenu(context))
|
registry.registerAction(FindActionMenu(context))
|
||||||
registry.registerAction(FileTreeAction(context))
|
registry.registerAction(FileTreeAction(context))
|
||||||
registry.registerAction(DaemonStatusAction(context))
|
registry.registerAction(DaemonStatusAction(context))
|
||||||
registry.registerAction(CancelBuildAction(context))
|
registry.registerAction(CancelBuildAction(context))
|
||||||
registry.registerAction(ProjectSyncAction(context))
|
registry.registerAction(ProjectSyncAction(context))
|
||||||
|
|
||||||
// editor text actions
|
// editor text actions
|
||||||
registry.registerAction(ExpandSelectionAction(context))
|
registry.registerAction(ExpandSelectionAction(context))
|
||||||
registry.registerAction(SelectAllAction(context))
|
registry.registerAction(SelectAllAction(context))
|
||||||
registry.registerAction(CutAction(context))
|
registry.registerAction(CutAction(context))
|
||||||
registry.registerAction(CopyAction(context))
|
registry.registerAction(CopyAction(context))
|
||||||
registry.registerAction(PasteAction(context))
|
registry.registerAction(PasteAction(context))
|
||||||
registry.registerAction(FormatCodeAction(context))
|
registry.registerAction(FormatCodeAction(context))
|
||||||
|
|
||||||
// editor search actions
|
// editor search actions
|
||||||
registry.registerAction(GoToNextAction(context))
|
registry.registerAction(GoToNextAction(context))
|
||||||
registry.registerAction(GoToPreviousAction(context))
|
registry.registerAction(GoToPreviousAction(context))
|
||||||
registry.registerAction(ReplaceAction(context))
|
registry.registerAction(ReplaceAction(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun clear() = ActionsRegistry.getInstance().clearActions(ActionItem.Location.EDITOR_TOOLBAR)
|
fun clear() = ActionsRegistry.getInstance().clearActions(ActionItem.Location.EDITOR_TOOLBAR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.itsaky.androidide.utils;
|
package com.itsaky.androidide.utils;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.itsaky.androidide.tooling.api.util.ToolingApiLauncher;
|
import com.itsaky.androidide.tooling.api.util.ToolingApiLauncher;
|
||||||
|
|
||||||
public class JSONUtility {
|
public class JSONUtility {
|
||||||
public static final Gson gson = new Gson();
|
public static final Gson gson = new Gson();
|
||||||
public static final Gson toolingGson;
|
public static final Gson toolingGson;
|
||||||
public static final Gson prettyPrinter = new GsonBuilder().setPrettyPrinting().create();
|
public static final Gson prettyPrinter = new GsonBuilder().setPrettyPrinting().create();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final var builder = new GsonBuilder();
|
final var builder = new GsonBuilder();
|
||||||
ToolingApiLauncher.configureGson(builder);
|
ToolingApiLauncher.configureGson(builder);
|
||||||
toolingGson = builder.create();
|
toolingGson = builder.create();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +1,43 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.utils
|
package com.itsaky.androidide.utils
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.StringReader
|
import java.io.StringReader
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ListingFileRedirect {
|
class ListingFileRedirect {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/** Redirect file will have this marker as the first line as comment. */
|
/** Redirect file will have this marker as the first line as comment. */
|
||||||
private const val REDIRECT_MARKER = "#- File Locator -"
|
private const val REDIRECT_MARKER = "#- File Locator -"
|
||||||
|
|
||||||
/** Property name in a [Properties] for the metadata file location. */
|
/** Property name in a [Properties] for the metadata file location. */
|
||||||
private const val REDIRECT_PROPERTY_NAME = "listingFile"
|
private const val REDIRECT_PROPERTY_NAME = "listingFile"
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun maybeExtractRedirectedFile(redirectFile: File): File? {
|
fun maybeExtractRedirectedFile(redirectFile: File): File? {
|
||||||
val fileContent = redirectFile.readText()
|
val fileContent = redirectFile.readText()
|
||||||
return if (fileContent.startsWith(REDIRECT_MARKER)) {
|
return if (fileContent.startsWith(REDIRECT_MARKER)) {
|
||||||
val fileLocator = Properties().also { it.load(StringReader(fileContent)) }
|
val fileLocator = Properties().also { it.load(StringReader(fileContent)) }
|
||||||
val file = File(fileLocator.getProperty(REDIRECT_PROPERTY_NAME))
|
val file = File(fileLocator.getProperty(REDIRECT_PROPERTY_NAME))
|
||||||
if (!file.isAbsolute) redirectFile.parentFile!!.resolve(file) else file
|
if (!file.isAbsolute) redirectFile.parentFile!!.resolve(file) else file
|
||||||
} else null
|
} else null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,3 @@
|
|||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
@@ -473,4 +456,4 @@ public class CodeEditorView extends FrameLayout {
|
|||||||
isModified = false;
|
isModified = false;
|
||||||
notifySaved();
|
notifySaved();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,391 +1,391 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.views.editor
|
package com.itsaky.androidide.views.editor
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.RectF
|
import android.graphics.RectF
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.graphics.drawable.GradientDrawable
|
import android.graphics.drawable.GradientDrawable
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.BaseAdapter
|
import android.widget.BaseAdapter
|
||||||
import android.widget.ListView
|
import android.widget.ListView
|
||||||
import androidx.appcompat.view.menu.MenuBuilder
|
import androidx.appcompat.view.menu.MenuBuilder
|
||||||
import androidx.appcompat.view.menu.MenuItemImpl
|
import androidx.appcompat.view.menu.MenuItemImpl
|
||||||
import androidx.appcompat.view.menu.SubMenuBuilder
|
import androidx.appcompat.view.menu.SubMenuBuilder
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.transition.ChangeBounds
|
import androidx.transition.ChangeBounds
|
||||||
import androidx.transition.TransitionManager
|
import androidx.transition.TransitionManager
|
||||||
import com.blankj.utilcode.util.SizeUtils
|
import com.blankj.utilcode.util.SizeUtils
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.textview.MaterialTextView
|
import com.google.android.material.textview.MaterialTextView
|
||||||
import com.itsaky.androidide.R
|
import com.itsaky.androidide.R
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.ActionItem
|
import com.itsaky.androidide.actions.ActionItem
|
||||||
import com.itsaky.androidide.actions.ActionsRegistry
|
import com.itsaky.androidide.actions.ActionsRegistry
|
||||||
import com.itsaky.androidide.actions.ActionsRegistry.Companion.getInstance
|
import com.itsaky.androidide.actions.ActionsRegistry.Companion.getInstance
|
||||||
import com.itsaky.androidide.actions.editor.SelectAllAction
|
import com.itsaky.androidide.actions.editor.SelectAllAction
|
||||||
import com.itsaky.androidide.app.StudioApp
|
import com.itsaky.androidide.app.StudioApp
|
||||||
import com.itsaky.androidide.language.IDELanguage
|
import com.itsaky.androidide.language.IDELanguage
|
||||||
import com.itsaky.androidide.utils.ILogger
|
import com.itsaky.androidide.utils.ILogger
|
||||||
import com.itsaky.lsp.java.JavaLanguageServer
|
import com.itsaky.lsp.java.JavaLanguageServer
|
||||||
import com.itsaky.lsp.models.DiagnosticItem
|
import com.itsaky.lsp.models.DiagnosticItem
|
||||||
import com.itsaky.lsp.models.Range
|
import com.itsaky.lsp.models.Range
|
||||||
import com.itsaky.lsp.util.DiagnosticUtil
|
import com.itsaky.lsp.util.DiagnosticUtil
|
||||||
import com.itsaky.lsp.xml.XMLLanguageServer
|
import com.itsaky.lsp.xml.XMLLanguageServer
|
||||||
import io.github.rosemoe.sora.event.HandleStateChangeEvent
|
import io.github.rosemoe.sora.event.HandleStateChangeEvent
|
||||||
import io.github.rosemoe.sora.event.ScrollEvent
|
import io.github.rosemoe.sora.event.ScrollEvent
|
||||||
import io.github.rosemoe.sora.event.SelectionChangeEvent
|
import io.github.rosemoe.sora.event.SelectionChangeEvent
|
||||||
import io.github.rosemoe.sora.event.SubscriptionReceipt
|
import io.github.rosemoe.sora.event.SubscriptionReceipt
|
||||||
import io.github.rosemoe.sora.widget.CodeEditor
|
import io.github.rosemoe.sora.widget.CodeEditor
|
||||||
import io.github.rosemoe.sora.widget.EditorTouchEventHandler
|
import io.github.rosemoe.sora.widget.EditorTouchEventHandler
|
||||||
import io.github.rosemoe.sora.widget.base.EditorPopupWindow
|
import io.github.rosemoe.sora.widget.base.EditorPopupWindow
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PopupMenu for showing editor's text and code actions.
|
* PopupMenu for showing editor's text and code actions.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
@SuppressLint("RestrictedApi")
|
@SuppressLint("RestrictedApi")
|
||||||
open class EditorActionsMenu(val editor: IDEEditor) :
|
open class EditorActionsMenu(val editor: IDEEditor) :
|
||||||
EditorPopupWindow(editor, FEATURE_SHOW_OUTSIDE_VIEW_ALLOWED),
|
EditorPopupWindow(editor, FEATURE_SHOW_OUTSIDE_VIEW_ALLOWED),
|
||||||
ActionsRegistry.ActionExecListener,
|
ActionsRegistry.ActionExecListener,
|
||||||
MenuBuilder.Callback {
|
MenuBuilder.Callback {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val DELAY: Long = 200
|
const val DELAY: Long = 200
|
||||||
}
|
}
|
||||||
|
|
||||||
private val touchHandler: EditorTouchEventHandler = editor.eventHandler
|
private val touchHandler: EditorTouchEventHandler = editor.eventHandler
|
||||||
private val receipts: MutableList<SubscriptionReceipt<*>> = mutableListOf()
|
private val receipts: MutableList<SubscriptionReceipt<*>> = mutableListOf()
|
||||||
private val log = ILogger.newInstance(javaClass.simpleName)
|
private val log = ILogger.newInstance(javaClass.simpleName)
|
||||||
private val list: ListView = ListView(editor.context)
|
private val list: ListView = ListView(editor.context)
|
||||||
private var mLastScroll: Long = 0
|
private var mLastScroll: Long = 0
|
||||||
private var mLastPosition: Int = 0
|
private var mLastPosition: Int = 0
|
||||||
|
|
||||||
private val menu: MenuBuilder = MenuBuilder(editor.context)
|
private val menu: MenuBuilder = MenuBuilder(editor.context)
|
||||||
protected open var location = ActionItem.Location.EDITOR_TEXT_ACTIONS
|
protected open var location = ActionItem.Location.EDITOR_TEXT_ACTIONS
|
||||||
|
|
||||||
open fun init() {
|
open fun init() {
|
||||||
subscribe()
|
subscribe()
|
||||||
applyBackground()
|
applyBackground()
|
||||||
|
|
||||||
list.clipChildren = true
|
list.clipChildren = true
|
||||||
list.clipToOutline = true
|
list.clipToOutline = true
|
||||||
list.isVerticalFadingEdgeEnabled = true
|
list.isVerticalFadingEdgeEnabled = true
|
||||||
list.isVerticalScrollBarEnabled = true
|
list.isVerticalScrollBarEnabled = true
|
||||||
list.setFadingEdgeLength(SizeUtils.dp2px(42f))
|
list.setFadingEdgeLength(SizeUtils.dp2px(42f))
|
||||||
list.divider = null
|
list.divider = null
|
||||||
list.layoutParams =
|
list.layoutParams =
|
||||||
ViewGroup.LayoutParams(
|
ViewGroup.LayoutParams(
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||||
|
|
||||||
popup.contentView = this.list
|
popup.contentView = this.list
|
||||||
popup.animationStyle = R.style.PopupAnimation
|
popup.animationStyle = R.style.PopupAnimation
|
||||||
|
|
||||||
val menu = getMenu()
|
val menu = getMenu()
|
||||||
if (menu is MenuBuilder) {
|
if (menu is MenuBuilder) {
|
||||||
menu.setCallback(this)
|
menu.setCallback(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun subscribe() {
|
open fun subscribe() {
|
||||||
receipts.add(
|
receipts.add(
|
||||||
editor.subscribeEvent(SelectionChangeEvent::class.java) { event, _ ->
|
editor.subscribeEvent(SelectionChangeEvent::class.java) { event, _ ->
|
||||||
this.onSelectionChanged(event)
|
this.onSelectionChanged(event)
|
||||||
})
|
})
|
||||||
receipts.add(
|
receipts.add(
|
||||||
editor.subscribeEvent(ScrollEvent::class.java) { _, _ -> this.onScrollEvent() })
|
editor.subscribeEvent(ScrollEvent::class.java) { _, _ -> this.onScrollEvent() })
|
||||||
receipts.add(
|
receipts.add(
|
||||||
editor.subscribeEvent(HandleStateChangeEvent::class.java) { event, _ ->
|
editor.subscribeEvent(HandleStateChangeEvent::class.java) { event, _ ->
|
||||||
this.onHandleStateChanged(event)
|
this.onHandleStateChanged(event)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun unsubscribeEvents() {
|
open fun unsubscribeEvents() {
|
||||||
for (receipt in receipts) {
|
for (receipt in receipts) {
|
||||||
receipt.unsubscribe()
|
receipt.unsubscribe()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun onSelectionChanged(event: SelectionChangeEvent) {
|
protected open fun onSelectionChanged(event: SelectionChangeEvent) {
|
||||||
if (touchHandler.hasAnyHeldHandle()) {
|
if (touchHandler.hasAnyHeldHandle()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (event.isSelected) {
|
if (event.isSelected) {
|
||||||
if (!isShowing) {
|
if (!isShowing) {
|
||||||
editor.post(::displayWindow)
|
editor.post(::displayWindow)
|
||||||
}
|
}
|
||||||
mLastPosition = -1
|
mLastPosition = -1
|
||||||
} else {
|
} else {
|
||||||
var show = false
|
var show = false
|
||||||
if (event.cause == SelectionChangeEvent.CAUSE_TAP &&
|
if (event.cause == SelectionChangeEvent.CAUSE_TAP &&
|
||||||
event.left.index == mLastPosition &&
|
event.left.index == mLastPosition &&
|
||||||
!isShowing &&
|
!isShowing &&
|
||||||
!editor.text.isInBatchEdit) {
|
!editor.text.isInBatchEdit) {
|
||||||
editor.post(::displayWindow)
|
editor.post(::displayWindow)
|
||||||
show = true
|
show = true
|
||||||
} else {
|
} else {
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
mLastPosition =
|
mLastPosition =
|
||||||
if (event.cause == SelectionChangeEvent.CAUSE_TAP && !show) {
|
if (event.cause == SelectionChangeEvent.CAUSE_TAP && !show) {
|
||||||
event.left.index
|
event.left.index
|
||||||
} else {
|
} else {
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun onScrollEvent() {
|
protected open fun onScrollEvent() {
|
||||||
val last = mLastScroll
|
val last = mLastScroll
|
||||||
mLastScroll = System.currentTimeMillis()
|
mLastScroll = System.currentTimeMillis()
|
||||||
if (mLastScroll - last < DELAY) {
|
if (mLastScroll - last < DELAY) {
|
||||||
postDisplay()
|
postDisplay()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun onHandleStateChanged(
|
protected open fun onHandleStateChanged(
|
||||||
event: HandleStateChangeEvent,
|
event: HandleStateChangeEvent,
|
||||||
) {
|
) {
|
||||||
if (event.isHeld) {
|
if (event.isHeld) {
|
||||||
postDisplay()
|
postDisplay()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun applyBackground() {
|
protected open fun applyBackground() {
|
||||||
val drawable = GradientDrawable()
|
val drawable = GradientDrawable()
|
||||||
drawable.shape = GradientDrawable.RECTANGLE
|
drawable.shape = GradientDrawable.RECTANGLE
|
||||||
drawable.cornerRadius = 16f
|
drawable.cornerRadius = 16f
|
||||||
drawable.color =
|
drawable.color =
|
||||||
ColorStateList.valueOf(
|
ColorStateList.valueOf(
|
||||||
ContextCompat.getColor(editor.context, R.color.content_background))
|
ContextCompat.getColor(editor.context, R.color.content_background))
|
||||||
drawable.setStroke(
|
drawable.setStroke(
|
||||||
SizeUtils.dp2px(1f), ContextCompat.getColor(editor.context, R.color.primaryLightColor))
|
SizeUtils.dp2px(1f), ContextCompat.getColor(editor.context, R.color.primaryLightColor))
|
||||||
list.background = drawable
|
list.background = drawable
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun postDisplay() {
|
private fun postDisplay() {
|
||||||
if (!isShowing) {
|
if (!isShowing) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dismiss()
|
dismiss()
|
||||||
if (!editor.cursor.isSelected) {
|
if (!editor.cursor.isSelected) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
editor.postDelayed(
|
editor.postDelayed(
|
||||||
object : Runnable {
|
object : Runnable {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
if (!touchHandler.hasAnyHeldHandle() &&
|
if (!touchHandler.hasAnyHeldHandle() &&
|
||||||
System.currentTimeMillis() - mLastScroll > DELAY &&
|
System.currentTimeMillis() - mLastScroll > DELAY &&
|
||||||
touchHandler.scroller.isFinished) {
|
touchHandler.scroller.isFinished) {
|
||||||
displayWindow()
|
displayWindow()
|
||||||
} else {
|
} else {
|
||||||
editor.postDelayed(this, DELAY)
|
editor.postDelayed(this, DELAY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DELAY)
|
DELAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun selectTop(rect: RectF): Int {
|
private fun selectTop(rect: RectF): Int {
|
||||||
val rowHeight = editor.rowHeight
|
val rowHeight = editor.rowHeight
|
||||||
return if (rect.top - rowHeight * 3 / 2f > height) {
|
return if (rect.top - rowHeight * 3 / 2f > height) {
|
||||||
(rect.top - rowHeight * 3 / 2 - height).toInt()
|
(rect.top - rowHeight * 3 / 2 - height).toInt()
|
||||||
} else {
|
} else {
|
||||||
(rect.bottom + rowHeight / 2).toInt()
|
(rect.bottom + rowHeight / 2).toInt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun displayWindow() {
|
open fun displayWindow() {
|
||||||
var top: Int
|
var top: Int
|
||||||
val cursor = editor.cursor
|
val cursor = editor.cursor
|
||||||
top =
|
top =
|
||||||
if (cursor.isSelected) {
|
if (cursor.isSelected) {
|
||||||
val leftRect = editor.leftHandleDescriptor.position
|
val leftRect = editor.leftHandleDescriptor.position
|
||||||
val rightRect = editor.rightHandleDescriptor.position
|
val rightRect = editor.rightHandleDescriptor.position
|
||||||
val top1 = selectTop(leftRect)
|
val top1 = selectTop(leftRect)
|
||||||
val top2 = selectTop(rightRect)
|
val top2 = selectTop(rightRect)
|
||||||
min(top1, top2)
|
min(top1, top2)
|
||||||
} else {
|
} else {
|
||||||
selectTop(editor.insertHandleDescriptor.position)
|
selectTop(editor.insertHandleDescriptor.position)
|
||||||
}
|
}
|
||||||
top = max(0, min(top, editor.height - height - 5))
|
top = max(0, min(top, editor.height - height - 5))
|
||||||
val handleLeftX = editor.getOffset(editor.cursor.leftLine, editor.cursor.leftColumn)
|
val handleLeftX = editor.getOffset(editor.cursor.leftLine, editor.cursor.leftColumn)
|
||||||
val handleRightX = editor.getOffset(editor.cursor.rightLine, editor.cursor.rightColumn)
|
val handleRightX = editor.getOffset(editor.cursor.rightLine, editor.cursor.rightColumn)
|
||||||
val panelX = ((handleLeftX + handleRightX) / 2f).toInt()
|
val panelX = ((handleLeftX + handleRightX) / 2f).toInt()
|
||||||
setLocationAbsolutely(panelX, top)
|
setLocationAbsolutely(panelX, top)
|
||||||
show()
|
show()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun fillMenu() {
|
protected open fun fillMenu() {
|
||||||
getMenu().clear()
|
getMenu().clear()
|
||||||
|
|
||||||
val data = onCreateActionData()
|
val data = onCreateActionData()
|
||||||
|
|
||||||
val registry = getInstance()
|
val registry = getInstance()
|
||||||
registry.registerActionExecListener(this)
|
registry.registerActionExecListener(this)
|
||||||
onFillMenu(registry, data)
|
onFillMenu(registry, data)
|
||||||
|
|
||||||
this.list.adapter = ActionsListAdapter(getMenu(), editor.context)
|
this.list.adapter = ActionsListAdapter(getMenu(), editor.context)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun onFillMenu(registry: ActionsRegistry, data: ActionData) {
|
protected open fun onFillMenu(registry: ActionsRegistry, data: ActionData) {
|
||||||
registry.fillMenu(data, onGetActionLocation(), getMenu())
|
registry.fillMenu(data, onGetActionLocation(), getMenu())
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun onGetActionLocation() = location
|
protected open fun onGetActionLocation() = location
|
||||||
|
|
||||||
protected open fun onCreateActionData(): ActionData {
|
protected open fun onCreateActionData(): ActionData {
|
||||||
val data = ActionData()
|
val data = ActionData()
|
||||||
data.put(Context::class.java, editor.context)
|
data.put(Context::class.java, editor.context)
|
||||||
data.put(IDEEditor::class.java, this.editor)
|
data.put(IDEEditor::class.java, this.editor)
|
||||||
data.put(
|
data.put(
|
||||||
CodeEditor::class.java,
|
CodeEditor::class.java,
|
||||||
editor) // For LSP actions, as they cannot access IDEEditor class
|
editor) // For LSP actions, as they cannot access IDEEditor class
|
||||||
data.put(File::class.java, editor.file)
|
data.put(File::class.java, editor.file)
|
||||||
data.put(DiagnosticItem::class.java, getDiagnosticAtCursor())
|
data.put(DiagnosticItem::class.java, getDiagnosticAtCursor())
|
||||||
data.put(Range::class.java, editor.cursorRange)
|
data.put(Range::class.java, editor.cursorRange)
|
||||||
data.put(
|
data.put(
|
||||||
JavaLanguageServer::class.java,
|
JavaLanguageServer::class.java,
|
||||||
StudioApp.getInstance().javaLanguageServer as JavaLanguageServer)
|
StudioApp.getInstance().javaLanguageServer as JavaLanguageServer)
|
||||||
data.put(
|
data.put(
|
||||||
XMLLanguageServer::class.java,
|
XMLLanguageServer::class.java,
|
||||||
StudioApp.getInstance().xmlLanguageServer as XMLLanguageServer)
|
StudioApp.getInstance().xmlLanguageServer as XMLLanguageServer)
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getMenu(): Menu = menu
|
protected open fun getMenu(): Menu = menu
|
||||||
|
|
||||||
private fun getDiagnosticAtCursor(): DiagnosticItem? {
|
private fun getDiagnosticAtCursor(): DiagnosticItem? {
|
||||||
val language = editor.editorLanguage as? IDELanguage ?: return null
|
val language = editor.editorLanguage as? IDELanguage ?: return null
|
||||||
val diagnostics = language.diagnostics
|
val diagnostics = language.diagnostics
|
||||||
return DiagnosticUtil.binarySearchDiagnostic(diagnostics, editor.cursorRange.start)
|
return DiagnosticUtil.binarySearchDiagnostic(diagnostics, editor.cursorRange.start)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onExec(action: ActionItem, result: Any) {
|
override fun onExec(action: ActionItem, result: Any) {
|
||||||
if (action !is SelectAllAction) {
|
if (action !is SelectAllAction) {
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun show() {
|
override fun show() {
|
||||||
if (list.parent != null) {
|
if (list.parent != null) {
|
||||||
(list.parent as ViewGroup).removeView(list)
|
(list.parent as ViewGroup).removeView(list)
|
||||||
}
|
}
|
||||||
|
|
||||||
fillMenu()
|
fillMenu()
|
||||||
|
|
||||||
val dp8 = SizeUtils.dp2px(8f)
|
val dp8 = SizeUtils.dp2px(8f)
|
||||||
val dp16 = dp8 * 2
|
val dp16 = dp8 * 2
|
||||||
this.list.measure(
|
this.list.measure(
|
||||||
View.MeasureSpec.makeMeasureSpec(editor.width - dp16 * 2, View.MeasureSpec.AT_MOST),
|
View.MeasureSpec.makeMeasureSpec(editor.width - dp16 * 2, View.MeasureSpec.AT_MOST),
|
||||||
View.MeasureSpec.makeMeasureSpec(
|
View.MeasureSpec.makeMeasureSpec(
|
||||||
(260 * editor.dpUnit).toInt() - dp16 * 2, View.MeasureSpec.AT_MOST))
|
(260 * editor.dpUnit).toInt() - dp16 * 2, View.MeasureSpec.AT_MOST))
|
||||||
setSize(findWidestItem(), this.list.measuredHeight)
|
setSize(findWidestItem(), this.list.measuredHeight)
|
||||||
super.show()
|
super.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findWidestItem(): Int {
|
private fun findWidestItem(): Int {
|
||||||
var widest = 0
|
var widest = 0
|
||||||
val text =
|
val text =
|
||||||
LayoutInflater.from(editor.context).inflate(R.layout.layout_popup_menu_item, null) as
|
LayoutInflater.from(editor.context).inflate(R.layout.layout_popup_menu_item, null) as
|
||||||
MaterialTextView
|
MaterialTextView
|
||||||
val dp30 = SizeUtils.dp2px(30f)
|
val dp30 = SizeUtils.dp2px(30f)
|
||||||
val paddingHorizontal = text.paddingStart + text.paddingEnd
|
val paddingHorizontal = text.paddingStart + text.paddingEnd
|
||||||
val drawablePadding = text.compoundDrawablePadding
|
val drawablePadding = text.compoundDrawablePadding
|
||||||
val extraWidth = dp30 * 2 // 30dp for start and end drawables both
|
val extraWidth = dp30 * 2 // 30dp for start and end drawables both
|
||||||
|
|
||||||
for (i in 0 until getMenu().size()) {
|
for (i in 0 until getMenu().size()) {
|
||||||
val item = getMenu().getItem(i)
|
val item = getMenu().getItem(i)
|
||||||
val title = item.title.toString()
|
val title = item.title.toString()
|
||||||
var width = paddingHorizontal + (drawablePadding * 2)
|
var width = paddingHorizontal + (drawablePadding * 2)
|
||||||
width += text.paint.measureText(title).toInt()
|
width += text.paint.measureText(title).toInt()
|
||||||
width += extraWidth
|
width += extraWidth
|
||||||
|
|
||||||
if (width > widest) {
|
if (width > widest) {
|
||||||
widest = width
|
widest = width
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return widest
|
return widest
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ActionsListAdapter(val menu: Menu, val context: Context) : BaseAdapter() {
|
private class ActionsListAdapter(val menu: Menu, val context: Context) : BaseAdapter() {
|
||||||
|
|
||||||
override fun getCount(): Int = menu.size()
|
override fun getCount(): Int = menu.size()
|
||||||
|
|
||||||
override fun getItem(position: Int): MenuItem = menu.getItem(position)
|
override fun getItem(position: Int): MenuItem = menu.getItem(position)
|
||||||
|
|
||||||
override fun getItemId(position: Int): Long = position.toLong()
|
override fun getItemId(position: Int): Long = position.toLong()
|
||||||
|
|
||||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
|
||||||
val view: MaterialTextView =
|
val view: MaterialTextView =
|
||||||
if (convertView == null || convertView !is MaterialButton) {
|
if (convertView == null || convertView !is MaterialButton) {
|
||||||
(context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
|
(context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
|
||||||
.inflate(R.layout.layout_popup_menu_item, parent, false) as
|
.inflate(R.layout.layout_popup_menu_item, parent, false) as
|
||||||
MaterialTextView
|
MaterialTextView
|
||||||
} else {
|
} else {
|
||||||
convertView as MaterialTextView
|
convertView as MaterialTextView
|
||||||
}
|
}
|
||||||
|
|
||||||
val item = getItem(position)
|
val item = getItem(position)
|
||||||
view.text = item.title
|
view.text = item.title
|
||||||
|
|
||||||
val start = item.icon ?: null
|
val start = item.icon ?: null
|
||||||
var end: Drawable? = null
|
var end: Drawable? = null
|
||||||
if (item.hasSubMenu()) {
|
if (item.hasSubMenu()) {
|
||||||
end = ContextCompat.getDrawable(context, R.drawable.ic_submenu_arrow)
|
end = ContextCompat.getDrawable(context, R.drawable.ic_submenu_arrow)
|
||||||
}
|
}
|
||||||
|
|
||||||
view.setCompoundDrawablesRelativeWithIntrinsicBounds(start, null, end, null)
|
view.setCompoundDrawablesRelativeWithIntrinsicBounds(start, null, end, null)
|
||||||
view.setOnClickListener { (item as MenuItemImpl).invoke() }
|
view.setOnClickListener { (item as MenuItemImpl).invoke() }
|
||||||
|
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMenuItemSelected(menu: MenuBuilder, item: MenuItem): Boolean {
|
override fun onMenuItemSelected(menu: MenuBuilder, item: MenuItem): Boolean {
|
||||||
// Click event of MenuItems without SubMenu is consumed by the ActionsRegistry
|
// Click event of MenuItems without SubMenu is consumed by the ActionsRegistry
|
||||||
// So we only need to handle click event of SubMenus
|
// So we only need to handle click event of SubMenus
|
||||||
if (!item.hasSubMenu()) {
|
if (!item.hasSubMenu()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.hasSubMenu() && item.subMenu is SubMenuBuilder) {
|
if (item.hasSubMenu() && item.subMenu is SubMenuBuilder) {
|
||||||
(item.subMenu as SubMenuBuilder).setCallback(this)
|
(item.subMenu as SubMenuBuilder).setCallback(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.editor.post {
|
this.editor.post {
|
||||||
TransitionManager.beginDelayedTransition(this.list, ChangeBounds())
|
TransitionManager.beginDelayedTransition(this.list, ChangeBounds())
|
||||||
this.list.adapter = ActionsListAdapter(item.subMenu, editor.context)
|
this.list.adapter = ActionsListAdapter(item.subMenu, editor.context)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMenuModeChange(menu: MenuBuilder) {}
|
override fun onMenuModeChange(menu: MenuBuilder) {}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,107 +1,107 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.itsaky.androidide.views.editor
|
package com.itsaky.androidide.views.editor
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.ActionMode
|
import android.view.ActionMode
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import androidx.appcompat.view.menu.MenuBuilder
|
import androidx.appcompat.view.menu.MenuBuilder
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import com.itsaky.androidide.actions.ActionData
|
import com.itsaky.androidide.actions.ActionData
|
||||||
import com.itsaky.androidide.actions.ActionItem
|
import com.itsaky.androidide.actions.ActionItem
|
||||||
import com.itsaky.androidide.actions.ActionsRegistry
|
import com.itsaky.androidide.actions.ActionsRegistry
|
||||||
import io.github.rosemoe.sora.R
|
import io.github.rosemoe.sora.R
|
||||||
import io.github.rosemoe.sora.widget.CodeEditor
|
import io.github.rosemoe.sora.widget.CodeEditor
|
||||||
import io.github.rosemoe.sora.widget.EditorSearcher.SearchOptions
|
import io.github.rosemoe.sora.widget.EditorSearcher.SearchOptions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action mode for find and replace functions in editor.
|
* Action mode for find and replace functions in editor.
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
class SearchActionMode(val editor: IDEEditor) : ActionMode.Callback {
|
class SearchActionMode(val editor: IDEEditor) : ActionMode.Callback {
|
||||||
|
|
||||||
@SuppressLint("RestrictedApi")
|
@SuppressLint("RestrictedApi")
|
||||||
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||||
|
|
||||||
if (mode == null) {
|
if (mode == null) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (menu is MenuBuilder) {
|
if (menu is MenuBuilder) {
|
||||||
menu.setOptionalIconsVisible(true)
|
menu.setOptionalIconsVisible(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
val search = SearchView(editor.context)
|
val search = SearchView(editor.context)
|
||||||
search.setOnQueryTextListener(OnQueryListener(editor))
|
search.setOnQueryTextListener(OnQueryListener(editor))
|
||||||
search.isIconified = false
|
search.isIconified = false
|
||||||
search.queryHint = editor.context.getString(R.string.text_to_search)
|
search.queryHint = editor.context.getString(R.string.text_to_search)
|
||||||
search.performClick()
|
search.performClick()
|
||||||
search.setIconifiedByDefault(false)
|
search.setIconifiedByDefault(false)
|
||||||
mode.customView = search
|
mode.customView = search
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||||
if (mode == null || menu == null) {
|
if (mode == null || menu == null) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
menu.clear()
|
menu.clear()
|
||||||
val registry = ActionsRegistry.getInstance()
|
val registry = ActionsRegistry.getInstance()
|
||||||
registry.fillMenu(createData(mode), ActionItem.Location.EDITOR_SEARCH_ACTION_MODE, menu)
|
registry.fillMenu(createData(mode), ActionItem.Location.EDITOR_SEARCH_ACTION_MODE, menu)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
|
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||||
editor.searcher.stopSearch()
|
editor.searcher.stopSearch()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createData(mode: ActionMode): ActionData {
|
private fun createData(mode: ActionMode): ActionData {
|
||||||
return ActionData().apply {
|
return ActionData().apply {
|
||||||
put(Context::class.java, editor.context)
|
put(Context::class.java, editor.context)
|
||||||
put(IDEEditor::class.java, editor)
|
put(IDEEditor::class.java, editor)
|
||||||
put(CodeEditor::class.java, editor)
|
put(CodeEditor::class.java, editor)
|
||||||
put(ActionMode::class.java, mode)
|
put(ActionMode::class.java, mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class OnQueryListener(val editor: IDEEditor) : SearchView.OnQueryTextListener {
|
private class OnQueryListener(val editor: IDEEditor) : SearchView.OnQueryTextListener {
|
||||||
override fun onQueryTextSubmit(query: String?): Boolean {
|
override fun onQueryTextSubmit(query: String?): Boolean {
|
||||||
editor.searcher.gotoNext()
|
editor.searcher.gotoNext()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onQueryTextChange(newText: String?): Boolean {
|
override fun onQueryTextChange(newText: String?): Boolean {
|
||||||
if (TextUtils.isEmpty(newText)) {
|
if (TextUtils.isEmpty(newText)) {
|
||||||
editor.searcher.stopSearch()
|
editor.searcher.stopSearch()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.searcher.search(newText!!, SearchOptions(false, false))
|
editor.searcher.search(newText!!, SearchOptions(false, false))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,117 +1,117 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of AndroidIDE.
|
* This file is part of AndroidIDE.
|
||||||
*
|
*
|
||||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* AndroidIDE is distributed in the hope that it will be useful,
|
* AndroidIDE is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@file:Suppress("DEPRECATION")
|
@file:Suppress("DEPRECATION")
|
||||||
|
|
||||||
package io.github.rosemoe.sora.widget
|
package io.github.rosemoe.sora.widget
|
||||||
|
|
||||||
import android.app.ProgressDialog
|
import android.app.ProgressDialog
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.itsaky.androidide.R.string
|
import com.itsaky.androidide.R.string
|
||||||
import com.itsaky.androidide.utils.ILogger
|
import com.itsaky.androidide.utils.ILogger
|
||||||
import com.itsaky.androidide.views.editor.IDEEditor
|
import com.itsaky.androidide.views.editor.IDEEditor
|
||||||
import io.github.rosemoe.sora.text.TextUtils
|
import io.github.rosemoe.sora.text.TextUtils
|
||||||
import io.github.rosemoe.sora.util.IntPair
|
import io.github.rosemoe.sora.util.IntPair
|
||||||
import java.util.concurrent.*
|
import java.util.concurrent.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search text in editor. As the constructor of [EditorSearcher] is package private, we cannot
|
* Search text in editor. As the constructor of [EditorSearcher] is package private, we cannot
|
||||||
* extend it in another package. So we put this class in the same package.
|
* extend it in another package. So we put this class in the same package.
|
||||||
*
|
*
|
||||||
* @author Akash Yadav
|
* @author Akash Yadav
|
||||||
*/
|
*/
|
||||||
open class IDEEditorSearcher(editor: IDEEditor) : EditorSearcher(editor) {
|
open class IDEEditorSearcher(editor: IDEEditor) : EditorSearcher(editor) {
|
||||||
|
|
||||||
private val log = ILogger.newInstance(javaClass.simpleName)
|
private val log = ILogger.newInstance(javaClass.simpleName)
|
||||||
|
|
||||||
protected fun getEditor(): CodeEditor {
|
protected fun getEditor(): CodeEditor {
|
||||||
try {
|
try {
|
||||||
val field = EditorSearcher::class.java.getDeclaredField("mEditor")
|
val field = EditorSearcher::class.java.getDeclaredField("mEditor")
|
||||||
field.isAccessible = true
|
field.isAccessible = true
|
||||||
return field.get(this) as CodeEditor
|
return field.get(this) as CodeEditor
|
||||||
} catch (error: Throwable) {
|
} catch (error: Throwable) {
|
||||||
throw RuntimeException("Unable get instance of editor", error)
|
throw RuntimeException("Unable get instance of editor", error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun replaceAllAsync(replacement: String): CompletableFuture<Void> {
|
fun replaceAllAsync(replacement: String): CompletableFuture<Void> {
|
||||||
val dialog =
|
val dialog =
|
||||||
ProgressDialog.show(
|
ProgressDialog.show(
|
||||||
getEditor().context,
|
getEditor().context,
|
||||||
getEditor().context.getString(string.replaceAll),
|
getEditor().context.getString(string.replaceAll),
|
||||||
getEditor().context.getString(string.msg_replacing),
|
getEditor().context.getString(string.msg_replacing),
|
||||||
true,
|
true,
|
||||||
false)
|
false)
|
||||||
return CompletableFuture.runAsync { replaceAll(replacement) }.thenAccept {
|
return CompletableFuture.runAsync { replaceAll(replacement) }.thenAccept {
|
||||||
getEditor().post { dialog.dismiss() }
|
getEditor().post { dialog.dismiss() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun replaceAll(replacement: String) {
|
override fun replaceAll(replacement: String) {
|
||||||
checkState()
|
checkState()
|
||||||
if (!isResultValid) {
|
if (!isResultValid) {
|
||||||
Toast.makeText(getEditor().context, "Editor is still preparing", Toast.LENGTH_SHORT)
|
Toast.makeText(getEditor().context, "Editor is still preparing", Toast.LENGTH_SHORT)
|
||||||
.show()
|
.show()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val res = mLastResults
|
val res = mLastResults
|
||||||
try {
|
try {
|
||||||
val sb = getEditor().text.toStringBuilder()
|
val sb = getEditor().text.toStringBuilder()
|
||||||
val newLength = replacement.length
|
val newLength = replacement.length
|
||||||
if (mOptions.useRegex) {
|
if (mOptions.useRegex) {
|
||||||
var delta = 0
|
var delta = 0
|
||||||
for (i in 0 until res.size()) {
|
for (i in 0 until res.size()) {
|
||||||
val region = res[i]
|
val region = res[i]
|
||||||
val start = IntPair.getFirst(region)
|
val start = IntPair.getFirst(region)
|
||||||
val end = IntPair.getSecond(region)
|
val end = IntPair.getSecond(region)
|
||||||
val oldLength = end - start
|
val oldLength = end - start
|
||||||
sb.replace(start + delta, end + delta, replacement)
|
sb.replace(start + delta, end + delta, replacement)
|
||||||
delta += newLength - oldLength
|
delta += newLength - oldLength
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var fromIndex = 0
|
var fromIndex = 0
|
||||||
var foundIndex: Int
|
var foundIndex: Int
|
||||||
while (TextUtils.indexOf(sb, mPattern, mOptions.ignoreCase, fromIndex).also {
|
while (TextUtils.indexOf(sb, mPattern, mOptions.ignoreCase, fromIndex).also {
|
||||||
foundIndex = it
|
foundIndex = it
|
||||||
} != -1) {
|
} != -1) {
|
||||||
sb.replace(foundIndex, foundIndex + mPattern.length, replacement)
|
sb.replace(foundIndex, foundIndex + mPattern.length, replacement)
|
||||||
fromIndex = foundIndex + newLength
|
fromIndex = foundIndex + newLength
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getEditor().post {
|
getEditor().post {
|
||||||
val pos = getEditor().cursor.left()
|
val pos = getEditor().cursor.left()
|
||||||
// stopSearch();
|
// stopSearch();
|
||||||
getEditor()
|
getEditor()
|
||||||
.text
|
.text
|
||||||
.replace(
|
.replace(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
getEditor().lineCount - 1,
|
getEditor().lineCount - 1,
|
||||||
getEditor().text.getColumnCount(getEditor().lineCount - 1),
|
getEditor().text.getColumnCount(getEditor().lineCount - 1),
|
||||||
sb)
|
sb)
|
||||||
getEditor().setSelectionAround(pos.line, pos.column)
|
getEditor().setSelectionAround(pos.line, pos.column)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.error("Failed to replace", e)
|
log.error("Failed to replace", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkState() {
|
private fun checkState() {
|
||||||
check(hasQuery()) { "pattern not set" }
|
check(hasQuery()) { "pattern not set" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="@android:color/white"
|
android:fillColor="@android:color/white"
|
||||||
android:pathData="M13,7h-2v4L7,11v2h4v4h2v-4h4v-2h-4L13,7zM12,2C6.49,2 2,6.49 2,12s4.49,10 10,10h8c1.1,0 2,-0.9 2,-2v-8c0,-5.51 -4.49,-10 -10,-10zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
|
android:pathData="M13,7h-2v4L7,11v2h4v4h2v-4h4v-2h-4L13,7zM12,2C6.49,2 2,6.49 2,12s4.49,10 10,10h8c1.1,0 2,-0.9 2,-2v-8c0,-5.51 -4.49,-10 -10,-10zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<!-- drawable/form_textbox_password.xml -->
|
<!-- drawable/form_textbox_password.xml -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path android:fillColor="#fff" android:pathData="M17,7H22V17H17V19A1,1 0 0,0 18,20H20V22H17.5C16.95,22 16,21.55 16,21C16,21.55 15.05,22 14.5,22H12V20H14A1,1 0 0,0 15,19V5A1,1 0 0,0 14,4H12V2H14.5C15.05,2 16,2.45 16,3C16,2.45 16.95,2 17.5,2H20V4H18A1,1 0 0,0 17,5V7M2,7H13V9H4V15H13V17H2V7M20,15V9H17V15H20M8.5,12A1.5,1.5 0 0,0 7,10.5A1.5,1.5 0 0,0 5.5,12A1.5,1.5 0 0,0 7,13.5A1.5,1.5 0 0,0 8.5,12M13,10.89C12.39,10.33 11.44,10.38 10.88,11C10.32,11.6 10.37,12.55 11,13.11C11.55,13.63 12.43,13.63 13,13.11V10.89Z" />
|
<path android:fillColor="#fff" android:pathData="M17,7H22V17H17V19A1,1 0 0,0 18,20H20V22H17.5C16.95,22 16,21.55 16,21C16,21.55 15.05,22 14.5,22H12V20H14A1,1 0 0,0 15,19V5A1,1 0 0,0 14,4H12V2H14.5C15.05,2 16,2.45 16,3C16,2.45 16.95,2 17.5,2H20V4H18A1,1 0 0,0 17,5V7M2,7H13V9H4V15H13V17H2V7M20,15V9H17V15H20M8.5,12A1.5,1.5 0 0,0 7,10.5A1.5,1.5 0 0,0 5.5,12A1.5,1.5 0 0,0 7,13.5A1.5,1.5 0 0,0 8.5,12M13,10.89C12.39,10.33 11.44,10.38 10.88,11C10.32,11.6 10.37,12.55 11,13.11C11.55,13.63 12.43,13.63 13,13.11V10.89Z" />
|
||||||
</vector>
|
</vector>
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
<!-- drawable/eyedropper.xml -->
|
<!-- drawable/eyedropper.xml -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path android:fillColor="#fff" android:pathData="M19.35,11.72L17.22,13.85L15.81,12.43L8.1,20.14L3.5,22L2,20.5L3.86,15.9L11.57,8.19L10.15,6.78L12.28,4.65L19.35,11.72M16.76,3C17.93,1.83 19.83,1.83 21,3C22.17,4.17 22.17,6.07 21,7.24L19.08,9.16L14.84,4.92L16.76,3M5.56,17.03L4.5,19.5L6.97,18.44L14.4,11L13,9.6L5.56,17.03Z" />
|
<path android:fillColor="#fff" android:pathData="M19.35,11.72L17.22,13.85L15.81,12.43L8.1,20.14L3.5,22L2,20.5L3.86,15.9L11.57,8.19L10.15,6.78L12.28,4.65L19.35,11.72M16.76,3C17.93,1.83 19.83,1.83 21,3C22.17,4.17 22.17,6.07 21,7.24L19.08,9.16L14.84,4.92L16.76,3M5.56,17.03L4.5,19.5L6.97,18.44L14.4,11L13,9.6L5.56,17.03Z" />
|
||||||
</vector>
|
</vector>
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<!-- drawable/auto_fix.xml -->
|
<!-- drawable/auto_fix.xml -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#fff"
|
android:fillColor="#fff"
|
||||||
android:pathData="M7.5,5.6L5,7L6.4,4.5L5,2L7.5,3.4L10,2L8.6,4.5L10,7L7.5,5.6M19.5,15.4L22,14L20.6,16.5L22,19L19.5,17.6L17,19L18.4,16.5L17,14L19.5,15.4M22,2L20.6,4.5L22,7L19.5,5.6L17,7L18.4,4.5L17,2L19.5,3.4L22,2M13.34,12.78L15.78,10.34L13.66,8.22L11.22,10.66L13.34,12.78M14.37,7.29L16.71,9.63C17.1,10 17.1,10.65 16.71,11.04L5.04,22.71C4.65,23.1 4,23.1 3.63,22.71L1.29,20.37C0.9,20 0.9,19.35 1.29,18.96L12.96,7.29C13.35,6.9 14,6.9 14.37,7.29Z" />
|
android:pathData="M7.5,5.6L5,7L6.4,4.5L5,2L7.5,3.4L10,2L8.6,4.5L10,7L7.5,5.6M19.5,15.4L22,14L20.6,16.5L22,19L19.5,17.6L17,19L18.4,16.5L17,14L19.5,15.4M22,2L20.6,4.5L22,7L19.5,5.6L17,7L18.4,4.5L17,2L19.5,3.4L22,2M13.34,12.78L15.78,10.34L13.66,8.22L11.22,10.66L13.34,12.78M14.37,7.29L16.71,9.63C17.1,10 17.1,10.65 16.71,11.04L5.04,22.71C4.65,23.1 4,23.1 3.63,22.71L1.29,20.37C0.9,20 0.9,19.35 1.29,18.96L12.96,7.29C13.35,6.9 14,6.9 14.37,7.29Z" />
|
||||||
</vector>
|
</vector>
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<!-- drawable/menu_right.xml -->
|
<!-- drawable/menu_right.xml -->
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#fff"
|
android:fillColor="#fff"
|
||||||
android:pathData="M10,17L15,12L10,7V17Z" />
|
android:pathData="M10,17L15,12L10,7V17Z" />
|
||||||
</vector>
|
</vector>
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24"
|
android:viewportHeight="24"
|
||||||
android:autoMirrored="true">
|
android:autoMirrored="true">
|
||||||
<path
|
<path
|
||||||
android:fillColor="@android:color/white"
|
android:fillColor="@android:color/white"
|
||||||
android:pathData="M4,19h6v-2L4,17v2zM20,5L4,5v2h16L20,5zM17,11L4,11v2h13.25c1.1,0 2,0.9 2,2s-0.9,2 -2,2L15,17v-2l-3,3 3,3v-2h2c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4z"/>
|
android:pathData="M4,19h6v-2L4,17v2zM20,5L4,5v2h16L20,5zM17,11L4,11v2h13.25c1.1,0 2,0.9 2,2s-0.9,2 -2,2L15,17v-2l-3,3 3,3v-2h2c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4z"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|||||||
@@ -1,84 +1,84 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?><!--
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
~ This file is part of AndroidIDE.
|
~ This file is part of AndroidIDE.
|
||||||
~
|
~
|
||||||
~ AndroidIDE is free software: you can redistribute it and/or modify
|
~ AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
~ it under the terms of the GNU General Public License as published by
|
~ it under the terms of the GNU General Public License as published by
|
||||||
~ the Free Software Foundation, either version 3 of the License, or
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
~ (at your option) any later version.
|
~ (at your option) any later version.
|
||||||
~
|
~
|
||||||
~ AndroidIDE is distributed in the hope that it will be useful,
|
~ AndroidIDE is distributed in the hope that it will be useful,
|
||||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
~ GNU General Public License for more details.
|
~ GNU General Public License for more details.
|
||||||
~
|
~
|
||||||
~ You should have received a copy of the GNU General Public License
|
~ You should have received a copy of the GNU General Public License
|
||||||
~ along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
~ along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:padding="16dp">
|
tools:padding="16dp">
|
||||||
|
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
android:id="@+id/choice_group"
|
android:id="@+id/choice_group"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<RadioButton
|
<RadioButton
|
||||||
android:id="@+id/bool_true"
|
android:id="@+id/bool_true"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginBottom="4dp"
|
android:layout_marginBottom="4dp"
|
||||||
android:padding="2dp"
|
android:padding="2dp"
|
||||||
android:text="true"
|
android:text="true"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
<RadioButton
|
<RadioButton
|
||||||
android:id="@+id/bool_false"
|
android:id="@+id/bool_false"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:padding="2dp"
|
android:padding="2dp"
|
||||||
android:text="false"
|
android:text="false"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/divider1"
|
android:id="@+id/divider1"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
android:background="@color/primaryLightColor"
|
android:background="@color/primaryLightColor"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/choice_group" />
|
app:layout_constraintTop_toBottomOf="@id/choice_group" />
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/boolean_res_input"
|
android:id="@+id/boolean_res_input"
|
||||||
style="@style/AppTheme.TextInputLayout.Outlined"
|
style="@style/AppTheme.TextInputLayout.Outlined"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:hint="@string/hint_boolean_res"
|
android:hint="@string/hint_boolean_res"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/divider1">
|
app:layout_constraintTop_toBottomOf="@id/divider1">
|
||||||
|
|
||||||
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
android:digits="abcdefghijklmnopqrstwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_/@"
|
android:digits="abcdefghijklmnopqrstwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_/@"
|
||||||
android:padding="16dp" />
|
android:padding="16dp" />
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -1,29 +1,29 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?><!--
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
~ This file is part of AndroidIDE.
|
~ This file is part of AndroidIDE.
|
||||||
~
|
~
|
||||||
~ AndroidIDE is free software: you can redistribute it and/or modify
|
~ AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
~ it under the terms of the GNU General Public License as published by
|
~ it under the terms of the GNU General Public License as published by
|
||||||
~ the Free Software Foundation, either version 3 of the License, or
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
~ (at your option) any later version.
|
~ (at your option) any later version.
|
||||||
~
|
~
|
||||||
~ AndroidIDE is distributed in the hope that it will be useful,
|
~ AndroidIDE is distributed in the hope that it will be useful,
|
||||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
~ GNU General Public License for more details.
|
~ GNU General Public License for more details.
|
||||||
~
|
~
|
||||||
~ You should have received a copy of the GNU General Public License
|
~ You should have received a copy of the GNU General Public License
|
||||||
~ along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
~ along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="36dp"
|
android:layout_height="36dp"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:paddingStart="8dp"
|
android:paddingStart="8dp"
|
||||||
android:paddingTop="4dp"
|
android:paddingTop="4dp"
|
||||||
android:paddingEnd="8dp"
|
android:paddingEnd="8dp"
|
||||||
android:paddingBottom="4dp"
|
android:paddingBottom="4dp"
|
||||||
android:textSize="11sp"
|
android:textSize="11sp"
|
||||||
tools:text="Implement abstract methods">
|
tools:text="Implement abstract methods">
|
||||||
|
|
||||||
</TextView>
|
</TextView>
|
||||||
@@ -1,78 +1,78 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?><!--
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
~ This file is part of AndroidIDE.
|
~ This file is part of AndroidIDE.
|
||||||
~
|
~
|
||||||
~ AndroidIDE is free software: you can redistribute it and/or modify
|
~ AndroidIDE is free software: you can redistribute it and/or modify
|
||||||
~ it under the terms of the GNU General Public License as published by
|
~ it under the terms of the GNU General Public License as published by
|
||||||
~ the Free Software Foundation, either version 3 of the License, or
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
~ (at your option) any later version.
|
~ (at your option) any later version.
|
||||||
~
|
~
|
||||||
~ AndroidIDE is distributed in the hope that it will be useful,
|
~ AndroidIDE is distributed in the hope that it will be useful,
|
||||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
~ GNU General Public License for more details.
|
~ GNU General Public License for more details.
|
||||||
~
|
~
|
||||||
~ You should have received a copy of the GNU General Public License
|
~ You should have received a copy of the GNU General Public License
|
||||||
~ along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
~ along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:padding="16dp">
|
tools:padding="16dp">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/pick_color"
|
android:id="@+id/pick_color"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/title_color_picker"
|
android:text="@string/title_color_picker"
|
||||||
android:textColor="@color/primaryTextColor"
|
android:textColor="@color/primaryTextColor"
|
||||||
app:icon="@drawable/ic_pick_color"
|
app:icon="@drawable/ic_pick_color"
|
||||||
app:iconTint="@color/primaryIconColor"
|
app:iconTint="@color/primaryIconColor"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:rippleColor="@color/secondaryColor" />
|
app:rippleColor="@color/secondaryColor" />
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/color_preview"
|
android:id="@+id/color_preview"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/pick_color"
|
app:layout_constraintStart_toEndOf="@id/pick_color"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:strokeColor="@color/primaryDarkColor"
|
app:strokeColor="@color/primaryDarkColor"
|
||||||
app:strokeWidth="1dp" />
|
app:strokeWidth="1dp" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/divider1"
|
android:id="@+id/divider1"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
android:background="@color/primaryLightColor"
|
android:background="@color/primaryLightColor"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/pick_color" />
|
app:layout_constraintTop_toBottomOf="@id/pick_color" />
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/color_res_input"
|
android:id="@+id/color_res_input"
|
||||||
style="@style/AppTheme.TextInputLayout.Outlined"
|
style="@style/AppTheme.TextInputLayout.Outlined"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:hint="@string/hint_color_resource"
|
android:hint="@string/hint_color_resource"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/divider1">
|
app:layout_constraintTop_toBottomOf="@id/divider1">
|
||||||
|
|
||||||
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
<com.google.android.material.textfield.MaterialAutoCompleteTextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
android:digits="abcdefghijklmnopqrstwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_/@"
|
android:digits="abcdefghijklmnopqrstwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_/@"
|
||||||
android:padding="16dp" />
|
android:padding="16dp" />
|
||||||
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user