├── .gitignore
├── .idea
├── .gitignore
├── gradle.xml
├── encodings.xml
├── vcs.xml
├── description.html
├── modules.xml
├── artifacts
│ └── AndroidResourceManager_jar.xml
├── misc.xml
├── compiler.xml
└── uiDesigner.xml
├── src
├── META-INF
│ └── MANIFEST.MF
├── resources
│ ├── icon
│ │ ├── arm_logo.png
│ │ ├── icon_color_48.png
│ │ ├── preview_128.png
│ │ ├── icon_dimens_48.png
│ │ ├── icon_resize_48.png
│ │ ├── icon_search_48.png
│ │ └── icon_analysis_48.png
│ └── style
│ │ └── main_style.css
└── arm
│ ├── resize
│ ├── OnProgressListener.java
│ ├── ImageType.java
│ ├── ResizeOrder.java
│ ├── ImageSize.java
│ ├── ResizeManager.java
│ ├── resize_view.fxml
│ └── ResizeController.java
│ ├── utils
│ ├── OnCrawlerListener.java
│ ├── DeviceInfo.java
│ ├── OnSearchListener.java
│ ├── Crawler.java
│ ├── ValidationUtils.java
│ ├── AlertManager.java
│ ├── SearchPosition.java
│ ├── FileCrawler.java
│ └── FileUtils.java
│ ├── main
│ ├── ServiceName.java
│ ├── ArmApplication.java
│ ├── main_view.fxml
│ └── MainController.java
│ ├── analysis
│ ├── OnAnalysisListener.java
│ ├── Source.java
│ ├── SourceAnalysis.java
│ ├── AnalysisManager.java
│ ├── analysis_view.fxml
│ └── AnalysisController.java
│ ├── search
│ ├── KeywordPosition.java
│ ├── KeywordSearch.java
│ ├── TextSearchManager.java
│ ├── search_view.fxml
│ └── SearchController.java
│ ├── color
│ ├── ColorPosition.java
│ ├── ColorSearchManager.java
│ ├── ColorSearch.java
│ ├── color_view.fxml
│ └── ColorController.java
│ └── dimens
│ ├── DimensionPosition.java
│ ├── DimensionSearchManager.java
│ ├── DimensionSearch.java
│ ├── dimen_view.fxml
│ └── DimensionController.java
├── jar
└── AndroidResourceManager.jar
├── screenshots
├── resize_sevice.jpg
├── code_analysis_service.jpg
├── color_analysis_service.jpg
├── keyword_search_service.jpg
└── dimens_analysis_service.jpg
├── AndroidResourceManager.iml
├── .github
└── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | /out
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/src/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Main-Class: arm.main.ArmApplication
3 |
4 |
--------------------------------------------------------------------------------
/jar/AndroidResourceManager.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmrDeveloper/AndroidResourceManager/HEAD/jar/AndroidResourceManager.jar
--------------------------------------------------------------------------------
/screenshots/resize_sevice.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmrDeveloper/AndroidResourceManager/HEAD/screenshots/resize_sevice.jpg
--------------------------------------------------------------------------------
/src/resources/icon/arm_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmrDeveloper/AndroidResourceManager/HEAD/src/resources/icon/arm_logo.png
--------------------------------------------------------------------------------
/src/resources/icon/icon_color_48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmrDeveloper/AndroidResourceManager/HEAD/src/resources/icon/icon_color_48.png
--------------------------------------------------------------------------------
/src/resources/icon/preview_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmrDeveloper/AndroidResourceManager/HEAD/src/resources/icon/preview_128.png
--------------------------------------------------------------------------------
/screenshots/code_analysis_service.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmrDeveloper/AndroidResourceManager/HEAD/screenshots/code_analysis_service.jpg
--------------------------------------------------------------------------------
/screenshots/color_analysis_service.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmrDeveloper/AndroidResourceManager/HEAD/screenshots/color_analysis_service.jpg
--------------------------------------------------------------------------------
/screenshots/keyword_search_service.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmrDeveloper/AndroidResourceManager/HEAD/screenshots/keyword_search_service.jpg
--------------------------------------------------------------------------------
/src/resources/icon/icon_dimens_48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmrDeveloper/AndroidResourceManager/HEAD/src/resources/icon/icon_dimens_48.png
--------------------------------------------------------------------------------
/src/resources/icon/icon_resize_48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmrDeveloper/AndroidResourceManager/HEAD/src/resources/icon/icon_resize_48.png
--------------------------------------------------------------------------------
/src/resources/icon/icon_search_48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmrDeveloper/AndroidResourceManager/HEAD/src/resources/icon/icon_search_48.png
--------------------------------------------------------------------------------
/screenshots/dimens_analysis_service.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmrDeveloper/AndroidResourceManager/HEAD/screenshots/dimens_analysis_service.jpg
--------------------------------------------------------------------------------
/src/resources/icon/icon_analysis_48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AmrDeveloper/AndroidResourceManager/HEAD/src/resources/icon/icon_analysis_48.png
--------------------------------------------------------------------------------
/src/arm/resize/OnProgressListener.java:
--------------------------------------------------------------------------------
1 | package arm.resize;
2 |
3 | public interface OnProgressListener {
4 | void onProcessChange(float progress);
5 | }
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/arm/utils/OnCrawlerListener.java:
--------------------------------------------------------------------------------
1 | package arm.utils;
2 |
3 | import java.io.File;
4 |
5 | public interface OnCrawlerListener {
6 | void onFileFound(File file);
7 | }
8 |
--------------------------------------------------------------------------------
/src/arm/utils/DeviceInfo.java:
--------------------------------------------------------------------------------
1 | package arm.utils;
2 |
3 | public class DeviceInfo {
4 |
5 | public static final int CORE_NUM = Runtime.getRuntime().availableProcessors();
6 | }
7 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/arm/main/ServiceName.java:
--------------------------------------------------------------------------------
1 | package arm.main;
2 |
3 | public enum ServiceName {
4 | RESIZING,
5 | SEARCHING,
6 | COLOR_ANALYSIS,
7 | DIMENS_ANALYSIS,
8 | SOURCE_ANALYSIS
9 | }
10 |
--------------------------------------------------------------------------------
/.idea/description.html:
--------------------------------------------------------------------------------
1 | Simple JavaFX 2.0 application that includes simple .fxml file with attached controller and Main class to quick start. Artifact to build JavaFX application is provided.
2 |
--------------------------------------------------------------------------------
/src/arm/utils/OnSearchListener.java:
--------------------------------------------------------------------------------
1 | package arm.utils;
2 |
3 | public interface OnSearchListener {
4 | void onSearchStart();
5 | void onSearchFound(SearchPosition position);
6 | void onSearchFinish();
7 | }
8 |
--------------------------------------------------------------------------------
/src/arm/analysis/OnAnalysisListener.java:
--------------------------------------------------------------------------------
1 | package arm.analysis;
2 |
3 | public interface OnAnalysisListener {
4 | void onAnalysisStart();
5 | void onAnalysisFound(Source source);
6 | void onAnalysisFinish();
7 | }
8 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/arm/utils/Crawler.java:
--------------------------------------------------------------------------------
1 | package arm.utils;
2 |
3 | import java.io.File;
4 |
5 | public interface Crawler {
6 | void onCrawlerStart();
7 | void startFileSearching(File file, OnCrawlerListener listener);
8 | void onDirectorySearch(File directory, OnCrawlerListener listener);
9 | void onCrawlerFinished();
10 | }
--------------------------------------------------------------------------------
/src/arm/utils/ValidationUtils.java:
--------------------------------------------------------------------------------
1 | package arm.utils;
2 |
3 | import java.util.regex.Pattern;
4 |
5 | public class ValidationUtils {
6 |
7 | private final static Pattern INTEGER_PATTERN = Pattern.compile("[0-9]+");
8 |
9 | public static boolean isInteger(String value) {
10 | return INTEGER_PATTERN.matcher(value).matches();
11 | }
12 | }
--------------------------------------------------------------------------------
/.idea/artifacts/AndroidResourceManager_jar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | $PROJECT_DIR$/jar
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/arm/utils/AlertManager.java:
--------------------------------------------------------------------------------
1 | package arm.utils;
2 |
3 | import javafx.scene.control.Alert;
4 |
5 | public class AlertManager {
6 |
7 | public static void showErrorDialog(String title, String header, String content) {
8 | Alert alert = new Alert(Alert.AlertType.ERROR);
9 | alert.setTitle(title);
10 | alert.setHeaderText(header);
11 | alert.setContentText(content);
12 | alert.showAndWait();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/arm/analysis/Source.java:
--------------------------------------------------------------------------------
1 | package arm.analysis;
2 |
3 | public class Source {
4 |
5 | private final String type;
6 | private final int linesNum;
7 |
8 | public Source(String type, int linesNum) {
9 | this.type = type;
10 | this.linesNum = linesNum;
11 | }
12 |
13 | public String getType() {
14 | return type;
15 | }
16 |
17 | public int getLinesNum() {
18 | return linesNum;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/arm/resize/ImageType.java:
--------------------------------------------------------------------------------
1 | package arm.resize;
2 |
3 | public enum ImageType {
4 |
5 | DRAWABLE("Drawable"),
6 | MIPMAP("Mipmap"),
7 | OTHER("Other");
8 |
9 | private final String name;
10 |
11 | ImageType(String name) {
12 | this.name = name;
13 | }
14 |
15 | public String getName() {
16 | return name;
17 | }
18 |
19 | @Override
20 | public String toString() {
21 | return name;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/AndroidResourceManager.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/arm/search/KeywordPosition.java:
--------------------------------------------------------------------------------
1 | package arm.search;
2 |
3 | import arm.utils.SearchPosition;
4 |
5 | import java.io.File;
6 |
7 | public class KeywordPosition extends SearchPosition {
8 |
9 | public KeywordPosition(File file, int line, int start, int end) {
10 | super(file, line, start, end);
11 | }
12 |
13 | @Override
14 | public String toString() {
15 | return getFile().getPath() + " -> " + getLine() + ":" + getStart() + ":" + getEnd();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/arm/color/ColorPosition.java:
--------------------------------------------------------------------------------
1 | package arm.color;
2 |
3 | import arm.utils.SearchPosition;
4 |
5 | import java.io.File;
6 |
7 | public class ColorPosition extends SearchPosition {
8 |
9 | private final String value;
10 |
11 | public ColorPosition(File file, String value, int line, int start, int end) {
12 | super(file, line, start, end);
13 | this.value = value;
14 | }
15 |
16 | public String getValue() {
17 | return value;
18 | }
19 |
20 | @Override
21 | public String toString() {
22 | return getFile().getPath() + " " + getValue() + " -> " + getLine() + ":" + getStart() + ":" + getEnd();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/arm/analysis/SourceAnalysis.java:
--------------------------------------------------------------------------------
1 | package arm.analysis;
2 |
3 | import java.io.*;
4 |
5 | public class SourceAnalysis {
6 |
7 | public static void analysisSourceFile(File sourceFile, String extension, OnAnalysisListener listener) {
8 | try {
9 | BufferedReader reader = new BufferedReader(new FileReader(sourceFile));
10 | int lines = 0;
11 | while (reader.readLine() != null) lines++;
12 | Source source = new Source(extension, lines);
13 | listener.onAnalysisFound(source);
14 | reader.close();
15 | } catch (Exception e) {
16 | e.printStackTrace();
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/src/arm/utils/SearchPosition.java:
--------------------------------------------------------------------------------
1 | package arm.utils;
2 |
3 | import java.io.File;
4 |
5 | public abstract class SearchPosition {
6 |
7 | private final File file;
8 | private final int line;
9 | private final int start;
10 | private final int end;
11 |
12 | public SearchPosition(File file, int line, int start, int end) {
13 | this.file = file;
14 | this.line = line;
15 | this.start = start;
16 | this.end = end;
17 | }
18 |
19 | public File getFile() {
20 | return file;
21 | }
22 |
23 | public int getLine() {
24 | return line;
25 | }
26 |
27 | public int getStart() {
28 | return start;
29 | }
30 |
31 | public int getEnd() {
32 | return end;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Version [e.g. 22]
29 |
30 | **Additional context**
31 | Add any other context about the problem here.
32 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/arm/utils/FileCrawler.java:
--------------------------------------------------------------------------------
1 | package arm.utils;
2 |
3 | import java.io.File;
4 |
5 | public abstract class FileCrawler implements Crawler {
6 |
7 | @Override
8 | public void startFileSearching(File file, OnCrawlerListener listener) {
9 | onCrawlerStart();
10 | if (file.isFile()) listener.onFileFound(file);
11 | else onDirectorySearch(file, listener);
12 | onCrawlerFinished();
13 | }
14 |
15 | @Override
16 | public void onDirectorySearch(File directory, OnCrawlerListener listener) {
17 | File[] files = directory.listFiles();
18 | if (files != null) {
19 | for (File file : files) {
20 | if (file.isFile()) listener.onFileFound(file);
21 | else onDirectorySearch(file, listener);
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/arm/dimens/DimensionPosition.java:
--------------------------------------------------------------------------------
1 | package arm.dimens;
2 |
3 | import arm.utils.SearchPosition;
4 |
5 | import java.io.File;
6 |
7 | public class DimensionPosition extends SearchPosition {
8 |
9 | private final String value;
10 | private static final String DIMENSION_FORMAT = "%s";
11 |
12 | public DimensionPosition(File file, String value, int line, int start, int end) {
13 | super(file, line, start, end);
14 | this.value = value;
15 | }
16 |
17 | public String getValue() {
18 | return value;
19 | }
20 |
21 | public String getFormattedValue() {
22 | return String.format(DIMENSION_FORMAT, value, value);
23 | }
24 |
25 | @Override
26 | public String toString() {
27 | return getFile().getPath() + " " + getValue() + " -> " + getLine() + ":" + getStart() + ":" + getEnd();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/arm/main/ArmApplication.java:
--------------------------------------------------------------------------------
1 | package arm.main;
2 |
3 | import javafx.application.Application;
4 | import javafx.fxml.FXMLLoader;
5 | import javafx.scene.Parent;
6 | import javafx.scene.Scene;
7 | import javafx.scene.image.Image;
8 | import javafx.stage.Stage;
9 |
10 | public class ArmApplication extends Application {
11 |
12 | @Override
13 | public void start(Stage primaryStage) throws Exception {
14 | Parent root = FXMLLoader.load(getClass().getResource("main_view.fxml"));
15 | primaryStage.setTitle("Android Resource Manager - ARM");
16 | Scene mainScene = new Scene(root, 650, 400);
17 | mainScene.getStylesheets().add("resources/style/main_style.css");
18 | primaryStage.getIcons().add(new Image("resources/icon/arm_logo.png"));
19 | primaryStage.setScene(mainScene);
20 | primaryStage.show();
21 | }
22 |
23 | public static void main(String[] args) {
24 | launch(args);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/arm/resize/ResizeOrder.java:
--------------------------------------------------------------------------------
1 | package arm.resize;
2 |
3 | import java.io.File;
4 | import java.util.Set;
5 |
6 | public class ResizeOrder {
7 |
8 | private final Set imageList;
9 | private final Set sizeSet;
10 | private final ImageType imageType;
11 | private final File outputDirectory;
12 |
13 | public ResizeOrder(Set images,
14 | Set sizes,
15 | ImageType imageType,
16 | File outputDirectory) {
17 | this.imageList = images;
18 | this.sizeSet = sizes;
19 | this.imageType = imageType;
20 | this.outputDirectory = outputDirectory;
21 | }
22 |
23 | public Set getImageList() {
24 | return imageList;
25 | }
26 |
27 | public Set getSizeSet() {
28 | return sizeSet;
29 | }
30 |
31 | public ImageType getImageType() {
32 | return imageType;
33 | }
34 |
35 | public File getOutputDirectory() {
36 | return outputDirectory;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Amr Hesham
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/arm/search/KeywordSearch.java:
--------------------------------------------------------------------------------
1 | package arm.search;
2 |
3 | import arm.utils.OnSearchListener;
4 | import arm.utils.SearchPosition;
5 |
6 | import java.io.BufferedReader;
7 | import java.io.File;
8 | import java.io.FileReader;
9 | import java.io.IOException;
10 |
11 | public class KeywordSearch {
12 |
13 | public static void searchOnFile(File file, String keyword, OnSearchListener listener) {
14 | try {
15 | BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
16 | String line;
17 | int lineNumber = 0;
18 | while ((line = bufferedReader.readLine()) != null) {
19 | int startIndex = line.indexOf(keyword);
20 | if (startIndex != -1) {
21 | int end = startIndex + keyword.length();
22 | SearchPosition position = new KeywordPosition(file, lineNumber, startIndex, end);
23 | listener.onSearchFound(position);
24 | }
25 | lineNumber++;
26 | }
27 | } catch (IOException e) {
28 | System.err.println(e.getMessage());
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/arm/color/ColorSearchManager.java:
--------------------------------------------------------------------------------
1 | package arm.color;
2 |
3 | import arm.utils.DeviceInfo;
4 | import arm.utils.FileCrawler;
5 | import arm.utils.FileUtils;
6 | import arm.utils.OnSearchListener;
7 |
8 | import java.io.File;
9 | import java.util.concurrent.Executors;
10 | import java.util.concurrent.ThreadPoolExecutor;
11 |
12 | public class ColorSearchManager extends FileCrawler {
13 |
14 | private final OnSearchListener mSearchListener;
15 |
16 | public ColorSearchManager(OnSearchListener listener) {
17 | mSearchListener = listener;
18 | }
19 |
20 | public void search(File mainFile) {
21 | ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(DeviceInfo.CORE_NUM);
22 | startFileSearching(mainFile, file -> {
23 | String extensionName = FileUtils.extensionName(file.getName());
24 | if(extensionName.equals("xml") && file.getParent().endsWith("res\\layout")) {
25 | executor.execute(() -> ColorSearch.searchOnFile(file, mSearchListener));
26 | }
27 | });
28 | executor.shutdown();
29 | }
30 |
31 | @Override
32 | public void onCrawlerStart() {
33 | mSearchListener.onSearchStart();
34 | }
35 |
36 | @Override
37 | public void onCrawlerFinished() {
38 | mSearchListener.onSearchFinish();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/arm/dimens/DimensionSearchManager.java:
--------------------------------------------------------------------------------
1 | package arm.dimens;
2 |
3 | import arm.utils.DeviceInfo;
4 | import arm.utils.FileCrawler;
5 | import arm.utils.FileUtils;
6 | import arm.utils.OnSearchListener;
7 |
8 | import java.io.File;
9 | import java.util.concurrent.Executors;
10 | import java.util.concurrent.ThreadPoolExecutor;
11 |
12 | public class DimensionSearchManager extends FileCrawler {
13 |
14 | private final OnSearchListener mSearchListener;
15 |
16 | public DimensionSearchManager(OnSearchListener listener) {
17 | mSearchListener = listener;
18 | }
19 |
20 | public void search(File mainFile) {
21 | ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(DeviceInfo.CORE_NUM);
22 | startFileSearching(mainFile, file -> {
23 | String extensionName = FileUtils.extensionName(file.getName());
24 | if(extensionName.equals("xml") && file.getParent().endsWith("res\\layout")) {
25 | executor.execute(() -> DimensionSearch.searchOnFile(file, mSearchListener));
26 | }
27 | });
28 | executor.shutdown();
29 | }
30 |
31 | @Override
32 | public void onCrawlerStart() {
33 | mSearchListener.onSearchStart();
34 | }
35 |
36 | @Override
37 | public void onCrawlerFinished() {
38 | mSearchListener.onSearchFinish();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/arm/resize/ImageSize.java:
--------------------------------------------------------------------------------
1 | package arm.resize;
2 |
3 | import java.util.Objects;
4 |
5 | public class ImageSize {
6 |
7 | private final int height;
8 | private final int width;
9 | private String hint = "";
10 |
11 | public ImageSize(int height, int width) {
12 | this.height = height;
13 | this.width = width;
14 | }
15 |
16 | public ImageSize(int height, int width, String hint) {
17 | this.height = height;
18 | this.width = width;
19 | this.hint = hint;
20 | }
21 |
22 | public int getHeight() {
23 | return height;
24 | }
25 |
26 | public int getWidth() {
27 | return width;
28 | }
29 |
30 | public String getHint() {
31 | return hint;
32 | }
33 |
34 | public String sizeString() {
35 | if(height == width) return String.valueOf(height);
36 | return height + "_" + width;
37 | }
38 |
39 | @Override
40 | public boolean equals(Object o) {
41 | if (this == o) return true;
42 | if (o == null || getClass() != o.getClass()) return false;
43 | ImageSize imageSize = (ImageSize) o;
44 | return height == imageSize.height && width == imageSize.width;
45 | }
46 |
47 | @Override
48 | public int hashCode() {
49 | return Objects.hash(height, width);
50 | }
51 |
52 | @Override
53 | public String toString() {
54 | return height + "x" + width + " pixels " + hint;
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/arm/utils/FileUtils.java:
--------------------------------------------------------------------------------
1 | package arm.utils;
2 |
3 | import java.io.File;
4 | import java.util.HashSet;
5 | import java.util.Set;
6 |
7 | public class FileUtils {
8 |
9 | private static final double KILOBYTES = 1_024;
10 | private static final double MEGABYTES = 1_048_576;
11 | private static final double GIGABYTES = 1_073_741_824;
12 |
13 | private static final Set mImageExtensionsSet = new HashSet<>();
14 |
15 | static {
16 | mImageExtensionsSet.add("png");
17 | mImageExtensionsSet.add("jpeg");
18 | mImageExtensionsSet.add("jpg");
19 | }
20 |
21 | public static String extensionName(String fileName) {
22 | String extension = "";
23 | int i = fileName.lastIndexOf('.');
24 | if (i > 0) {
25 | extension = fileName.substring(i + 1);
26 | }
27 | return extension;
28 | }
29 |
30 | public static boolean isImageExtension(String fileName) {
31 | String extension = extensionName(fileName);
32 | extension = extension.toLowerCase();
33 | return mImageExtensionsSet.contains(extension);
34 | }
35 |
36 | public static String getFormattedFileSize(File file) {
37 | double lengthInBytes = file.length();
38 | if (lengthInBytes >= GIGABYTES) return String.format("%.2f", lengthInBytes / GIGABYTES) + " gb";
39 | if (lengthInBytes >= MEGABYTES) return String.format("%.2f", lengthInBytes / MEGABYTES) + " mb";
40 | if (lengthInBytes >= KILOBYTES) return String.format("%.2f", lengthInBytes / KILOBYTES) + " kb";
41 | return String.format("%.2f", lengthInBytes) + " bytes";
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/arm/dimens/DimensionSearch.java:
--------------------------------------------------------------------------------
1 | package arm.dimens;
2 |
3 | import arm.utils.OnSearchListener;
4 | import arm.utils.SearchPosition;
5 |
6 | import java.io.BufferedReader;
7 | import java.io.File;
8 | import java.io.FileReader;
9 | import java.io.IOException;
10 | import java.util.regex.Pattern;
11 |
12 | public class DimensionSearch {
13 |
14 | private static final Pattern dimensionPattern = Pattern.compile("[0-9]+(dp|sp)$");
15 |
16 | public static void searchOnFile(File file, OnSearchListener listener) {
17 | try {
18 | BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
19 | String line;
20 | int lineNumber = 0;
21 | while ((line = bufferedReader.readLine()) != null) {
22 | int firstQuoteIndex = line.indexOf('\"');
23 | if(firstQuoteIndex != -1) {
24 | int lastQuoteIndex = line.lastIndexOf('\"');
25 | if((lastQuoteIndex != -1) && (lastQuoteIndex != firstQuoteIndex)) {
26 | String value = line.substring(firstQuoteIndex + 1, lastQuoteIndex);
27 | if(dimensionPattern.matcher(value).matches()) {
28 | SearchPosition position =
29 | new DimensionPosition(file, value, lineNumber, firstQuoteIndex, lastQuoteIndex);
30 | listener.onSearchFound(position);
31 | }
32 | }
33 | }
34 | lineNumber++;
35 | }
36 | } catch (IOException e) {
37 | System.err.println(e.getMessage());
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/arm/color/ColorSearch.java:
--------------------------------------------------------------------------------
1 | package arm.color;
2 |
3 | import arm.utils.OnSearchListener;
4 | import arm.utils.SearchPosition;
5 |
6 | import java.io.BufferedReader;
7 | import java.io.File;
8 | import java.io.FileReader;
9 | import java.io.IOException;
10 |
11 | public class ColorSearch {
12 |
13 | public static void searchOnFile(File file, OnSearchListener listener) {
14 |
15 | try {
16 | BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
17 | String line;
18 | int lineNumber = 0;
19 | while ((line = bufferedReader.readLine()) != null) {
20 | int startIndex = line.indexOf("#");
21 | if (startIndex != -1) {
22 | int index = startIndex + 1;
23 | int lineLen = line.length() - 1;
24 | while ((index < lineLen) && isColorChar(line.charAt(index))) {
25 | index++;
26 | }
27 | if((index - startIndex) < 4) continue;
28 | String value = line.substring(startIndex, index);
29 | SearchPosition position = new ColorPosition(file, value, lineNumber, startIndex, index);
30 | listener.onSearchFound(position);
31 | }
32 | lineNumber++;
33 | }
34 | } catch (IOException e) {
35 | System.err.println(e.getMessage());
36 | }
37 |
38 | }
39 |
40 | private static boolean isColorChar(char c) {
41 | if(c >= '0' && c <= '9') return true;
42 | if(c >= 'a' && c <= 'f') return true;
43 | return (c >= 'A' && c <= 'F');
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/arm/search/TextSearchManager.java:
--------------------------------------------------------------------------------
1 | package arm.search;
2 |
3 | import arm.utils.DeviceInfo;
4 | import arm.utils.FileCrawler;
5 | import arm.utils.FileUtils;
6 | import arm.utils.OnSearchListener;
7 |
8 | import java.io.File;
9 | import java.util.HashSet;
10 | import java.util.Set;
11 | import java.util.concurrent.Executors;
12 | import java.util.concurrent.ThreadPoolExecutor;
13 |
14 | public class TextSearchManager extends FileCrawler {
15 |
16 | private final OnSearchListener mSearchListener;
17 | private static final Set mSupportedExtensions = new HashSet<>(5);
18 |
19 | static {
20 | mSupportedExtensions.add("java");
21 | mSupportedExtensions.add("kt");
22 | mSupportedExtensions.add("cpp");
23 | mSupportedExtensions.add("xml");
24 | mSupportedExtensions.add("txt");
25 | }
26 |
27 | public TextSearchManager(OnSearchListener listener) {
28 | mSearchListener = listener;
29 | }
30 |
31 | public void search(File mainFile, String keyword) {
32 | ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(DeviceInfo.CORE_NUM);
33 | startFileSearching(mainFile, file -> {
34 | String extensionName = FileUtils.extensionName(file.getName());
35 | if(mSupportedExtensions.contains(extensionName)) {
36 | executor.execute(() -> KeywordSearch.searchOnFile(file, keyword, mSearchListener));
37 | }
38 | });
39 | executor.shutdown();
40 | }
41 |
42 | @Override
43 | public void onCrawlerStart() {
44 | mSearchListener.onSearchStart();
45 | }
46 |
47 | @Override
48 | public void onCrawlerFinished() {
49 | mSearchListener.onSearchFinish();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/arm/analysis/AnalysisManager.java:
--------------------------------------------------------------------------------
1 | package arm.analysis;
2 |
3 | import arm.utils.DeviceInfo;
4 | import arm.utils.FileCrawler;
5 | import arm.utils.FileUtils;
6 |
7 | import java.io.File;
8 | import java.util.HashSet;
9 | import java.util.Set;
10 | import java.util.concurrent.Executors;
11 | import java.util.concurrent.ThreadPoolExecutor;
12 |
13 | public class AnalysisManager extends FileCrawler {
14 |
15 | private final OnAnalysisListener mAnalysisListener;
16 |
17 | private static final Set mSupportedExtensions = new HashSet<>();
18 | static {
19 | mSupportedExtensions.add("java");
20 | mSupportedExtensions.add("kt");
21 | mSupportedExtensions.add("xml");
22 | }
23 |
24 | public AnalysisManager(OnAnalysisListener listener) {
25 | mAnalysisListener = listener;
26 | }
27 |
28 | public void search(File projectDirectory) {
29 | ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(DeviceInfo.CORE_NUM);
30 | startFileSearching(projectDirectory, file -> {
31 | String extensionName = FileUtils.extensionName(file.getName());
32 | if(mSupportedExtensions.contains(extensionName)) {
33 | if(extensionName.equals("xml")) {
34 | if(file.getParent().endsWith("res\\layout"))
35 | executor.execute(() -> SourceAnalysis.analysisSourceFile(file, extensionName, mAnalysisListener));
36 | }
37 | else {
38 | executor.execute(() -> SourceAnalysis.analysisSourceFile(file, extensionName, mAnalysisListener));
39 | }
40 | }
41 | });
42 | executor.shutdown();
43 | }
44 |
45 | @Override
46 | public void onCrawlerStart() {
47 | mAnalysisListener.onAnalysisStart();
48 | }
49 |
50 | @Override
51 | public void onCrawlerFinished() {
52 | mAnalysisListener.onAnalysisFinish();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/arm/main/main_view.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/arm/search/search_view.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/arm/color/color_view.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/arm/dimens/dimen_view.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AndroidResourceManager
2 |
3 | [](https://sourceforge.net/projects/androidresourcemanager/files/latest/download)
4 | [](https://sourceforge.net/p/androidresourcemanager/)
5 | [](https://www.codefactor.io/repository/github/amrdeveloper/androidresourcemanager)
6 | [](https://sourceforge.net/p/androidresourcemanager/)
7 | [](https://jdk.java.net/java-se-ri/8-MR3)
8 | [](https://sourceforge.net/projects/androidresourcemanager/files/latest/download)
9 | [](https://opensource.org/licenses/MIT)
10 |
11 | Lightweight Cross-Platform tools with less than 1MB size to manage your resources as an Android Developer, AndroidResourceManager - ARM provide five main services to you
12 |
13 | ### Image Resize Service
14 | You can easily resize your drawable, mipmap or normal images with unlimited number of sizes, the default sizes are 7 which are ldpi, mdpi, tvdpi,
15 | hdpi, xhdpi, xxhdpi, xxxhdpi and you can add or remove sizes and preview your image.
16 |
17 | 
18 |
19 | ### Keyword Search Service
20 |
21 | Once you select your project directory and put your search keyword, the ARM will search in all your Java, Kotlin, C++, Xml and normal text files for this keyword
22 | and show you the details of the search, file name, start and end position.
23 |
24 | 
25 |
26 | ### Color Analysis Service
27 | Once you select your project directory and click on search,
28 | ARM will search for every hex color value in your layout resources and show it to you so you should put them in color.xml and clear your resources
29 |
30 | 
31 |
32 | ### Dimensions Analysis Service
33 | Once you select your project directory and click on search, ARM will search for every dimension value in your layout resources and show it to you so you should put them in dimens.xml and clear your resources
34 |
35 | 
36 |
37 | ### Source Code Analysis Service
38 | Once you select your project directory and click analysis, the ARM will be analysing your source code files and show you the number of Java, Kotlin and XML files.
39 |
40 | 
41 |
42 | Feel free to suggest, submit an issue or create a pull request
43 |
44 | Youtube Video: [AndroidResourceManager 1.0.0](https://www.youtube.com/watch?v=sEdpBIALJIg&feature=youtu.be&ab_channel=AmrDeveloper)
45 |
--------------------------------------------------------------------------------
/src/resources/style/main_style.css:
--------------------------------------------------------------------------------
1 | .root {
2 | -fx-background-color: #333333;
3 | }
4 |
5 | .list-view {
6 | -fx-background-color: #333333;
7 | -fx-text-fill: #cccccc;
8 | }
9 |
10 | .list-cell {
11 | -fx-background-color: #626873;
12 | -fx-text-fill: #ffffff;
13 | -fx-border-radius: 4px;
14 | }
15 |
16 | .list-cell:focused {
17 | -fx-background-color: #3b3b3b;
18 | }
19 |
20 | .button {
21 | -fx-background-color: #1d8c45;
22 | -fx-text-fill: #cccccc;
23 | }
24 |
25 | .button:hover {
26 | -fx-background-color: #16af4a;
27 | }
28 |
29 | .combo-box {
30 | -fx-background-color: #626873;
31 | -fx-border-color: #626873;
32 | -fx-border-style: solid;
33 | -fx-border-width: 1;
34 | }
35 |
36 | .combo-box .arrow {
37 | -fx-background-color: #1d8c45;
38 | }
39 |
40 | .combo-box .arrow-button {
41 | -fx-background-color: #333333;
42 | -fx-border-style: none;
43 | }
44 |
45 | .combo-box.list-cell {
46 | -fx-background-color: #333333;
47 | }
48 |
49 | .progress-bar .track{
50 | -fx-background-color: #626873;
51 | -fx-border-radius:20;
52 | -fx-background-radius:20;
53 | }
54 |
55 | .progress-bar > .bar {
56 | -fx-background-color: #1d8c45;
57 | -fx-background-insets: 0, 1, 2;
58 | -fx-border-radius:20;
59 | -fx-background-radius:20;
60 | }
61 |
62 | .progress-bar > .bar:hover {
63 | -fx-background-color: #16af4a;
64 | }
65 |
66 | .text-field {
67 | -fx-background-color: #626873;
68 | -fx-text-fill: #cccccc;
69 | }
70 |
71 | .label {
72 | -fx-text-fill: #cccccc;
73 | }
74 |
75 | .scroll-bar:horizontal .track,
76 | .scroll-bar:vertical .track{
77 | -fx-background-color :transparent;
78 | -fx-border-color :transparent;
79 | -fx-background-radius : 0.0em;
80 | -fx-border-radius :2.0em;
81 | }
82 |
83 |
84 | .scroll-bar:horizontal .increment-button ,
85 | .scroll-bar:horizontal .decrement-button {
86 | -fx-background-color :transparent;
87 | -fx-background-radius : 0.0em;
88 | -fx-padding :0.0 0.0 10.0 0.0;
89 |
90 | }
91 |
92 | .scroll-bar:vertical .increment-button ,
93 | .scroll-bar:vertical .decrement-button {
94 | -fx-background-color :transparent;
95 | -fx-background-radius : 0.0em;
96 | -fx-padding :0.0 10.0 0.0 0.0;
97 |
98 | }
99 |
100 | .scroll-bar .increment-arrow,
101 | .scroll-bar .decrement-arrow{
102 | -fx-shape : " ";
103 | -fx-padding :0.15em 0.0;
104 | }
105 |
106 | .scroll-bar:vertical .increment-arrow,
107 | .scroll-bar:vertical .decrement-arrow{
108 | -fx-shape : " ";
109 | -fx-padding :0.0 0.15em;
110 | }
111 |
112 | .scroll-bar:horizontal .thumb,
113 | .scroll-bar:vertical .thumb {
114 | -fx-background-color :derive(black,90.0%);
115 | -fx-background-insets : 2.0, 0.0, 0.0;
116 | -fx-background-radius : 2.0em;
117 | }
118 |
119 | .scroll-bar:horizontal .thumb:hover,
120 | .scroll-bar:vertical .thumb:hover {
121 | -fx-background-color :derive(#333333,10.0%);
122 | -fx-background-insets : 2.0, 0.0, 0.0;
123 | -fx-background-radius : 2.0em;
124 | }
--------------------------------------------------------------------------------
/src/arm/main/MainController.java:
--------------------------------------------------------------------------------
1 | package arm.main;
2 |
3 | import javafx.fxml.FXML;
4 | import javafx.fxml.FXMLLoader;
5 | import javafx.fxml.Initializable;
6 | import javafx.scene.Parent;
7 | import javafx.scene.control.Tooltip;
8 | import javafx.scene.image.ImageView;
9 | import javafx.scene.layout.BorderPane;
10 |
11 | import java.io.IOException;
12 | import java.net.URL;
13 | import java.util.ResourceBundle;
14 |
15 | public class MainController implements Initializable {
16 |
17 | @FXML private ImageView resizeImageView;
18 | @FXML private ImageView searchImageView;
19 | @FXML private ImageView colorImageView;
20 | @FXML private ImageView dimensionImageView;
21 | @FXML private ImageView analysisImageView;
22 | @FXML private BorderPane viewBorderPane;
23 |
24 | private static ServiceName mServiceName = ServiceName.RESIZING;
25 |
26 | @Override
27 | public void initialize(URL location, ResourceBundle resources) {
28 | setupActionsTooltip();
29 |
30 | loadViewIntoBorderPane("/arm/resize/resize_view", viewBorderPane);
31 | }
32 |
33 | private void setupActionsTooltip() {
34 | Tooltip.install(resizeImageView, new Tooltip("Resizing"));
35 | Tooltip.install(searchImageView, new Tooltip("Searching"));
36 | Tooltip.install(colorImageView, new Tooltip("Color"));
37 | Tooltip.install(dimensionImageView, new Tooltip("Dimensions"));
38 | Tooltip.install(analysisImageView, new Tooltip("Analysis"));
39 | }
40 |
41 | @FXML
42 | private void openResizeView() {
43 | if(mServiceName != ServiceName.RESIZING) {
44 | loadViewIntoBorderPane("/arm/resize/resize_view", viewBorderPane);
45 | mServiceName = ServiceName.RESIZING;
46 | }
47 | }
48 |
49 | @FXML
50 | private void openSearchView() {
51 | if(mServiceName != ServiceName.SEARCHING) {
52 | loadViewIntoBorderPane("/arm/search/search_view", viewBorderPane);
53 | mServiceName = ServiceName.SEARCHING;
54 | }
55 | }
56 |
57 | @FXML
58 | private void openColorSearchView() {
59 | if(mServiceName != ServiceName.COLOR_ANALYSIS) {
60 | loadViewIntoBorderPane("/arm/color/color_view", viewBorderPane);
61 | mServiceName = ServiceName.COLOR_ANALYSIS;
62 | }
63 | }
64 |
65 | @FXML
66 | private void openDimensionSearchView() {
67 | if(mServiceName != ServiceName.DIMENS_ANALYSIS) {
68 | loadViewIntoBorderPane("/arm/dimens/dimen_view", viewBorderPane);
69 | mServiceName = ServiceName.DIMENS_ANALYSIS;
70 | }
71 | }
72 |
73 | @FXML
74 | private void openAnalysisSearchView() {
75 | if(mServiceName != ServiceName.SOURCE_ANALYSIS) {
76 | loadViewIntoBorderPane("/arm/analysis/analysis_view", viewBorderPane);
77 | mServiceName = ServiceName.SOURCE_ANALYSIS;
78 | }
79 | }
80 |
81 | private void loadViewIntoBorderPane(String viewName, BorderPane pane) {
82 | Parent root = null;
83 | try {
84 | root = FXMLLoader.load(getClass().getResource(viewName + ".fxml"));
85 | } catch (IOException e) {
86 | System.err.println("Invalid View Loader : " + e.getMessage());
87 | }
88 | pane.setCenter(root);
89 | }
90 | }
--------------------------------------------------------------------------------
/src/arm/analysis/analysis_view.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/arm/resize/ResizeManager.java:
--------------------------------------------------------------------------------
1 | package arm.resize;
2 |
3 | import arm.utils.DeviceInfo;
4 | import arm.utils.FileUtils;
5 |
6 | import javax.imageio.ImageIO;
7 | import java.awt.*;
8 | import java.awt.image.BufferedImage;
9 | import java.io.File;
10 | import java.io.IOException;
11 | import java.util.*;
12 | import java.util.concurrent.Executors;
13 | import java.util.concurrent.ThreadPoolExecutor;
14 |
15 | public class ResizeManager {
16 |
17 | private volatile static ResizeManager mInstance = null;
18 |
19 | public static ResizeManager getInstance() {
20 | if (mInstance == null) {
21 | mInstance = new ResizeManager();
22 | }
23 | return mInstance;
24 | }
25 |
26 | public void resize(ResizeOrder order, OnProgressListener listener) {
27 | ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(DeviceInfo.CORE_NUM);
28 | Map outputDirectories = generateOutputDirectories(
29 | order.getOutputDirectory(),
30 | order.getSizeSet(),
31 | order.getImageType());
32 |
33 | final float[] progress = {0};
34 | int orderSize = order.getImageList().size();
35 | for (File image : order.getImageList()) {
36 | executor.execute(() -> {
37 | resizeImage(image, order.getSizeSet(), outputDirectories);
38 | progress[0] += 1;
39 | listener.onProcessChange(progress[0] / orderSize);
40 | });
41 | }
42 | executor.shutdown();
43 | }
44 |
45 | private void resizeImage(File image, Set sizes, Map directories) {
46 | for (ImageSize size : sizes) {
47 | try {
48 | BufferedImage originalImage = ImageIO.read(image);
49 | BufferedImage resizedImage = imageBufferedResize(originalImage, size);
50 | File outputDirectory = directories.get(size);
51 | String extension = FileUtils.extensionName(image.getName());
52 | String imagePath = outputDirectory + File.separator + imageNameParser(image.getName()) + "." + extension;
53 | ImageIO.write(resizedImage, extension, new File(imagePath));
54 | } catch (IOException e) {
55 | System.err.println("Can't create this directory : " + e.getMessage());
56 | }
57 | }
58 | }
59 |
60 | private BufferedImage imageBufferedResize(BufferedImage originalImage, ImageSize size) {
61 | final BufferedImage bufferedImage = new BufferedImage(size.getWidth(), size.getHeight(), BufferedImage.TYPE_INT_RGB);
62 | final Graphics2D graphics2D = bufferedImage.createGraphics();
63 | graphics2D.setComposite(AlphaComposite.Src);
64 | graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
65 | graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
66 | graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
67 | graphics2D.drawImage(originalImage, 0, 0, size.getWidth(), size.getHeight(), null);
68 | graphics2D.dispose();
69 | return bufferedImage;
70 | }
71 |
72 | private Map generateOutputDirectories(File mainDirectory, Set sizes, ImageType type) {
73 | String mainPath = mainDirectory.getAbsolutePath();
74 | Map outputDirectories = new HashMap<>();
75 | for (ImageSize imageSize : sizes) {
76 | String sizeName = imageSize.getHint().isEmpty() ? imageSize.sizeString() : imageSize.getHint();
77 | String path = mainPath + File.separator + type.getName().toLowerCase() + "-" + sizeName;
78 | File directory = new File(path);
79 | if (directory.exists()) {
80 | outputDirectories.put(imageSize, directory);
81 | } else {
82 | boolean success = directory.mkdir();
83 | if (success) {
84 | outputDirectories.put(imageSize, directory);
85 | } else {
86 | System.err.println("Can't create this directory : " + directory.getAbsolutePath());
87 | }
88 | }
89 | }
90 | return outputDirectories;
91 | }
92 |
93 | private String imageNameParser(String fullName) {
94 | int dotIndex = fullName.indexOf('.');
95 | return fullName.substring(0, dotIndex);
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/arm/resize/resize_view.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/arm/color/ColorController.java:
--------------------------------------------------------------------------------
1 | package arm.color;
2 |
3 | import arm.utils.AlertManager;
4 | import arm.utils.OnSearchListener;
5 | import arm.utils.SearchPosition;
6 | import javafx.application.Platform;
7 | import javafx.fxml.FXML;
8 | import javafx.fxml.Initializable;
9 | import javafx.scene.control.*;
10 | import javafx.scene.input.MouseEvent;
11 | import javafx.scene.layout.BorderPane;
12 | import javafx.stage.DirectoryChooser;
13 | import javafx.stage.Stage;
14 |
15 | import java.io.File;
16 | import java.net.URL;
17 | import java.util.ResourceBundle;
18 |
19 | public class ColorController implements Initializable, OnSearchListener {
20 |
21 | @FXML private Label searchStateLabel;
22 | @FXML private Label matchesCountLabel;
23 | @FXML private Label colorValueLabel;
24 | @FXML private TextField layoutsPathTextField;
25 |
26 | @FXML private Button layoutPathButton;
27 | @FXML private Button colorSearchButton;
28 |
29 | @FXML private ListView colorListView;
30 | @FXML private BorderPane colorViewLayout;
31 |
32 | private int mSearchResultCounter = 0;
33 | private final ColorSearchManager mColorSearchManager = new ColorSearchManager(this);
34 |
35 | @Override
36 | public void initialize(URL location, ResourceBundle resources) {
37 | setViewsTooltip();
38 | resultListViewSetup();
39 | }
40 |
41 | private void setViewsTooltip() {
42 | searchStateLabel.setTooltip(new Tooltip("State of search"));
43 | matchesCountLabel.setTooltip(new Tooltip("Number of matches search"));
44 | colorValueLabel.setTooltip(new Tooltip("The value of current color"));
45 |
46 | layoutPathButton.setTooltip(new Tooltip("Find button to select project path"));
47 | colorSearchButton.setTooltip(new Tooltip("Search button to start search for colors"));
48 |
49 | colorListView.setTooltip(new Tooltip("List of color result"));
50 | }
51 |
52 | private void resultListViewSetup() {
53 | colorListView.setOnMouseClicked(this::onSearchResultSelected);
54 | colorListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
55 | colorListView.setPlaceholder(new Label("List of your Colors search result :)"));
56 | }
57 |
58 | private void onSearchResultSelected(MouseEvent event) {
59 | ColorPosition position = colorListView.getSelectionModel().getSelectedItem();
60 | if(position != null) {
61 | colorValueLabel.setText(position.getValue());
62 | }
63 | }
64 |
65 | @FXML
66 | private void findProjectPath() {
67 | DirectoryChooser directoryChooser = new DirectoryChooser();
68 | directoryChooser.setTitle("Output Directory Path");
69 | Stage currentStage = (Stage) colorViewLayout.getScene().getWindow();
70 | File output = directoryChooser.showDialog(currentStage);
71 | if(output != null) {
72 | layoutsPathTextField.setText(output.getPath());
73 | }
74 | }
75 |
76 | @FXML
77 | private void startColorAnalysis() {
78 | String layoutsPath = layoutsPathTextField.getText();
79 | if(layoutsPath.isEmpty()) {
80 | AlertManager.showErrorDialog("Search Action",
81 | "Project Path",
82 | "Project or File path is empty.");
83 | return;
84 | }
85 |
86 | File layoutsDirectory = new File(layoutsPath);
87 | if(!layoutsDirectory.exists()) {
88 | AlertManager.showErrorDialog("Search Action",
89 | "Project Path",
90 | "Project or File path don't exists.");
91 | return;
92 | }
93 |
94 | colorListView.getItems().clear();
95 | new Thread(() -> mColorSearchManager.search(layoutsDirectory)).start();
96 | }
97 |
98 | @Override
99 | public void onSearchStart() {
100 | Platform.runLater(() -> {
101 | searchStateLabel.setText("Searching...");
102 | matchesCountLabel.setText("0");
103 | });
104 | }
105 |
106 | @Override
107 | public void onSearchFound(SearchPosition position) {
108 | Platform.runLater(() -> {
109 | colorListView.getItems().add((ColorPosition) position);
110 | mSearchResultCounter++;
111 | matchesCountLabel.setText(String.valueOf(mSearchResultCounter));
112 | });
113 | }
114 |
115 | @Override
116 | public void onSearchFinish() {
117 | Platform.runLater(() -> searchStateLabel.setText("Done"));
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/arm/dimens/DimensionController.java:
--------------------------------------------------------------------------------
1 | package arm.dimens;
2 |
3 | import arm.utils.AlertManager;
4 | import arm.utils.OnSearchListener;
5 | import arm.utils.SearchPosition;
6 | import javafx.application.Platform;
7 | import javafx.fxml.FXML;
8 | import javafx.fxml.Initializable;
9 | import javafx.scene.control.*;
10 | import javafx.scene.input.MouseEvent;
11 | import javafx.scene.layout.BorderPane;
12 | import javafx.stage.DirectoryChooser;
13 | import javafx.stage.Stage;
14 |
15 | import java.io.File;
16 | import java.net.URL;
17 | import java.util.ResourceBundle;
18 |
19 | public class DimensionController implements Initializable, OnSearchListener {
20 |
21 | @FXML private Label searchStateLabel;
22 | @FXML private Label matchesCountLabel;
23 | @FXML private Label colorValueLabel;
24 | @FXML private TextField layoutsPathTextField;
25 |
26 | @FXML private Button layoutPathButton;
27 | @FXML private Button dimensionSearchButton;
28 |
29 | @FXML private ListView dimensionListView;
30 | @FXML private BorderPane dimensViewLayout;
31 |
32 | private int mSearchResultCounter = 0;
33 | private final DimensionSearchManager mDimensionSearchManager = new DimensionSearchManager(this);
34 |
35 | @Override
36 | public void initialize(URL location, ResourceBundle resources) {
37 | setViewsTooltip();
38 | resultListViewSetup();
39 | }
40 |
41 | private void setViewsTooltip() {
42 | searchStateLabel.setTooltip(new Tooltip("State of search"));
43 | matchesCountLabel.setTooltip(new Tooltip("Number of matches search"));
44 | colorValueLabel.setTooltip(new Tooltip("The value of current color"));
45 |
46 | layoutPathButton.setTooltip(new Tooltip("Find button to select project path"));
47 | dimensionSearchButton.setTooltip(new Tooltip("Search button to start search for colors"));
48 |
49 | dimensionListView.setTooltip(new Tooltip("List of dimensions result"));
50 | }
51 |
52 | private void resultListViewSetup() {
53 | dimensionListView.setOnMouseClicked(this::onSearchResultSelected);
54 | dimensionListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
55 | dimensionListView.setPlaceholder(new Label("List of your dimensions search result :)"));
56 | }
57 |
58 | private void onSearchResultSelected(MouseEvent event) {
59 | DimensionPosition position = dimensionListView.getSelectionModel().getSelectedItem();
60 | if(position != null) {
61 | colorValueLabel.setText(position.getValue());
62 | }
63 | }
64 |
65 | @FXML
66 | private void findProjectPath() {
67 | DirectoryChooser directoryChooser = new DirectoryChooser();
68 | directoryChooser.setTitle("Output Directory Path");
69 | Stage currentStage = (Stage) dimensViewLayout.getScene().getWindow();
70 | File output = directoryChooser.showDialog(currentStage);
71 | if(output != null) {
72 | layoutsPathTextField.setText(output.getPath());
73 | }
74 | }
75 |
76 | @FXML
77 | private void startColorAnalysis() {
78 | String layoutsPath = layoutsPathTextField.getText();
79 | if(layoutsPath.isEmpty()) {
80 | AlertManager.showErrorDialog("Search Action",
81 | "Project Path",
82 | "Project or File path is empty.");
83 | return;
84 | }
85 |
86 | File layoutsDirectory = new File(layoutsPath);
87 | if(!layoutsDirectory.exists()) {
88 | AlertManager.showErrorDialog("Search Action",
89 | "Project Path",
90 | "Project or File path don't exists.");
91 | return;
92 | }
93 |
94 | dimensionListView.getItems().clear();
95 | new Thread(() -> mDimensionSearchManager.search(layoutsDirectory)).start();
96 | }
97 |
98 | @Override
99 | public void onSearchStart() {
100 | Platform.runLater(() -> {
101 | searchStateLabel.setText("Searching...");
102 | matchesCountLabel.setText("0");
103 | });
104 | }
105 |
106 | @Override
107 | public void onSearchFound(SearchPosition position) {
108 | Platform.runLater(() -> {
109 | dimensionListView.getItems().add((DimensionPosition) position);
110 | mSearchResultCounter++;
111 | matchesCountLabel.setText(String.valueOf(mSearchResultCounter));
112 | });
113 | }
114 |
115 | @Override
116 | public void onSearchFinish() {
117 | Platform.runLater(() -> searchStateLabel.setText("Done"));
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/arm/search/SearchController.java:
--------------------------------------------------------------------------------
1 | package arm.search;
2 |
3 | import arm.utils.AlertManager;
4 | import arm.utils.OnSearchListener;
5 | import arm.utils.SearchPosition;
6 | import javafx.application.Platform;
7 | import javafx.fxml.FXML;
8 | import javafx.fxml.Initializable;
9 | import javafx.scene.control.*;
10 | import javafx.scene.control.Button;
11 | import javafx.scene.control.Label;
12 | import javafx.scene.control.TextField;
13 | import javafx.scene.input.MouseEvent;
14 | import javafx.scene.layout.BorderPane;
15 | import javafx.stage.DirectoryChooser;
16 | import javafx.stage.Stage;
17 |
18 | import java.awt.*;
19 | import java.io.File;
20 | import java.io.IOException;
21 | import java.net.URL;
22 | import java.util.ResourceBundle;
23 |
24 | public class SearchController implements Initializable, OnSearchListener {
25 |
26 | @FXML private Label matchesCountLabel;
27 | @FXML private Label searchStateLabel;
28 | @FXML private TextField projectPathTextField;
29 | @FXML private TextField searchKeywordTextField;
30 |
31 | @FXML private Button findPathButton;
32 | @FXML private Button searchButton;
33 |
34 | @FXML private ListView searchResultListView;
35 |
36 | @FXML private BorderPane searchViewLayout;
37 |
38 | private int mSearchResultCounter = 0;
39 | private final TextSearchManager mTextSearchManager = new TextSearchManager(this);
40 |
41 | @Override
42 | public void initialize(URL location, ResourceBundle resources) {
43 | setViewsTooltip();
44 | resultListViewSetup();
45 | }
46 |
47 | private void setViewsTooltip() {
48 | matchesCountLabel.setTooltip(new Tooltip("Number of matches search"));
49 | searchStateLabel.setTooltip(new Tooltip("Search State Label"));
50 |
51 | projectPathTextField.setTooltip(new Tooltip("Project Path to search in it"));
52 | searchKeywordTextField.setTooltip(new Tooltip("Search keyword to search with it"));
53 |
54 | findPathButton.setTooltip(new Tooltip("Find button to select project path"));
55 | searchButton.setTooltip(new Tooltip("Search button to start searching with keyword"));
56 |
57 | searchResultListView.setTooltip(new Tooltip("List of search Result"));
58 | }
59 |
60 | @FXML
61 | private void findProjectPath() {
62 | DirectoryChooser directoryChooser = new DirectoryChooser();
63 | directoryChooser.setTitle("Output Directory Path");
64 | Stage currentStage = (Stage) searchViewLayout.getScene().getWindow();
65 | File output = directoryChooser.showDialog(currentStage);
66 | if(output != null) {
67 | projectPathTextField.setText(output.getPath());
68 | }
69 | }
70 |
71 | @FXML
72 | private void keywordSearching() {
73 | mSearchResultCounter = 0;
74 | String projectPath = projectPathTextField.getText();
75 | File path = new File(projectPath);
76 | if(!path.exists()) {
77 | AlertManager.showErrorDialog("Search Action",
78 | "Project Path",
79 | "Project or File path don't exists.");
80 | return;
81 | }
82 |
83 | String keyword = searchKeywordTextField.getText();
84 | if(keyword.isEmpty()) {
85 | AlertManager.showErrorDialog("Search Action",
86 | "Search Keyword",
87 | "Search keyword mustn't be empty.");
88 | return;
89 | }
90 |
91 | searchResultListView.getItems().clear();
92 |
93 | new Thread(() -> mTextSearchManager.search(path, keyword)).start();
94 | }
95 |
96 | private void resultListViewSetup() {
97 | searchResultListView.setOnMouseClicked(this::onSearchResultSelected);
98 | searchResultListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
99 | searchResultListView.setPlaceholder(new Label("List of your search result :)"));
100 | }
101 |
102 | private void onSearchResultSelected(MouseEvent event) {
103 | SearchPosition position = searchResultListView.getSelectionModel().getSelectedItem();
104 | if (position != null) {
105 | Desktop desktop = Desktop.getDesktop();
106 | try {
107 | desktop.open(position.getFile());
108 | } catch (IOException e) {
109 | e.printStackTrace();
110 | }
111 | }
112 | }
113 |
114 | @Override
115 | public void onSearchStart() {
116 | Platform.runLater(() -> {
117 | searchStateLabel.setText("Searching...");
118 | matchesCountLabel.setText("0");
119 | });
120 | }
121 |
122 | @Override
123 | public void onSearchFound(SearchPosition position) {
124 | Platform.runLater(() -> {
125 | searchResultListView.getItems().add((KeywordPosition) position);
126 | mSearchResultCounter++;
127 | matchesCountLabel.setText(String.valueOf(mSearchResultCounter));
128 | });
129 | }
130 |
131 | @Override
132 | public void onSearchFinish() {
133 | Platform.runLater(() -> searchStateLabel.setText("Done"));
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/arm/analysis/AnalysisController.java:
--------------------------------------------------------------------------------
1 | package arm.analysis;
2 |
3 | import arm.utils.AlertManager;
4 | import javafx.application.Platform;
5 | import javafx.fxml.FXML;
6 | import javafx.fxml.Initializable;
7 | import javafx.scene.control.Button;
8 | import javafx.scene.control.Label;
9 | import javafx.scene.control.TextField;
10 | import javafx.scene.control.Tooltip;
11 | import javafx.scene.layout.BorderPane;
12 | import javafx.stage.DirectoryChooser;
13 | import javafx.stage.Stage;
14 |
15 | import java.io.File;
16 | import java.net.URL;
17 | import java.util.ResourceBundle;
18 |
19 | public class AnalysisController implements Initializable, OnAnalysisListener {
20 |
21 | @FXML private Label numberOfFilesLabel;
22 | @FXML private Label numberOfJavaFilesLabel;
23 | @FXML private Label numberOfKotlinFilesLabel;
24 | @FXML private Label numberOfXmlFilesLabel;
25 | @FXML private Label numberOfJavaLinesLabel;
26 | @FXML private Label numberOfKotlinLinesLabel;
27 | @FXML private Label numberOfXmlLinesLabel;
28 | @FXML private Label numberOfLinesLabel;
29 | @FXML private Label analysisStateLabel;
30 |
31 | @FXML private TextField projectPathTextField;
32 | @FXML private Button findPathButton;
33 | @FXML private Button analysisButton;
34 |
35 | @FXML private BorderPane analysisViewLayout;
36 |
37 | private int javaLinesCount = 0;
38 | private int kotlinLinesCount = 0;
39 | private int xmlLinesCount = 0;
40 | private int allLinesCount = 0;
41 | private int javaFilesCount = 0;
42 | private int kotlinFilesCount = 0;
43 | private int xmlFilesCount = 0;
44 | private int allFilesCount = 0;
45 |
46 | private final AnalysisManager mAnalysisManager = new AnalysisManager(this);
47 |
48 | @Override
49 | public void initialize(URL location, ResourceBundle resources) {
50 | setViewsTooltip();
51 | }
52 |
53 | private void setViewsTooltip() {
54 | findPathButton.setTooltip(new Tooltip("Find button to select project path"));
55 | analysisButton.setTooltip(new Tooltip("Start Project Analysing"));
56 | }
57 |
58 | private void resetAllCounters() {
59 | javaLinesCount = 0;
60 | kotlinLinesCount = 0;
61 | xmlLinesCount = 0;
62 | allLinesCount = 0;
63 | javaFilesCount = 0;
64 | kotlinFilesCount = 0;
65 | xmlFilesCount = 0;
66 | allFilesCount = 0;
67 | }
68 |
69 | private void resetAllCountersUI() {
70 | Platform.runLater(() -> {
71 | numberOfJavaFilesLabel.setText(String.valueOf(javaFilesCount));
72 | numberOfJavaLinesLabel.setText(String.valueOf(javaLinesCount));
73 |
74 | numberOfKotlinFilesLabel.setText(String.valueOf(kotlinFilesCount));
75 | numberOfKotlinLinesLabel.setText(String.valueOf(kotlinLinesCount));
76 |
77 | numberOfXmlFilesLabel.setText(String.valueOf(xmlFilesCount));
78 | numberOfXmlLinesLabel.setText(String.valueOf(xmlLinesCount));
79 |
80 | numberOfFilesLabel.setText(String.valueOf(allFilesCount));
81 | numberOfLinesLabel.setText(String.valueOf(allLinesCount));
82 | });
83 | }
84 |
85 | @FXML
86 | private void startDirectoryAnalysis() {
87 | String projectPath = projectPathTextField.getText();
88 | File path = new File(projectPath);
89 | if(!path.exists()) {
90 | AlertManager.showErrorDialog("Search Action",
91 | "Project Path",
92 | "Project or File path don't exists.");
93 | return;
94 | }
95 |
96 | resetAllCounters();
97 | resetAllCountersUI();
98 | new Thread(() -> mAnalysisManager.search(path)).start();
99 | }
100 |
101 | @FXML
102 | private void findProjectPath() {
103 | DirectoryChooser directoryChooser = new DirectoryChooser();
104 | directoryChooser.setTitle("Output Directory Path");
105 | Stage currentStage = (Stage) analysisViewLayout.getScene().getWindow();
106 | File output = directoryChooser.showDialog(currentStage);
107 | if(output != null) {
108 | projectPathTextField.setText(output.getPath());
109 | }
110 | }
111 |
112 | @Override
113 | public void onAnalysisStart() {
114 | Platform.runLater(() -> analysisStateLabel.setText("Analysing..."));
115 | }
116 |
117 | @Override
118 | public void onAnalysisFound(Source source) {
119 | String extension = source.getType();
120 | allLinesCount += source.getLinesNum();
121 | allFilesCount++;
122 |
123 | switch (extension) {
124 | case "java": {
125 | javaLinesCount += source.getLinesNum();
126 | javaFilesCount++;
127 | Platform.runLater(() -> {
128 | numberOfJavaFilesLabel.setText(String.valueOf(javaFilesCount));
129 | numberOfJavaLinesLabel.setText(String.valueOf(javaLinesCount));
130 | });
131 | break;
132 | }
133 | case "kt": {
134 | kotlinLinesCount += source.getLinesNum();
135 | kotlinFilesCount++;
136 | Platform.runLater(() -> {
137 | numberOfKotlinFilesLabel.setText(String.valueOf(kotlinFilesCount));
138 | numberOfKotlinLinesLabel.setText(String.valueOf(kotlinLinesCount));
139 | });
140 | break;
141 | }
142 | case "xml": {
143 | xmlLinesCount += source.getLinesNum();
144 | xmlFilesCount++;
145 | Platform.runLater(() -> {
146 | numberOfXmlFilesLabel.setText(String.valueOf(xmlFilesCount));
147 | numberOfXmlLinesLabel.setText(String.valueOf(xmlLinesCount));
148 | });
149 | break;
150 | }
151 | }
152 |
153 | Platform.runLater(() -> {
154 | numberOfFilesLabel.setText(String.valueOf(allFilesCount));
155 | numberOfLinesLabel.setText(String.valueOf(allLinesCount));
156 | });
157 | }
158 |
159 | @Override
160 | public void onAnalysisFinish() {
161 | Platform.runLater(() -> analysisStateLabel.setText("Done"));
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/.idea/uiDesigner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 | -
9 |
10 |
11 | -
12 |
13 |
14 | -
15 |
16 |
17 | -
18 |
19 |
20 |
21 |
22 |
23 | -
24 |
25 |
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 |
46 | -
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 |
60 |
61 | -
62 |
63 |
64 |
65 |
66 | -
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 | -
75 |
76 |
77 |
78 |
79 | -
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
87 |
88 |
89 | -
90 |
91 |
92 |
93 |
94 | -
95 |
96 |
97 |
98 |
99 | -
100 |
101 |
102 | -
103 |
104 |
105 | -
106 |
107 |
108 | -
109 |
110 |
111 | -
112 |
113 |
114 |
115 |
116 | -
117 |
118 |
119 | -
120 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/src/arm/resize/ResizeController.java:
--------------------------------------------------------------------------------
1 | package arm.resize;
2 |
3 | import arm.utils.FileUtils;
4 | import arm.utils.ValidationUtils;
5 | import arm.utils.AlertManager;
6 | import javafx.application.Platform;
7 | import javafx.collections.ObservableList;
8 | import javafx.fxml.FXML;
9 | import javafx.fxml.Initializable;
10 | import javafx.scene.control.*;
11 | import javafx.scene.image.Image;
12 | import javafx.scene.image.ImageView;
13 | import javafx.scene.input.DragEvent;
14 | import javafx.scene.input.MouseEvent;
15 | import javafx.scene.input.TransferMode;
16 | import javafx.scene.layout.BorderPane;
17 | import javafx.stage.DirectoryChooser;
18 | import javafx.stage.Stage;
19 |
20 | import java.io.File;
21 | import java.net.URL;
22 | import java.util.*;
23 |
24 | public class ResizeController implements Initializable, OnProgressListener {
25 |
26 | // Preview Views
27 | @FXML private ImageView previewImageView;
28 | @FXML private Label previewImageSize;
29 | @FXML private Label previewImageDimensions;
30 |
31 | // Options
32 | @FXML private ComboBox imageTypeComboBox;
33 |
34 | // State
35 | @FXML private ProgressBar stateProgressBar;
36 |
37 | // Image Sizes Views
38 | @FXML private TextField heightTextField;
39 | @FXML private TextField widthTextField;
40 | @FXML private Button addSizeButton;
41 | @FXML private Button clearSizeButton;
42 | @FXML private ListView imageSizesListView;
43 |
44 | // Image List Views
45 | @FXML private TextField pathTextField;
46 | @FXML private Button outputPathButton;
47 | @FXML private Button clearSelectedImageButton;
48 | @FXML private Button clearAllImagesAction;
49 | @FXML private Button resizeButton;
50 | @FXML private ListView imagesListView;
51 | @FXML private BorderPane resizeViewLayout;
52 |
53 | private final Set mImagesFilesSet = new HashSet<>();
54 | private final Set mImagesSizeSet = new HashSet<>();
55 |
56 | private final ResizeManager mResizeManager = ResizeManager.getInstance();
57 | private final static Image mDefaultPreviewImage = new Image("resources/icon/preview_128.png");
58 |
59 | @Override
60 | public void initialize(URL location, ResourceBundle resources) {
61 | imageListViewSetup();
62 | sizeListViewSetup();
63 | setViewsTooltip();
64 | setPreviewImageDefaultValues();
65 | imageTypeComboBox.getItems().addAll(ImageType.values());
66 | imageTypeComboBox.getSelectionModel().select(0);
67 | }
68 |
69 | private void setViewsTooltip() {
70 | // Sizes Tooltip
71 | addSizeButton.setTooltip(new Tooltip("Add New Size"));
72 | clearSizeButton.setTooltip(new Tooltip("Clear Selected Size"));
73 | imageSizesListView.setTooltip(new Tooltip("Image Sizes"));
74 |
75 | imageTypeComboBox.setTooltip(new Tooltip("Select Image Type"));
76 | stateProgressBar.setTooltip(new Tooltip("State ProgressBar"));
77 |
78 | // Images Tooltip
79 | pathTextField.setTooltip(new Tooltip("Output Path"));
80 | outputPathButton.setTooltip(new Tooltip("Set output Path"));
81 | clearSelectedImageButton.setTooltip(new Tooltip("Clear Selected Images"));
82 | clearAllImagesAction.setTooltip(new Tooltip("Clear All Images"));
83 | resizeButton.setTooltip(new Tooltip("Start Resizing"));
84 | imagesListView.setTooltip(new Tooltip("Image List"));
85 | }
86 |
87 | @FXML
88 | private void onImageDragging(DragEvent event) {
89 | if (event.getDragboard().hasFiles()) {
90 | List files = event.getDragboard().getFiles();
91 | boolean isValidFileType = true;
92 | for(File file : files) {
93 | if(file.isFile() && !FileUtils.isImageExtension(file.getName())) isValidFileType = false;
94 | }
95 | if(isValidFileType) event.acceptTransferModes(TransferMode.ANY);
96 | }
97 | event.consume();
98 | }
99 |
100 | @FXML
101 | private void onImageDragDropped(DragEvent event) {
102 | List currentDropped = event.getDragboard().getFiles();
103 | for(File imageFile : currentDropped) {
104 | if(imageFile.isFile()) {
105 | if(mImagesFilesSet.add(imageFile)) {
106 | imagesListView.getItems().add(imageFile);
107 | }
108 | } else {
109 | crawlImagesFromDirectory(imageFile);
110 | }
111 | }
112 | event.setDropCompleted(true);
113 | event.consume();
114 | }
115 |
116 | private void crawlImagesFromDirectory(File directory) {
117 | for(File file : Objects.requireNonNull(directory.listFiles())) {
118 | if(file.isDirectory()) crawlImagesFromDirectory(file);
119 | else if(file.isFile() && FileUtils.isImageExtension(file.getName())) {
120 | this.mImagesFilesSet.add(file);
121 | this.imagesListView.getItems().add(file);
122 | }
123 | }
124 | }
125 |
126 | @FXML
127 | private void resizeButtonAction() {
128 | String outputPath = pathTextField.getText();
129 | if(outputPath.isEmpty()) {
130 | AlertManager.showErrorDialog("Resize Action",
131 | "Output Path",
132 | "Output Path Can't be empty.");
133 | return;
134 | }
135 |
136 | File outputPathFile = new File(outputPath);
137 | if(!outputPathFile.exists() && !outputPathFile.canWrite()) {
138 | AlertManager.showErrorDialog("Resize Action",
139 | "Output Path",
140 | "Output Path not exists or can't write.");
141 | return;
142 | }
143 |
144 | if(!outputPathFile.isDirectory()) {
145 | AlertManager.showErrorDialog("Resize Action",
146 | "Output Path",
147 | "Output Path must be Directory.");
148 | return;
149 | }
150 |
151 | if (mImagesSizeSet.isEmpty()) {
152 | AlertManager.showErrorDialog("Resize Action",
153 | "Number of sizes",
154 | "You must have at last one size.");
155 | return;
156 | }
157 |
158 | ImageType imageType = imageTypeComboBox.getSelectionModel().getSelectedItem();
159 | ResizeOrder resizeOrder = new ResizeOrder(mImagesFilesSet, mImagesSizeSet, imageType, outputPathFile);
160 | new Thread(() -> mResizeManager.resize(resizeOrder, ResizeController.this)).start();
161 | }
162 |
163 | @FXML
164 | private void findOutputDirectoryPath() {
165 | DirectoryChooser directoryChooser = new DirectoryChooser();
166 | directoryChooser.setTitle("Output Directory Path");
167 | Stage currentStage = (Stage) resizeViewLayout.getScene().getWindow();
168 | File output = directoryChooser.showDialog(currentStage);
169 | if(output != null) {
170 | pathTextField.setText(output.getPath());
171 | }
172 | }
173 |
174 | @FXML
175 | private void onImagesListClearSelectedItems() {
176 | List selectedImagesIndex = imagesListView.getSelectionModel().getSelectedIndices();
177 | for (int i = selectedImagesIndex.size() - 1; i > -1; i--) {
178 | int currentIndex = selectedImagesIndex.get(i);
179 | File removedImage = imagesListView.getItems().remove(currentIndex);
180 | mImagesFilesSet.remove(removedImage);
181 | }
182 |
183 | if(imagesListView.getItems().size() == 0) {
184 | setPreviewImageDefaultValues();
185 | return;
186 | }
187 |
188 | updatePreviewWithSelectedImage();
189 | }
190 |
191 | @FXML
192 | private void onImagesListClearAllItems() {
193 | mImagesFilesSet.clear();
194 | this.imagesListView.getItems().clear();
195 | setPreviewImageDefaultValues();
196 | }
197 |
198 | @FXML
199 | private void addImageSize() {
200 | String height = heightTextField.getText();
201 | String width = widthTextField.getText();
202 |
203 | if(height.isEmpty() || width.isEmpty()) {
204 | AlertManager.showErrorDialog("Add Size Action",
205 | "Image Size",
206 | "Height and Width can't be empty.");
207 | return;
208 | }
209 |
210 | if(!ValidationUtils.isInteger(height)
211 | || !ValidationUtils.isInteger(width)) {
212 | AlertManager.showErrorDialog("Add Size Action",
213 | "Image Size",
214 | "Height and Width must be integers.");
215 | return;
216 | }
217 |
218 | int iHeight = Integer.parseInt(height);
219 | int iWidth = Integer.parseInt(width);
220 | ImageSize imageSize = new ImageSize(iHeight, iWidth);
221 |
222 | boolean isUnique = mImagesSizeSet.add(imageSize);
223 | if(isUnique) {
224 | imageSizesListView.getItems().add(imageSize);
225 | heightTextField.clear();
226 | widthTextField.clear();
227 | }
228 | }
229 |
230 | @FXML
231 | private void clearSelectedImageSize() {
232 | ObservableList selectedImageSizes = imageSizesListView.getSelectionModel().getSelectedItems();
233 | mImagesSizeSet.removeAll(selectedImageSizes);
234 | imageSizesListView.getItems().removeAll(selectedImageSizes);
235 | }
236 |
237 | private void imageListViewSetup() {
238 | this.imagesListView.setOnMouseClicked(this::onImageSelected);
239 | this.imagesListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
240 | this.imagesListView.setPlaceholder(new Label("Drop you images here :)"));
241 | }
242 |
243 | private void sizeListViewSetup() {
244 | this.imageSizesListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
245 |
246 | // Add default 7 sizes for Android Development
247 | this.mImagesSizeSet.add(new ImageSize(36, 36, "ldpi"));
248 | this.mImagesSizeSet.add(new ImageSize(48, 48, "mdpi"));
249 | this.mImagesSizeSet.add(new ImageSize(64, 64, "tvdpi"));
250 | this.mImagesSizeSet.add(new ImageSize(72, 72, "hdpi"));
251 | this.mImagesSizeSet.add(new ImageSize(96, 96, "xhdpi"));
252 | this.mImagesSizeSet.add(new ImageSize(144, 144, "xxhdpi"));
253 | this.mImagesSizeSet.add(new ImageSize(192, 192, "xxxhdpi"));
254 | this.imageSizesListView.getItems().addAll(mImagesSizeSet);
255 | }
256 |
257 | private void onImageSelected(MouseEvent event) {
258 | updatePreviewWithSelectedImage();
259 | }
260 |
261 | private void setPreviewImageDefaultValues() {
262 | previewImageView.setImage(mDefaultPreviewImage);
263 | previewImageSize.setText("0 bytes");
264 | previewImageDimensions.setText("0x0");
265 | }
266 |
267 | private void updatePreviewWithSelectedImage() {
268 | File selectedItem = imagesListView.getSelectionModel().getSelectedItem();
269 | if(selectedItem != null) {
270 | Image image = new Image(selectedItem.toURI().toString());
271 | previewImageSize.setText(FileUtils.getFormattedFileSize(selectedItem));
272 | previewImageDimensions.setText(image.getHeight() + "x" + image.getWidth());
273 | previewImageView.setImage(image);
274 | } else {
275 | setPreviewImageDefaultValues();
276 | }
277 | }
278 |
279 | @Override
280 | public void onProcessChange(float progress) {
281 | Platform.runLater(() -> stateProgressBar.setProgress(progress));
282 | }
283 | }
284 |
--------------------------------------------------------------------------------