├── .github
├── FUNDING.yml
└── workflows
│ └── gradle.yml
├── .gitignore
├── .gitmodules
├── .idea
├── .gitignore
├── .name
├── compiler.xml
├── discord.xml
├── gradle.xml
├── jarRepositories.xml
└── misc.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── openblocks
│ │ └── android
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-playstore.png
│ ├── java
│ │ └── com
│ │ │ └── openblocks
│ │ │ └── android
│ │ │ ├── AboutActivity.java
│ │ │ ├── MainActivity.java
│ │ │ ├── ModuleConfigActivity.java
│ │ │ ├── ProjectEditorActivity.java
│ │ │ ├── README.md
│ │ │ ├── SettingsActivity.java
│ │ │ ├── adapters
│ │ │ ├── ConfigRecyclerViewAdapter.java
│ │ │ ├── ModulesRecyclerViewAdapter.java
│ │ │ └── ProjectRecyclerViewAdapter.java
│ │ │ ├── constants
│ │ │ └── IncludedBinaries.java
│ │ │ ├── dialog
│ │ │ ├── NewProjectDialog.java
│ │ │ └── ProjectMetadataEditDialog.java
│ │ │ ├── fragments
│ │ │ ├── main
│ │ │ │ ├── ModulesFragment.java
│ │ │ │ └── ProjectsFragment.java
│ │ │ └── projecteditor
│ │ │ │ ├── CodeEditFragment.java
│ │ │ │ ├── LayoutEditFragment.java
│ │ │ │ └── LogFragment.java
│ │ │ ├── helpers
│ │ │ ├── BlockCollectionParser.java
│ │ │ └── FileHelper.java
│ │ │ └── modman
│ │ │ ├── ModuleJsonCorruptedException.java
│ │ │ ├── ModuleLoader.java
│ │ │ ├── ModuleLogger.java
│ │ │ ├── ModuleManager.java
│ │ │ └── models
│ │ │ └── Module.java
│ └── res
│ │ ├── drawable-anydpi-v24
│ │ ├── ic_about.xml
│ │ ├── ic_add_white.xml
│ │ ├── ic_discord.xml
│ │ ├── ic_home.xml
│ │ ├── ic_settings.xml
│ │ └── ic_website.xml
│ │ ├── drawable-hdpi
│ │ ├── ic_about.png
│ │ ├── ic_add_white.png
│ │ ├── ic_discord.png
│ │ ├── ic_github.png
│ │ ├── ic_home.png
│ │ ├── ic_settings.png
│ │ └── ic_website.png
│ │ ├── drawable-mdpi
│ │ ├── ic_about.png
│ │ ├── ic_add_white.png
│ │ ├── ic_discord.png
│ │ ├── ic_github.png
│ │ ├── ic_home.png
│ │ ├── ic_settings.png
│ │ └── ic_website.png
│ │ ├── drawable-xhdpi
│ │ ├── ic_about.png
│ │ ├── ic_add_white.png
│ │ ├── ic_discord.png
│ │ ├── ic_github.png
│ │ ├── ic_home.png
│ │ ├── ic_settings.png
│ │ └── ic_website.png
│ │ ├── drawable-xxhdpi
│ │ ├── ic_about.png
│ │ ├── ic_add_white.png
│ │ ├── ic_discord.png
│ │ ├── ic_github.png
│ │ ├── ic_home.png
│ │ ├── ic_settings.png
│ │ └── ic_website.png
│ │ ├── drawable-xxxhdpi
│ │ ├── ic_discord.png
│ │ └── ic_github.png
│ │ ├── drawable
│ │ ├── bg_module_item.xml
│ │ ├── bg_module_item_ripple.xml
│ │ ├── ic_about.xml
│ │ ├── ic_add.xml
│ │ ├── ic_code.xml
│ │ ├── ic_compiler.xml
│ │ ├── ic_dashboard_black_24dp.xml
│ │ ├── ic_home_black_24dp.xml
│ │ ├── ic_import.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_layout.xml
│ │ ├── ic_notifications_black_24dp.xml
│ │ ├── ic_project_manager.xml
│ │ ├── ic_project_parser.xml
│ │ ├── ic_run.xml
│ │ └── ic_settings.xml
│ │ ├── layout
│ │ ├── _main_drawer_header.xml
│ │ ├── activity_about.xml
│ │ ├── activity_main.xml
│ │ ├── activity_module_config.xml
│ │ ├── activity_project_editor.xml
│ │ ├── dialog_edit_project_metadata.xml
│ │ ├── fragment_code_edit.xml
│ │ ├── fragment_layout_edit.xml
│ │ ├── fragment_log.xml
│ │ ├── fragment_modules.xml
│ │ ├── fragment_projects.xml
│ │ ├── nav_header_main.xml
│ │ ├── rv_config_item.xml
│ │ ├── rv_module_item.xml
│ │ ├── rv_project_item.xml
│ │ └── settings_activity.xml
│ │ ├── menu
│ │ ├── _main_drawer_menu.xml
│ │ └── activity_main_drawer.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_background.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_background.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_background.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_background.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_background.png
│ │ └── ic_launcher_round.png
│ │ ├── values-night
│ │ ├── colors.xml
│ │ └── styles.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ │ └── xml
│ │ └── root_preferences.xml
│ └── test
│ └── java
│ └── com
│ └── openblocks
│ └── android
│ └── ExampleUnitTest.java
├── build.gradle
├── copy_binaries.bat
├── copy_binaries.sh
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: OpenBlocks
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.github/workflows/gradle.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Gradle
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
3 |
4 | name: Java CI with Gradle
5 |
6 | on:
7 | push:
8 | branches: [ main ]
9 | pull_request:
10 | branches: [ main, dev ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Update and init submodules
20 | run: git submodule update --init
21 | - name: Set up JDK 1.8
22 | uses: actions/setup-java@v1
23 | with:
24 | java-version: 1.8
25 | - name: Grant execute permission for gradlew
26 | run: chmod +x gradlew
27 | - name: Build with Gradle
28 | run: ./gradlew build
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.aar
4 | *.ap_
5 | *.aab
6 |
7 | # Files for the ART/Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 | out/
17 | # Uncomment the following line in case you need and you don't have the release build type files in your app
18 | # release/
19 |
20 | # Gradle files
21 | .gradle/
22 | build/
23 |
24 | # Local configuration file (sdk path, etc)
25 | local.properties
26 |
27 | # Proguard folder generated by Eclipse
28 | proguard/
29 |
30 | # Log Files
31 | *.log
32 |
33 | # Android Studio Navigation editor temp files
34 | .navigation/
35 |
36 | # Android Studio captures folder
37 | captures/
38 |
39 | # IntelliJ
40 | *.iml
41 | .idea/workspace.xml
42 | .idea/tasks.xml
43 | .idea/gradle.xml
44 | .idea/assetWizardSettings.xml
45 | .idea/dictionaries
46 | .idea/libraries
47 | # Android Studio 3 in .gitignore file.
48 | .idea/caches
49 | .idea/modules.xml
50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
51 | .idea/navEditor.xml
52 |
53 | # Keystore files
54 | # Uncomment the following lines if you do not want to check your keystore files in.
55 | #*.jks
56 | #*.keystore
57 |
58 | # External native build folder generated in Android Studio 2.2 and later
59 | .externalNativeBuild
60 | .cxx/
61 |
62 | # Google Services (e.g. APIs or Firebase)
63 | # google-services.json
64 |
65 | # Freeline
66 | freeline.py
67 | freeline/
68 | freeline_project_description.json
69 |
70 | # fastlane
71 | fastlane/report.xml
72 | fastlane/Preview.html
73 | fastlane/screenshots
74 | fastlane/test_output
75 | fastlane/readme.md
76 |
77 | # Version control
78 | .idea/vcs.xml
79 |
80 | # lint
81 | lint/intermediates/
82 | lint/generated/
83 | lint/outputs/
84 | lint/tmp/
85 | # lint/reports/
86 |
87 | # Ignore the binaries
88 | app/src/main/jniLibs/**/
89 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "openblocks-module-interface"]
2 | path = openblocks-module-interface
3 | url = https://github.com/OpenBlocksTeam/openblocks-module-interface
4 | [submodule "android-build-tools"]
5 | path = android-build-tools
6 | url = https://github.com/OpenBlocksTeam/android-build-tools
7 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | OpenBlocks
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/discord.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.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 |
--------------------------------------------------------------------------------
/.idea/misc.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 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2021 OpenBlocks
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | OpenBlocks
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | An open source, modular alternative of sketchware. Create your own app in android using block programming like scratch!
21 |
22 | ## What is OpenBlocks?
23 | OpenBlocks is a community-driven modular android application that can create android apps using block programming like scratch. Every component for OpenBlocks is modular, these modules can be loaded and unloaded at runtime, giving users freedom on what they want to do with this app. Create customizable blocks, Custom widgets, Custom manager, Custom project type, Custom everything, Anything you want with it!
24 |
25 | #### For Sketchware users...
26 | OpenBlocks is basically an app that you can mod easily! It's open source, change what you want, contribute what you want, use what you want! It's also modular, meaning you can create modules to do something else, For example, I want to add a TextInputLayout to my Layout editor, just download an already-existing module that adds TextInputLayout to the layout editor, and boom! That's it, No need to mod sketchware. And if you want to create a module, we have already made an interface for that, check out [openblocks-module-interface](https://github.com/OpenBlocksTeam/openblocks-module-interface), the guide is also there, check out it's [wiki page](https://github.com/OpenBlocksTeam/openblocks-module-communicator/wiki/Initial-Idea).
27 |
28 | Happy Coding!
29 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'androidx.navigation.safeargs'
4 | }
5 |
6 | android {
7 |
8 | splits {
9 | abi {
10 | enable true
11 | reset()
12 | include 'armeabi-v7a', 'arm64-v8a', 'x86_64', 'x86'
13 | universalApk true
14 | }
15 | }
16 |
17 | compileSdkVersion 30
18 | buildToolsVersion "30.0.3"
19 |
20 | defaultConfig {
21 | applicationId "com.openblocks.android"
22 | minSdkVersion 21
23 | targetSdkVersion 30
24 | versionCode 1
25 | versionName "0.1-alpha"
26 |
27 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
28 | }
29 |
30 | buildFeatures {
31 | viewBinding true
32 | }
33 |
34 | buildTypes {
35 | release {
36 | minifyEnabled false
37 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
38 | }
39 | }
40 |
41 | compileOptions {
42 | sourceCompatibility JavaVersion.VERSION_1_8
43 | targetCompatibility JavaVersion.VERSION_1_8
44 | }
45 | }
46 |
47 | dependencies {
48 |
49 | implementation project(":module-interface")
50 |
51 | implementation 'androidx.appcompat:appcompat:1.2.0'
52 | implementation 'com.google.android.material:material:1.3.0'
53 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
54 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
55 | implementation 'androidx.navigation:navigation-fragment:2.3.4'
56 | implementation 'androidx.navigation:navigation-ui:2.3.4'
57 | implementation 'androidx.preference:preference:1.1.1'
58 |
59 | testImplementation 'junit:junit:4.13.2'
60 |
61 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
62 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
63 | }
64 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/openblocks/android/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("com.openblocks.android", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
16 |
17 |
18 |
19 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/AboutActivity.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android;
2 |
3 | import androidx.appcompat.app.AppCompatActivity;
4 | import androidx.appcompat.widget.Toolbar;
5 |
6 | import android.os.Bundle;
7 |
8 | import com.openblocks.android.databinding.ActivityAboutBinding;
9 |
10 | public class AboutActivity extends AppCompatActivity {
11 |
12 | private ActivityAboutBinding _binding;
13 | private Toolbar _toolBar;
14 |
15 | @Override
16 | protected void onCreate(Bundle savedInstanceState) {
17 | super.onCreate(savedInstanceState);
18 | _binding = ActivityAboutBinding.inflate(getLayoutInflater());
19 | setContentView(_binding.getRoot());
20 |
21 | _toolBar = _binding.toolbarAbout;
22 | setSupportActionBar(_toolBar);
23 |
24 | if (getSupportActionBar() != null) {
25 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
26 | getSupportActionBar().setHomeButtonEnabled(true);
27 | _toolBar.setNavigationOnClickListener(v -> onBackPressed());
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.content.SharedPreferences;
6 | import android.net.Uri;
7 | import android.os.Build;
8 | import android.os.Bundle;
9 | import android.util.Log;
10 | import android.view.MenuItem;
11 | import android.view.View;
12 | import android.widget.Toast;
13 |
14 | import androidx.annotation.NonNull;
15 | import androidx.annotation.Nullable;
16 | import androidx.appcompat.app.ActionBarDrawerToggle;
17 | import androidx.appcompat.app.AppCompatActivity;
18 | import androidx.appcompat.widget.Toolbar;
19 | import androidx.core.view.GravityCompat;
20 | import androidx.drawerlayout.widget.DrawerLayout;
21 | import androidx.fragment.app.Fragment;
22 | import androidx.fragment.app.FragmentManager;
23 | import androidx.fragment.app.FragmentStatePagerAdapter;
24 | import androidx.viewpager.widget.ViewPager;
25 |
26 | import com.google.android.material.floatingactionbutton.FloatingActionButton;
27 | import com.google.android.material.navigation.NavigationView;
28 | import com.google.android.material.tabs.TabLayout;
29 | import com.openblocks.android.databinding.ActivityMainBinding;
30 | import com.openblocks.android.fragments.main.ModulesFragment;
31 | import com.openblocks.android.fragments.main.ProjectsFragment;
32 | import com.openblocks.android.helpers.FileHelper;
33 | import com.openblocks.android.modman.ModuleJsonCorruptedException;
34 | import com.openblocks.android.modman.ModuleLoader;
35 | import com.openblocks.android.modman.ModuleLogger;
36 | import com.openblocks.android.modman.ModuleManager;
37 | import com.openblocks.android.modman.models.Module;
38 | import com.openblocks.android.dialog.NewProjectDialog;
39 | import com.openblocks.moduleinterface.OpenBlocksModule;
40 | import com.openblocks.moduleinterface.exceptions.ParseException;
41 | import com.openblocks.moduleinterface.models.OpenBlocksProjectMetadata;
42 | import com.openblocks.moduleinterface.models.OpenBlocksRawProject;
43 | import com.openblocks.moduleinterface.projectfiles.OpenBlocksCode;
44 | import com.openblocks.moduleinterface.projectfiles.OpenBlocksLayout;
45 |
46 | import org.json.JSONException;
47 |
48 | import java.io.File;
49 | import java.io.FileInputStream;
50 | import java.io.IOException;
51 | import java.util.ArrayList;
52 | import java.util.HashMap;
53 |
54 | public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
55 |
56 | private static final String TAG = "MainActivity";
57 |
58 | final int EDIT_METADATA_REQUEST_CODE = 2;
59 | final int IMPORT_MODULE_REQUEST_CODE = 1;
60 |
61 | // Used to list, get and read project
62 | OpenBlocksModule.ProjectManager project_manager;
63 | OpenBlocksModule.ProjectParser project_parser;
64 |
65 | // Used to initialize / create a new project
66 | OpenBlocksModule.BlocksCollection blocks_collection;
67 | OpenBlocksModule.ProjectLayoutGUI layout_editor;
68 |
69 | // List of existing project ids
70 | ArrayList project_ids;
71 |
72 | private ActivityMainBinding binding;
73 |
74 | private DrawerLayout _drawer;
75 |
76 | private FloatingActionButton fabProjects;
77 | private FloatingActionButton fabModules;
78 |
79 | private HashMap> modules;
80 |
81 | private ModuleLogger logger;
82 |
83 | @Override
84 | protected void onCreate(Bundle savedInstanceState) {
85 | super.onCreate(savedInstanceState);
86 | binding = ActivityMainBinding.inflate(getLayoutInflater());
87 | setContentView(binding.getRoot());
88 |
89 | // Main Part (ActionBar)
90 | Toolbar _actionBar = binding.toolBar;
91 | setSupportActionBar(_actionBar);
92 |
93 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
94 | getSupportActionBar().setHomeButtonEnabled(true);
95 |
96 | // Drawer Toggle & Drawer
97 | _drawer = binding.drawerLayout;
98 | NavigationView _drawer_navView = binding.navView;
99 |
100 | ActionBarDrawerToggle _toggle = new ActionBarDrawerToggle(MainActivity.this, _drawer, _actionBar, R.string.app_name, R.string.app_name);
101 | _drawer.addDrawerListener(_toggle);
102 | _toggle.syncState();
103 |
104 | _drawer_navView.setNavigationItemSelectedListener(this);
105 |
106 | // Load Modules ============================================================================
107 |
108 | // Get the SharedPreferences
109 | SharedPreferences sp = getSharedPreferences("data", MODE_PRIVATE);
110 |
111 | // Check if this is the first time the user has opened this app
112 | if (sp.getBoolean("first_time", true)) {
113 |
114 | // Oo, first time huh, let's initialize the modules folder, and extract our default modules there
115 | try {
116 | // Initialize the modules folder
117 | File modules_folder = new File(getFilesDir(), "/modules/");
118 |
119 | if (!modules_folder.mkdir()) {
120 | Log.w(TAG, "onCreate: modules folder already exists on init, continuing anyway");
121 | }
122 |
123 | // Initialize the modules.json file
124 | File modulesjson = new File(modules_folder, "modules.json");
125 |
126 | if (!modulesjson.createNewFile()) {
127 | Log.w(TAG, "onCreate: modules.json already exists on first time, continuing anyway");
128 | }
129 |
130 | FileHelper.writeFile(modulesjson, "{\"modules\":{}, \"active_modules\":{}}".getBytes());
131 |
132 | // TODO: EXTRACT / DOWNLOAD DEFAULT MODULES
133 |
134 | sp.edit().putBoolean("first_time", false).apply();
135 | } catch (IOException e) {
136 | Toast.makeText(this, "Error while initializing modules: " + e.getMessage(), Toast.LENGTH_LONG).show();
137 | e.printStackTrace();
138 | finish();
139 | }
140 | }
141 |
142 | // TODO: SHOW A LOADING BAR / SCREEN WHEN WE'RE LOADING MODULES
143 | ModuleManager moduleManager = ModuleManager.getInstance();
144 |
145 | // Load modules
146 | try {
147 | moduleManager.fetchAllModules(this);
148 |
149 | } catch (IOException e) {
150 | e.printStackTrace();
151 |
152 | Toast.makeText(this, "Error while reading modules: " + e.getMessage(), Toast.LENGTH_LONG).show();
153 | } catch (ModuleJsonCorruptedException e) {
154 | e.printStackTrace();
155 |
156 | Toast.makeText(this, "modules.json is corrupted: " + e.getMessage(), Toast.LENGTH_LONG).show();
157 | }
158 |
159 | modules = moduleManager.getModules();
160 |
161 | // Load Modules ============================================================================
162 |
163 | // Load Projects ===========================================================================
164 |
165 | logger = ModuleLogger.getInstance();
166 |
167 | Module project_manager_module = moduleManager.getActiveModule(OpenBlocksModule.Type.PROJECT_MANAGER);
168 | Module project_parser_module = moduleManager.getActiveModule(OpenBlocksModule.Type.PROJECT_PARSER);
169 | Module blocks_collection_module = moduleManager.getActiveModule(OpenBlocksModule.Type.BLOCKS_COLLECTION);
170 | Module layout_editor_module = moduleManager.getActiveModule(OpenBlocksModule.Type.PROJECT_LAYOUT_GUI);
171 |
172 | project_manager = ModuleLoader.load(this, project_manager_module, OpenBlocksModule.ProjectManager.class);
173 | project_parser = ModuleLoader.load(this, project_parser_module, OpenBlocksModule.ProjectParser.class);
174 | blocks_collection = ModuleLoader.load(this, blocks_collection_module, OpenBlocksModule.BlocksCollection.class);
175 | layout_editor = ModuleLoader.load(this, layout_editor_module, OpenBlocksModule.ProjectLayoutGUI.class);
176 |
177 | if (project_manager != null) project_manager.initialize(this, logger);
178 | if (project_parser != null) project_parser.initialize(this, logger);
179 | if (layout_editor != null) layout_editor.initialize(this, logger);
180 |
181 | ArrayList projects_metadata = new ArrayList<>();
182 |
183 | if (project_manager != null && project_parser != null) {
184 | // Only run these if the modules are successfully loaded
185 | ArrayList projects = project_manager.listProjects();
186 |
187 | for (OpenBlocksRawProject project : projects) {
188 | project_ids.add(project.ID);
189 |
190 | try {
191 | projects_metadata.add(project_parser.parseMetadata(project));
192 | } catch (ParseException e) {
193 | e.printStackTrace();
194 | logger.err(project_parser.getClass(), "");
195 | }
196 | }
197 | }
198 |
199 | // Load Projects ===========================================================================
200 |
201 | // View Pager
202 | ViewPager viewPager = binding.viewPager;
203 | TabLayout tabLayout = binding.tabLayout;
204 |
205 | viewPager.setAdapter(new FragmentAdapter(getApplicationContext(), getSupportFragmentManager(), 2, modules, projects_metadata));
206 | tabLayout.setupWithViewPager(viewPager);
207 |
208 | // FABs
209 | fabProjects = binding.fabProjects;
210 | fabModules = binding.fabModules;
211 |
212 | fabModules.hide();
213 |
214 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
215 | fabProjects.setTooltipText("New project");
216 | fabModules.setTooltipText("Add module");
217 | }
218 |
219 | // Listeners
220 | viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
221 | @Override
222 | public void onPageScrolled(int _position, float _positionOffset, int _positionOffsetPixels) {
223 |
224 | }
225 |
226 | @Override
227 | public void onPageSelected(int _position) {
228 | if (_position == 0) {
229 | fabProjects.show();
230 | fabModules.hide();
231 | } else {
232 | fabProjects.hide();
233 | fabModules.show();
234 | }
235 | }
236 |
237 | @Override
238 | public void onPageScrollStateChanged(int _scrollState) {
239 |
240 | }
241 | });
242 | }
243 |
244 | // When the user clicked the "New Project" button
245 | public void fabProjectsClicked(View view) {
246 | // Handle a not implemented Project parser
247 | if (project_parser == null) {
248 | Toast.makeText(this, "No Project parser module has been loaded yet.", Toast.LENGTH_SHORT).show();
249 | return;
250 | }
251 | // Show the "New project" dialog
252 | NewProjectDialog dialog = new NewProjectDialog(this, project_parser.generateFreeId(project_ids))
253 | .addOnMetadataSavedListener((appName, packageName, versionName, versionCode) -> {
254 | // User has clicked the "OK" button (and the data is valid), Create a new project
255 | OpenBlocksProjectMetadata metadata =
256 | new OpenBlocksProjectMetadata(
257 | appName,
258 | packageName,
259 | versionName,
260 | versionCode
261 | );
262 |
263 | String new_id = project_parser.generateFreeId(project_ids);
264 |
265 | // Initialize the project
266 | OpenBlocksCode initialized_code = blocks_collection.initializeNewCode();
267 |
268 | // Set the block collection name
269 | initialized_code.block_collection_name =
270 | ModuleManager
271 | .getInstance()
272 | .getActiveModule(OpenBlocksModule.Type.BLOCKS_COLLECTION).name;
273 |
274 | OpenBlocksLayout initialized_layout = layout_editor.initializeNewLayout();
275 | OpenBlocksRawProject new_project = project_parser.saveProject(metadata, initialized_code, initialized_layout);
276 |
277 | new_project.ID = new_id;
278 |
279 | // Save the project
280 | project_manager.saveProject(new_project);
281 | });
282 |
283 | dialog.show();
284 | }
285 |
286 | // When user clicked the "import" button
287 | public void fabModulesClicked(View view) {
288 | // Use SAF to pick a zip file, we ain't messing around with scoped storage
289 | Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT)
290 | .addCategory(Intent.CATEGORY_OPENABLE)
291 | .setType("application/zip");
292 |
293 | startActivityForResult(intent, IMPORT_MODULE_REQUEST_CODE);
294 | }
295 |
296 | @Override
297 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
298 | super.onActivityResult(requestCode, resultCode, data);
299 |
300 | if (resultCode == RESULT_CANCELED || data == null)
301 | return;
302 |
303 | if (requestCode == IMPORT_MODULE_REQUEST_CODE) {
304 | // Get the URI
305 | Uri uri = data.getData();
306 | ArrayList module;
307 |
308 | // Then import the module
309 | try {
310 | module = ModuleManager.getInstance().importModule(this,
311 | new FileInputStream(getContentResolver().openFileDescriptor(uri, "r").getFileDescriptor()));
312 | } catch (IOException e) {
313 | Toast.makeText(this, "Error while reading module: " + e.getMessage(), Toast.LENGTH_LONG).show();
314 |
315 | return;
316 | } catch (JSONException e) {
317 | Toast.makeText(this, "Module is corrupted: " + e.getMessage(), Toast.LENGTH_LONG).show();
318 |
319 | return;
320 | }
321 |
322 | StringBuilder module_string = new StringBuilder();
323 |
324 | for (Module module1 : module) {
325 | module_string.append(module1.name).append(" ");
326 | }
327 |
328 | Toast.makeText(this, "Module " + module_string + "has successfully imported, restarting activity", Toast.LENGTH_SHORT).show();
329 |
330 | // Ok then refresh our activity
331 | recreate();
332 | } else if (requestCode == EDIT_METADATA_REQUEST_CODE) {
333 | OpenBlocksProjectMetadata metadata =
334 | new OpenBlocksProjectMetadata(
335 | data.getStringExtra("app_name"),
336 | data.getStringExtra("package_name"),
337 | data.getStringExtra("version_name"),
338 | Integer.parseInt(data.getStringExtra("version_code"))
339 | );
340 |
341 | // Create a new project
342 | // TODO: Handle project_parser being null (for some reason)
343 | String new_id = project_parser.generateFreeId(project_ids);
344 |
345 | // Initialize the project
346 | OpenBlocksCode initialized_code = blocks_collection.initializeNewCode();
347 | OpenBlocksLayout initialized_layout = layout_editor.initializeNewLayout();
348 | OpenBlocksRawProject new_project = project_parser.saveProject(metadata, initialized_code, initialized_layout);
349 |
350 | // Save the project
351 | project_manager.saveProject(new_project);
352 |
353 | project_ids.add(new_id);
354 |
355 | // Then finally, open the project
356 | Intent i = new Intent(this, ProjectEditorActivity.class);
357 | i.putExtra("project_id", new_id);
358 | startActivity(i);
359 | }
360 | }
361 |
362 |
363 | @Override
364 | public void onBackPressed() {
365 | if (_drawer.isDrawerOpen(GravityCompat.START)) {
366 | _drawer.closeDrawer(GravityCompat.START);
367 | } else {
368 | super.onBackPressed();
369 | }
370 | }
371 |
372 | @Override
373 | public boolean onNavigationItemSelected(@NonNull MenuItem item) {
374 | Intent intent = new Intent();
375 |
376 | int itemId = item.getItemId();
377 |
378 | if (itemId == R.id.home) {
379 | _drawer.closeDrawer(GravityCompat.START);
380 | return false;
381 |
382 | } else if (itemId == R.id.settings) {
383 | intent.setClass(MainActivity.this, SettingsActivity.class);
384 |
385 | } else if (itemId == R.id.about) {
386 | intent.setClass(MainActivity.this, AboutActivity.class);
387 |
388 | } else if (itemId == R.id.dc) {
389 | intent.setAction(Intent.ACTION_VIEW);
390 | intent.setData(Uri.parse("https://discord.gg/ESCfUBy26Z"));
391 |
392 | } else if (itemId == R.id.gh) {
393 | intent.setAction(Intent.ACTION_VIEW);
394 | intent.setData(Uri.parse("https://github.com/OpenBlocksTeam"));
395 |
396 | } else if (itemId == R.id.web) {
397 | intent.setAction(Intent.ACTION_VIEW);
398 | intent.setData(Uri.parse("https://openblocks.tk/"));
399 | }
400 |
401 | startActivity(intent);
402 |
403 | return false;
404 | }
405 |
406 | public static class FragmentAdapter extends FragmentStatePagerAdapter {
407 | Context context;
408 | int tabCount;
409 |
410 | HashMap> modules;
411 | ArrayList projectMetadataArrayList;
412 |
413 | public FragmentAdapter(Context context, FragmentManager fm, int tabCount, HashMap> modules, ArrayList projectMetadataArrayList) {
414 | super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
415 | this.context = context;
416 | this.tabCount = tabCount;
417 | this.modules = modules;
418 | this.projectMetadataArrayList = projectMetadataArrayList;
419 | }
420 |
421 | @Override
422 | public int getCount() {
423 | return tabCount;
424 | }
425 |
426 | @Override
427 | public CharSequence getPageTitle(int _position) {
428 | switch (_position) {
429 | case 0:
430 | return "Projects";
431 | case 1:
432 | return "Modules";
433 | default:
434 | return null;
435 | }
436 | }
437 |
438 | @NonNull
439 | @Override
440 | public Fragment getItem(int _position) {
441 | switch (_position) {
442 | case 0:
443 | return ProjectsFragment.newInstance(projectMetadataArrayList);
444 | case 1:
445 | return ModulesFragment.newInstance(modules);
446 | default:
447 | return new Fragment();
448 | }
449 | }
450 | }
451 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/ModuleConfigActivity.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android;
2 |
3 | import androidx.annotation.NonNull;
4 | import androidx.annotation.Nullable;
5 | import androidx.appcompat.app.ActionBar;
6 | import androidx.appcompat.app.AppCompatActivity;
7 | import androidx.recyclerview.widget.LinearLayoutManager;
8 | import androidx.recyclerview.widget.RecyclerView;
9 |
10 | import android.content.Intent;
11 | import android.os.Bundle;
12 | import android.util.Log;
13 | import android.view.MenuItem;
14 | import android.widget.Toast;
15 |
16 | import com.openblocks.android.adapters.ConfigRecyclerViewAdapter;
17 | import com.openblocks.android.modman.ModuleManager;
18 | import com.openblocks.android.modman.models.Module;
19 | import com.openblocks.moduleinterface.OpenBlocksModule;
20 | import com.openblocks.moduleinterface.models.config.OpenBlocksConfig;
21 |
22 | import java.io.File;
23 | import java.lang.reflect.InvocationTargetException;
24 | import java.lang.reflect.Method;
25 | import java.util.Objects;
26 |
27 | import dalvik.system.DexClassLoader;
28 |
29 | /**
30 | * This activity is where the user can edit the module's (pre-defined by the module itself) configuration
31 | */
32 | public class ModuleConfigActivity extends AppCompatActivity {
33 |
34 | private static final String TAG = "ModuleConfigActivity";
35 |
36 | ConfigRecyclerViewAdapter adapter;
37 |
38 | @Override
39 | protected void onCreate(Bundle savedInstanceState) {
40 | super.onCreate(savedInstanceState);
41 | setContentView(R.layout.activity_module_config);
42 |
43 | // We need a back button
44 | Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
45 |
46 | // Get the module extra
47 | Module module = getIntent().getParcelableExtra("module");
48 |
49 | // Null check
50 | if (module == null) {
51 | Log.e(TAG, "onCreate: Module is null", null);
52 | finish();
53 |
54 | return;
55 | }
56 |
57 | File jarfile = module.jar_file;
58 | String classpath = module.classpath;
59 |
60 | // Now load the module
61 | try {
62 | // Get the jar file's path
63 | final String libPath = jarfile.getAbsolutePath();
64 |
65 | // Load it using DexClassLoader
66 | final DexClassLoader classloader = new DexClassLoader(libPath, getCodeCacheDir().getAbsolutePath(), null, this.getClass().getClassLoader());
67 | final Class module_class = (Class) classloader.loadClass(classpath);
68 |
69 | // Then get the setupConfig method (one of the functions in OpenBlocks Module Interface)
70 | final Method setupConfig = module_class.getMethod("setupConfig");
71 |
72 | // Invoke it
73 | OpenBlocksConfig config = (OpenBlocksConfig) setupConfig.invoke(module_class);
74 |
75 | // Then load it
76 | loadConfig(config);
77 |
78 | } catch (ClassNotFoundException e) {
79 | e.printStackTrace();
80 |
81 | Toast.makeText(this, "Error while loading config: Wrong classpath: " + classpath, Toast.LENGTH_LONG).show();
82 | } catch (IllegalAccessException e) {
83 | e.printStackTrace();
84 |
85 | Toast.makeText(this, "IllegalAccessException: " + e.getMessage(), Toast.LENGTH_LONG).show();
86 | } catch (NoSuchMethodException e) {
87 | e.printStackTrace();
88 |
89 | Toast.makeText(this, "Method not found: " + e.getMessage(), Toast.LENGTH_LONG).show();
90 | } catch (InvocationTargetException e) {
91 | e.printStackTrace();
92 |
93 | Toast.makeText(this, "InvocationTargetException: " + e.getMessage(), Toast.LENGTH_LONG).show();
94 | }
95 | }
96 |
97 | private void loadConfig(OpenBlocksConfig config) {
98 | // This is where we will display the config to the recyclerview, simple
99 | // Get the recyclerview
100 | RecyclerView rv = findViewById(R.id.module_config);
101 | rv.setLayoutManager(new LinearLayoutManager(this));
102 |
103 | // And apply the adapter, done
104 | adapter = new ConfigRecyclerViewAdapter(config, this);
105 | rv.setAdapter(adapter);
106 | }
107 |
108 | @Override
109 | public boolean onOptionsItemSelected(@NonNull MenuItem item) {
110 | int id = item.getItemId();
111 |
112 | // Did the user clicked the back button?
113 | if (id == android.R.id.home) {
114 | onBackPressed();
115 | }
116 |
117 | return super.onOptionsItemSelected(item);
118 | }
119 |
120 | @Override
121 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
122 | super.onActivityResult(requestCode, resultCode, data);
123 |
124 | if (data == null)
125 | return;
126 |
127 | adapter.onResult(requestCode, data);
128 | }
129 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/ProjectEditorActivity.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android;
2 |
3 | import android.os.Bundle;
4 | import android.os.Environment;
5 | import android.util.Pair;
6 | import android.widget.Toast;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.appcompat.app.AlertDialog;
10 | import androidx.appcompat.app.AppCompatActivity;
11 | import androidx.appcompat.widget.Toolbar;
12 | import androidx.fragment.app.Fragment;
13 | import androidx.fragment.app.FragmentManager;
14 | import androidx.fragment.app.FragmentPagerAdapter;
15 | import androidx.viewpager.widget.ViewPager;
16 |
17 | import com.google.android.material.floatingactionbutton.FloatingActionButton;
18 | import com.google.android.material.tabs.TabLayout;
19 | import com.openblocks.android.constants.IncludedBinaries;
20 | import com.openblocks.android.fragments.projecteditor.CodeEditFragment;
21 | import com.openblocks.android.fragments.projecteditor.LayoutEditFragment;
22 | import com.openblocks.android.fragments.projecteditor.LogFragment;
23 | import com.openblocks.android.helpers.BlockCollectionParser;
24 | import com.openblocks.android.modman.ModuleLoader;
25 | import com.openblocks.android.modman.ModuleLogger;
26 | import com.openblocks.android.modman.ModuleManager;
27 | import com.openblocks.android.modman.models.Module;
28 | import com.openblocks.moduleinterface.OpenBlocksModule;
29 | import com.openblocks.moduleinterface.callbacks.SaveCallback;
30 | import com.openblocks.moduleinterface.exceptions.CompileException;
31 | import com.openblocks.moduleinterface.exceptions.ParseException;
32 | import com.openblocks.moduleinterface.models.OpenBlocksProjectMetadata;
33 | import com.openblocks.moduleinterface.models.OpenBlocksRawProject;
34 | import com.openblocks.moduleinterface.models.code.ParseBlockTask;
35 | import com.openblocks.moduleinterface.models.compiler.IncludedBinary;
36 | import com.openblocks.moduleinterface.projectfiles.OpenBlocksCode;
37 | import com.openblocks.moduleinterface.projectfiles.OpenBlocksLayout;
38 |
39 | import java.util.ArrayList;
40 | import java.util.Arrays;
41 | import java.util.HashMap;
42 |
43 | public class ProjectEditorActivity extends AppCompatActivity {
44 |
45 | ModuleManager moduleManager = ModuleManager.getInstance();
46 |
47 | OpenBlocksCode code;
48 | OpenBlocksLayout layout;
49 | OpenBlocksProjectMetadata metadata;
50 |
51 | ModuleLogger logger = ModuleLogger.getInstance();
52 |
53 | @Override
54 | protected void onCreate(Bundle savedInstanceState) {
55 | super.onCreate(savedInstanceState);
56 | setContentView(R.layout.activity_project_editor);
57 |
58 | // TODO: 3/10/21 Run these on an another thread / asynchronously, Project Parser might take some time to parse the project
59 |
60 | // Read the project
61 | String project_id = getIntent().getStringExtra("project_id");
62 |
63 | // Get project manager and project parser
64 | Module project_manager = moduleManager.getActiveModule(OpenBlocksModule.Type.PROJECT_MANAGER);
65 | Module project_parser = moduleManager.getActiveModule(OpenBlocksModule.Type.PROJECT_PARSER);
66 | OpenBlocksModule.ProjectManager project_manager_instance = ModuleLoader.load(this, project_manager, OpenBlocksModule.ProjectManager.class);
67 | OpenBlocksModule.ProjectParser project_parser_instance = ModuleLoader.load(this, project_parser, OpenBlocksModule.ProjectParser.class);
68 |
69 | // Initialize these modules
70 | project_manager_instance.initialize(this, logger);
71 | project_parser_instance.initialize(this, logger);
72 |
73 | // Get the project
74 | OpenBlocksRawProject project = project_manager_instance.getProject(project_id);
75 |
76 | // Parse it
77 | try {
78 | code = project_parser_instance.parseCode(project);
79 | layout = project_parser_instance.parseLayout(project);
80 | metadata = project_parser_instance.parseMetadata(project);
81 | } catch (ParseException e) {
82 | Toast.makeText(this, "Error while parsing project: " + e.getMessage(), Toast.LENGTH_LONG).show();
83 |
84 | return;
85 | }
86 |
87 | // After parsing the code, get the module that is used in the code
88 | Module blocks_collection_module = moduleManager.findModule(OpenBlocksModule.Type.BLOCKS_COLLECTION, code.block_collection_name);
89 |
90 | // Check if the blocks collection exists
91 | if (blocks_collection_module == null) {
92 | // Nope, there is no blocks collection with this name
93 | AlertDialog.Builder builder = new AlertDialog.Builder(this);
94 | builder.setTitle("Error finding blocks collection");
95 | builder.setMessage("Blocks Collection with name " + code.block_collection_name + " not found, please find the module and install it to edit this project.");
96 | builder.create().show();
97 |
98 | finish();
99 | }
100 |
101 | // Create some save callbacks
102 | SaveCallback code_save = code_new -> {
103 | code = code_new;
104 |
105 | // TODO: 3/10/21 Run this asynchronously
106 |
107 | // Save the code using project parser and manager
108 | project_manager_instance.saveProject(
109 | project_parser_instance.saveProject(
110 | metadata,
111 | code_new,
112 | layout
113 | )
114 | );
115 |
116 | Toast.makeText(this, "Code saved!", Toast.LENGTH_SHORT).show();
117 | };
118 |
119 | SaveCallback layout_save = layout_new -> {
120 | layout = layout_new;
121 |
122 | // TODO: 3/10/21 Run this asynchronously
123 |
124 | // Save the layout using project parser and manager
125 | project_manager_instance.saveProject(
126 | project_parser_instance.saveProject(
127 | metadata,
128 | code,
129 | layout_new
130 | )
131 | );
132 |
133 | Toast.makeText(this, "Layout saved!", Toast.LENGTH_SHORT).show();
134 | };
135 |
136 | // And bind UI elements I guess
137 | Toolbar toolbar = findViewById(R.id.project_editor_toolbar);
138 | setSupportActionBar(toolbar);
139 |
140 | Module compiler_module = moduleManager.getActiveModule(OpenBlocksModule.Type.PROJECT_COMPILER);
141 |
142 | OpenBlocksModule.BlocksCollection blocks_collection = ModuleLoader.load(this, blocks_collection_module, OpenBlocksModule.BlocksCollection.class);
143 | OpenBlocksModule.ProjectCompiler compiler = ModuleLoader.load(this, compiler_module, OpenBlocksModule.ProjectCompiler.class);
144 |
145 | IncludedBinaries.init(this);
146 |
147 | HashMap> blocks = BlockCollectionParser.parseBlocks(blocks_collection.getBlocks());
148 |
149 | // Initialize the compiler
150 | compiler.initializeCompiler(
151 | (ArrayList) Arrays.asList(IncludedBinaries.INCLUDED_BINARIES),
152 | convertParsedBlocks(blocks)
153 | );
154 |
155 | // Don't forget to set the blocks format for our code editor
156 | code.setBlocksFormats(convertParsedBlocks2(blocks));
157 |
158 | FloatingActionButton run_fab = findViewById(R.id.project_editor_run);
159 |
160 | String apk_output_path = getSharedPreferences("data", MODE_PRIVATE).getString("apk_output_path", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath());
161 | run_fab.setOnClickListener(view -> {
162 | try {
163 | compiler.compile(metadata, code, layout, apk_output_path);
164 | } catch (CompileException e) {
165 | e.printStackTrace();
166 | AlertDialog.Builder builder = new AlertDialog.Builder(ProjectEditorActivity.this);
167 | builder.setTitle("An error occurred while compiling");
168 | builder.setMessage("The compiler module (" + compiler_module.name + ") said:\n" + e.message);
169 | builder.create().show();
170 | }
171 | });
172 |
173 | ViewPager viewPager = findViewById(R.id.viewPager);
174 |
175 | ProjectEditorViewPagerAdapter viewPagerAdapter = new ProjectEditorViewPagerAdapter(getSupportFragmentManager(), code, layout, code_save, layout_save);
176 | viewPager.setAdapter(viewPagerAdapter);
177 |
178 | TabLayout tabLayout = findViewById(R.id.tabs);
179 | tabLayout.setupWithViewPager(viewPager);
180 | }
181 |
182 | /**
183 | * This function is used to convert the blocks list generated by
184 | * {@link BlockCollectionParser#parseBlocks(Object[])} into HashMap<\String, ParseBlockTask>
185 | * @param blocks The blocks generated from {@link BlockCollectionParser#parseBlocks(Object[])}
186 | * @return The parsed collection
187 | */
188 | private HashMap convertParsedBlocks(HashMap> blocks) {
189 | HashMap result = new HashMap<>();
190 |
191 | for (String key : blocks.keySet()) {
192 | result.put(key, blocks.get(key).second);
193 | }
194 |
195 | return result;
196 | }
197 |
198 | /**
199 | * This function is used to convert the blocks list generated by
200 | * {@link BlockCollectionParser#parseBlocks(Object[])} into HashMap<\String, String>
201 | * @param blocks The blocks generated from {@link BlockCollectionParser#parseBlocks(Object[])}
202 | * @return The parsed collection
203 | */
204 | private HashMap convertParsedBlocks2(HashMap> blocks) {
205 | HashMap result = new HashMap<>();
206 |
207 | for (String key : blocks.keySet()) {
208 | result.put(key, blocks.get(key).first);
209 | }
210 |
211 | return result;
212 | }
213 |
214 | public static class ProjectEditorViewPagerAdapter extends FragmentPagerAdapter {
215 |
216 | // TODO LOW_PRIORITY: 3/10/21 mvvm
217 |
218 | OpenBlocksCode code;
219 | OpenBlocksLayout layout;
220 |
221 | SaveCallback code_save;
222 | SaveCallback layout_save;
223 |
224 | public ProjectEditorViewPagerAdapter(
225 | FragmentManager fm, OpenBlocksCode code, OpenBlocksLayout layout,
226 | SaveCallback code_save, SaveCallback layout_save) {
227 | super(fm);
228 | this.code = code;
229 | this.layout = layout;
230 | this.code_save = code_save;
231 | this.layout_save = layout_save;
232 | }
233 |
234 | @Override
235 | public int getCount(){
236 | return 3;
237 | }
238 |
239 | @Override
240 | public CharSequence getPageTitle(int _position) {
241 | switch (_position) {
242 | case 0:
243 | return "Layout";
244 | case 1:
245 | return "Code";
246 | case 2:
247 | return "Components";
248 | default:
249 | return null;
250 | }
251 | }
252 |
253 | @NonNull
254 | @Override
255 | public Fragment getItem(int _position) {
256 | switch (_position) {
257 | case 0:
258 | return new LayoutEditFragment(layout, code, layout_save);
259 | case 1:
260 | return new CodeEditFragment(code, layout, code_save);
261 | case 2:
262 | return new LogFragment();
263 | default:
264 | return new Fragment();
265 | }
266 | }
267 | }
268 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/README.md:
--------------------------------------------------------------------------------
1 | ## Welcome to the source code!
2 | Here are some folders you should know:
3 | - `adapters` Is the folder where the adapters are located (Example: RecyclerViewAdapter, etc)
4 | - `constants` Is the folder where constants are located (Example: IncludedBinaries, etc)
5 | - `dialog` Is the folder where dialogs are located (Example: NewProjectDialog, etc)
6 | - `fragments` Is the folder where the fragments are located (Example: CodeEditFragment, etc)
7 | - `helpers` Is the folder where the helper classes are located, these helpers are, well, to help us (make the code a bit prettier, and simpler)
8 | - `modman` Is the folder where the module manager is located (**MOD**ule **MAN**ager). `ModuleManager.java` Is the class that is used to access, import, and remove modules.
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android;
2 |
3 | import android.os.Bundle;
4 | import android.widget.Toolbar;
5 |
6 | import androidx.appcompat.app.ActionBar;
7 | import androidx.appcompat.app.AppCompatActivity;
8 | import androidx.preference.PreferenceFragmentCompat;
9 |
10 | public class SettingsActivity extends AppCompatActivity {
11 |
12 | @Override
13 | protected void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | setContentView(R.layout.settings_activity);
16 | if (savedInstanceState == null) {
17 | getSupportFragmentManager()
18 | .beginTransaction()
19 | .replace(R.id.settings, new SettingsFragment())
20 | .commit();
21 | }
22 |
23 | ActionBar actionBar = getSupportActionBar();
24 | if (actionBar != null) {
25 | actionBar.setDisplayHomeAsUpEnabled(true);
26 | }
27 | }
28 |
29 | public static class SettingsFragment extends PreferenceFragmentCompat {
30 | @Override
31 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
32 | setPreferencesFromResource(R.xml.root_preferences, rootKey);
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/adapters/ConfigRecyclerViewAdapter.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.adapters;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.DialogInterface;
6 | import android.content.Intent;
7 | import android.text.Editable;
8 | import android.text.InputType;
9 | import android.text.TextWatcher;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.AdapterView;
14 | import android.widget.ArrayAdapter;
15 | import android.widget.Button;
16 | import android.widget.CompoundButton;
17 | import android.widget.EditText;
18 | import android.widget.FrameLayout;
19 | import android.widget.Spinner;
20 | import android.widget.Switch;
21 | import android.widget.TextView;
22 |
23 | import androidx.annotation.NonNull;
24 | import androidx.appcompat.app.AlertDialog;
25 | import androidx.appcompat.widget.SwitchCompat;
26 | import androidx.recyclerview.widget.RecyclerView;
27 |
28 | import com.google.android.material.button.MaterialButton;
29 | import com.openblocks.android.ModuleConfigActivity;
30 | import com.openblocks.android.R;
31 | import com.openblocks.moduleinterface.models.config.OpenBlocksConfig;
32 | import com.openblocks.moduleinterface.models.config.OpenBlocksConfigItem;
33 |
34 | import java.lang.ref.WeakReference;
35 | import java.util.ArrayList;
36 | import java.util.HashMap;
37 |
38 | public class ConfigRecyclerViewAdapter extends RecyclerView.Adapter {
39 |
40 | OpenBlocksConfig config;
41 |
42 | // Why WeakReference? Because setting this as plain activity can cause memory leaks, the java
43 | // garbage collector doesn't collect variables that have strong reference
44 | WeakReference activity;
45 |
46 | // TAG: VALUE
47 | HashMap saved_items = new HashMap<>();
48 |
49 | public ConfigRecyclerViewAdapter(OpenBlocksConfig configItems, Activity activity) {
50 | this.config = configItems;
51 | this.activity = new WeakReference<>(activity);
52 | }
53 |
54 | @NonNull
55 | @Override
56 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
57 | return new ViewHolder(
58 | LayoutInflater
59 | .from(parent.getContext())
60 | .inflate(R.layout.rv_module_item, parent, false)
61 | );
62 | }
63 |
64 | public OpenBlocksConfig getConfig() {
65 | for (String tag: saved_items.keySet()) {
66 | config.setConfigValue(tag, saved_items.get(tag));
67 | }
68 |
69 | return config;
70 | }
71 |
72 | public void onResult(int requestCode, Intent data) {
73 | // Set the value as the path
74 | saved_items.put(config.getTAGs()[requestCode], data.getData().getPath());
75 | }
76 |
77 | @Override
78 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
79 | OpenBlocksConfigItem item = config.getConfigs().get(position);
80 | String[] tags = config.getTAGs();
81 |
82 | Context context = holder.title.getContext();
83 | View input = null;
84 |
85 | holder.title.setText(item.text);
86 |
87 | switch (item.config_type) {
88 | case SWITCH:
89 | SwitchCompat switch_ = new SwitchCompat(context);
90 | switch_.setShowText(false);
91 | switch_.setChecked((Boolean) item.value);
92 |
93 | switch_.setOnCheckedChangeListener((buttonView, isChecked) -> {
94 | saved_items.put(tags[position], isChecked);
95 | });
96 |
97 | input = switch_;
98 | break;
99 |
100 | case DROPDOWN:
101 | Spinner spinner = new Spinner(context);
102 | spinner.setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_spinner_dropdown_item, (ArrayList) item.extra));
103 |
104 | spinner.setOnItemClickListener((parent, view, position1, id) ->
105 | saved_items.put(
106 | tags[position],
107 | ((String[]) item.extra)[position1]
108 | )
109 | );
110 |
111 | input = spinner;
112 | break;
113 |
114 | case OPEN_FILE:
115 | MaterialButton button = new MaterialButton(context);
116 | button.setText("Open File");
117 |
118 | button.setOnClickListener(v -> {
119 | Intent i = new Intent();
120 | i .setAction(Intent.ACTION_OPEN_DOCUMENT)
121 | .addCategory(Intent.CATEGORY_OPENABLE);
122 |
123 | activity.get().startActivityForResult(i, position); // Use the position as the request code
124 | });
125 |
126 | input = button;
127 | break;
128 |
129 | case INPUT_TEXT:
130 | EditText editText = new EditText(context);
131 | editText.setText((String) item.value);
132 | editText.setHint("Input here");
133 |
134 | editText.addTextChangedListener(new TextWatcher() {
135 | @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
136 | @Override public void afterTextChanged(Editable s) { }
137 |
138 | @Override
139 | public void onTextChanged(CharSequence s, int start, int before, int count) {
140 | saved_items.put(tags[position], s.toString());
141 | }
142 | });
143 |
144 | input = editText;
145 | break;
146 |
147 | case INPUT_NUMBER:
148 | EditText editText_ = new EditText(context);
149 | editText_.setRawInputType(InputType.TYPE_CLASS_NUMBER);
150 | editText_.setText((String) item.value);
151 | editText_.setHint("Input here");
152 |
153 | editText_.addTextChangedListener(new TextWatcher() {
154 | @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
155 | @Override public void afterTextChanged(Editable s) { }
156 |
157 | @Override
158 | public void onTextChanged(CharSequence s, int start, int before, int count) {
159 | saved_items.put(tags[position], Integer.parseInt(s.toString()));
160 | }
161 | });
162 |
163 | input = editText_;
164 | break;
165 |
166 | case MULTIPLE_CHOICE:
167 | // https://stackoverflow.com/questions/40700140/how-to-initialize-a-multiple-choice-alert-dialog-with-every-option-selected
168 | String[] items = (String[]) item.value;
169 | ArrayList results = new ArrayList<>();
170 |
171 | boolean[] checkedItems = new boolean[items.length];
172 |
173 | AlertDialog.Builder builder = new AlertDialog.Builder(context);
174 | builder.setMultiChoiceItems(items, checkedItems, (dialog, which, isChecked) -> {
175 | if (isChecked && !results.contains(items[which])) {
176 | results.add(items[which]);
177 |
178 | } else if (results.contains(items[which])) {
179 | results.remove(which);
180 | }
181 |
182 | }).setPositiveButton("OK", (dialog, id) ->
183 | saved_items.put(tags[position], results)
184 |
185 | ).setNegativeButton("Cancel", (dialog, id) ->
186 | dialog.dismiss()
187 | );
188 |
189 | break;
190 |
191 | default:
192 | break;
193 | }
194 |
195 | holder.holder.addView(input);
196 | }
197 |
198 | @Override
199 | public int getItemCount() {
200 | return config.getConfigs().size();
201 | }
202 |
203 | public static class ViewHolder extends RecyclerView.ViewHolder {
204 |
205 | TextView title;
206 |
207 | FrameLayout holder;
208 |
209 | public ViewHolder(@NonNull View itemView) {
210 | super(itemView);
211 | title = itemView.findViewById(R.id.config_title);
212 | holder = itemView.findViewById(R.id.input_holder);
213 | }
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/adapters/ModulesRecyclerViewAdapter.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.adapters;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.res.Resources;
8 | import android.util.Log;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.ImageView;
13 | import android.widget.TextView;
14 |
15 | import androidx.annotation.NonNull;
16 | import androidx.core.content.res.ResourcesCompat;
17 | import androidx.recyclerview.widget.RecyclerView;
18 |
19 | import com.openblocks.android.ModuleConfigActivity;
20 | import com.openblocks.android.R;
21 | import com.openblocks.android.modman.ModuleManager;
22 | import com.openblocks.android.modman.models.Module;
23 | import com.openblocks.moduleinterface.OpenBlocksModule;
24 |
25 | import java.lang.ref.WeakReference;
26 | import java.util.ArrayList;
27 | import java.util.HashMap;
28 |
29 | public class ModulesRecyclerViewAdapter extends RecyclerView.Adapter {
30 | private static final String TAG = "ModuleRVAdapter";
31 | WeakReference activity;
32 | // TODO: REPLACE THIS WITH JUST MODULE MANAGER
33 | private HashMap> data = new HashMap<>();
34 | private ArrayList modules;
35 | private ModuleManager moduleManager;
36 |
37 | public ModulesRecyclerViewAdapter(Activity activity) {
38 | this.activity = new WeakReference<>(activity);
39 | }
40 |
41 | public ModulesRecyclerViewAdapter(HashMap> data, Activity activity) {
42 | this.data = data;
43 | this.activity = new WeakReference<>(activity);
44 |
45 | moduleManager = ModuleManager.getInstance();
46 | modules = moduleManager.getModulesAsList();
47 | }
48 |
49 | public void updateView(HashMap> data) {
50 | this.data = data;
51 | notifyDataSetChanged();
52 | }
53 |
54 | @NonNull
55 | @Override
56 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
57 | return new ViewHolder(
58 | LayoutInflater
59 | .from(parent.getContext())
60 | .inflate(R.layout.rv_module_item, parent, false)
61 | );
62 | }
63 |
64 | @SuppressLint("SetTextI18n")
65 | @Override
66 | public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
67 | Log.d(TAG, "onBindViewHolder: called.");
68 | Module item = modules.get(position);
69 |
70 | holder.name.setText(item.name);
71 | holder.description.setText(item.description);
72 |
73 | // Check if this module is active
74 | if (item.equals(moduleManager.getActiveModule(item.module_type))) {
75 | // Nop it's inactive, red text with NOT ACTIVE text
76 | holder.active_status.setText("NOT ACTIVE");
77 | holder.active_status.setTextColor(0xFFE61212);
78 | }
79 |
80 | Context context = activity.get();
81 | Resources resources = context.getResources();
82 | Resources.Theme theme = context.getTheme();
83 |
84 | switch (item.module_type) {
85 | case PROJECT_MANAGER:
86 | holder.module_type.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ic_project_manager, theme));
87 | break;
88 | case PROJECT_PARSER:
89 | holder.module_type.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ic_project_parser, theme));
90 | break;
91 | case PROJECT_LAYOUT_GUI:
92 | holder.module_type.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ic_layout, theme));
93 | break;
94 | case PROJECT_CODE_GUI:
95 | holder.module_type.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ic_code, theme));
96 | break;
97 | case PROJECT_COMPILER:
98 | holder.module_type.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ic_compiler, theme));
99 | break;
100 | }
101 |
102 | holder.body.setOnClickListener(v -> {
103 | Intent open_config = new Intent(activity.get(), ModuleConfigActivity.class);
104 | open_config.putExtra("module", item);
105 | activity.get().startActivity(open_config);
106 | });
107 | }
108 |
109 | @Override
110 | public int getItemCount() {
111 | if (data == null) return 0;
112 |
113 | int sum = 0;
114 |
115 | for (ArrayList modules : data.values()) {
116 | if (modules == null) continue;
117 | sum += modules.size();
118 | }
119 |
120 | return sum;
121 | }
122 |
123 | public static class ViewHolder extends RecyclerView.ViewHolder {
124 |
125 | TextView name;
126 | TextView description;
127 | TextView active_status;
128 |
129 | ImageView module_type;
130 |
131 | View body;
132 |
133 | public ViewHolder(@NonNull View itemView) {
134 | super(itemView);
135 | name = itemView.findViewById(R.id.module_title);
136 | description = itemView.findViewById(R.id.module_description);
137 | module_type = itemView.findViewById(R.id.module_type);
138 | active_status = itemView.findViewById(R.id.module_active_status);
139 |
140 | body = itemView.findViewById(R.id.module_body);
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/adapters/ProjectRecyclerViewAdapter.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.adapters;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.TextView;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.recyclerview.widget.RecyclerView;
10 |
11 | import com.openblocks.android.R;
12 | import com.openblocks.moduleinterface.models.OpenBlocksProjectMetadata;
13 |
14 | import java.util.ArrayList;
15 |
16 | public class ProjectRecyclerViewAdapter extends RecyclerView.Adapter {
17 |
18 | ArrayList projects_metadata;
19 |
20 | public ProjectRecyclerViewAdapter(ArrayList projects_metadata) {
21 | this.projects_metadata = projects_metadata;
22 | }
23 |
24 | @NonNull
25 | @Override
26 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
27 | return new ViewHolder(
28 | LayoutInflater.from(parent.getContext())
29 | .inflate(R.layout.rv_project_item, parent)
30 | );
31 | }
32 |
33 | @Override
34 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
35 | OpenBlocksProjectMetadata metadata = projects_metadata.get(position);
36 |
37 | holder.project_title.setText(metadata.getName());
38 | holder.project_package.setText(metadata.getPackageName());
39 | }
40 |
41 | @Override
42 | public int getItemCount() {
43 | return projects_metadata.size();
44 | }
45 |
46 | static class ViewHolder extends RecyclerView.ViewHolder {
47 |
48 | TextView project_title;
49 | TextView project_package;
50 |
51 | public ViewHolder(@NonNull View itemView) {
52 | super(itemView);
53 |
54 | project_title = itemView.findViewById(R.id.project_title);
55 | project_package = itemView.findViewById(R.id.project_package);
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/constants/IncludedBinaries.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.constants;
2 |
3 | import android.content.Context;
4 |
5 | import com.openblocks.moduleinterface.models.compiler.IncludedBinary;
6 |
7 | public class IncludedBinaries {
8 | public static IncludedBinary[] INCLUDED_BINARIES;
9 |
10 | public static void init(Context context) {
11 | String nativeLibraryDir = context.getApplicationInfo().nativeLibraryDir;
12 |
13 | INCLUDED_BINARIES = new IncludedBinary[] {
14 | new IncludedBinary(
15 | "aapt",
16 | 1,
17 | nativeLibraryDir.concat("/bin/aapt")
18 | ),
19 | new IncludedBinary(
20 | "aapt2",
21 | 1,
22 | nativeLibraryDir.concat("/bin/aapt2")
23 | ),
24 | new IncludedBinary(
25 | "zipalign",
26 | 1,
27 | nativeLibraryDir.concat("/bin/zipalign")
28 | ),
29 | };
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/dialog/NewProjectDialog.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.dialog;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.annotation.NonNull;
6 |
7 | import com.openblocks.moduleinterface.models.OpenBlocksProjectMetadata;
8 | import com.openblocks.moduleinterface.models.OpenBlocksRawProject;
9 |
10 | import java.util.ArrayList;
11 |
12 | public class NewProjectDialog extends ProjectMetadataEditDialog {
13 |
14 | public NewProjectDialog(@NonNull Context context, String newProjectId) {
15 | super(context, new OpenBlocksProjectMetadata("", "", "", 1), newProjectId);
16 |
17 | projectId = newProjectId;
18 | titleText = "New project";
19 | buttonText = "Create project";
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/dialog/ProjectMetadataEditDialog.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.dialog;
2 |
3 | import android.content.Context;
4 | import android.widget.TextView;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.appcompat.app.AlertDialog;
8 |
9 | import com.google.android.material.button.MaterialButton;
10 | import com.google.android.material.textfield.TextInputEditText;
11 | import com.openblocks.android.databinding.DialogEditProjectMetadataBinding;
12 | import com.openblocks.moduleinterface.models.OpenBlocksProjectMetadata;
13 |
14 | public class ProjectMetadataEditDialog extends AlertDialog {
15 |
16 | protected final TextView title;
17 | protected final TextInputEditText appName;
18 | protected final TextInputEditText packageName;
19 | protected final TextInputEditText versionName;
20 | protected final TextInputEditText versionCode;
21 | protected final MaterialButton saveButton;
22 | protected String projectId;
23 |
24 | // TODO: Set title to "Edit "
25 |
26 | protected String titleText = "Edit";
27 | protected String buttonText = "Save project";
28 |
29 | protected OnMetadataSavedListener listener;
30 |
31 | public ProjectMetadataEditDialog(@NonNull Context context, OpenBlocksProjectMetadata metadata, String project_id) {
32 | super(context);
33 | projectId = project_id;
34 |
35 | DialogEditProjectMetadataBinding binding = DialogEditProjectMetadataBinding.inflate(getLayoutInflater());
36 | setView(binding.getRoot());
37 |
38 | title = binding.textView2;
39 | appName = binding.editAppName;
40 | packageName = binding.editPackage;
41 | versionName = binding.editVersionName;
42 | versionCode = binding.editVersionCode;
43 | saveButton = binding.okButton;
44 |
45 | // Set these values
46 | appName.setText(metadata.getName());
47 | packageName.setText(metadata.getPackageName());
48 | versionName.setText(metadata.getVersionName());
49 | versionCode.setText(metadata.getVersionCode());
50 | }
51 |
52 | @Override
53 | protected void onStart() {
54 | super.onStart();
55 |
56 | title.setText(titleText);
57 | saveButton.setText(buttonText);
58 |
59 | saveButton.setOnClickListener(v -> {
60 | if (!validateInput()) return;
61 |
62 | listener.onMetadataSaved(
63 | appName.getText().toString(),
64 | packageName.getText().toString(),
65 | versionName.getText().toString(),
66 | Integer.parseInt(versionCode.getText().toString())
67 | );
68 |
69 | dismiss();
70 | });
71 | }
72 |
73 | /**
74 | * @param Any class extending {@link ProjectMetadataEditDialog}.
75 | * @param listener The {@link OnMetadataSavedListener} object to register as callback for this dialog instance.
76 | * @return The current {@link ProjectMetadataEditDialog}.
77 | */
78 | public T addOnMetadataSavedListener(OnMetadataSavedListener listener) {
79 | this.listener = listener;
80 | return (T) this;
81 | }
82 |
83 | /**
84 | * Validates input of all TextInputEditTexts in this dialog. If a text field has invalid data,
85 | * an error is set, if not, its error gets cleared.
86 | *
87 | * @return If the input in the TextInputEditTexts is valid.
88 | */
89 | protected boolean validateInput() {
90 | if (appName.getText().toString().isEmpty()) {
91 | appName.setError("Missing app name");
92 | } else {
93 | appName.setError(null);
94 | }
95 |
96 | if (packageName.getText().toString().isEmpty()) {
97 | packageName.setError("Missing package name");
98 | } else {
99 | packageName.setError(null);
100 | }
101 |
102 | if (versionName.getText().toString().isEmpty()) {
103 | versionName.setError("Missing version name");
104 | } else {
105 | versionName.setError(null);
106 | }
107 |
108 | if (versionCode.getText().toString().isEmpty()) {
109 | versionCode.setError("Missing version code");
110 | } else {
111 | versionCode.setError(null);
112 | }
113 |
114 | return appName.getError() == null && packageName.getError() == null
115 | && versionName.getError() == null && versionCode.getError() == null;
116 | }
117 |
118 | /**
119 | * A listener class used with a {@link ProjectMetadataEditDialog} class, providing an event
120 | * when the metadata for a project has been saved.
121 | */
122 | public interface OnMetadataSavedListener {
123 | /**
124 | * Called when metadata for the project has been saved.
125 | *
126 | * @param appName The project's new application name.
127 | * @param packageName The project's new APK package name.
128 | * @param versionName The project's new version name.
129 | * @param versionCode The project's new version code.
130 | */
131 | void onMetadataSaved(String appName, String packageName, String versionName, int versionCode);
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/fragments/main/ModulesFragment.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.fragments.main;
2 |
3 | import android.os.Bundle;
4 |
5 | import androidx.fragment.app.Fragment;
6 | import androidx.recyclerview.widget.RecyclerView;
7 | import androidx.recyclerview.widget.StaggeredGridLayoutManager;
8 |
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 |
13 | import com.openblocks.android.R;
14 | import com.openblocks.android.adapters.ModulesRecyclerViewAdapter;
15 | import com.openblocks.android.modman.models.Module;
16 | import com.openblocks.moduleinterface.OpenBlocksModule;
17 |
18 | import java.util.ArrayList;
19 | import java.util.HashMap;
20 |
21 | /**
22 | * A simple {@link Fragment} subclass.
23 | * Use the {@link ModulesFragment#newInstance} factory method to
24 | * create an instance of this fragment.
25 | */
26 | public class ModulesFragment extends Fragment {
27 |
28 | // TODO: MVVM
29 |
30 | // Every modules (unsorted), this is used to display the recyclerview
31 | HashMap> modules;
32 |
33 | public ModulesFragment() {
34 | // Required empty public constructor
35 | }
36 |
37 | /**
38 | * Use this factory method to create a new instance of
39 | * this fragment using the provided parameters.
40 | *
41 | * @param modules List of Modules
42 | * @return A new instance of fragment ModulesFragment.
43 | */
44 | // TODO: Rename and change types and number of parameters
45 | public static ModulesFragment newInstance(HashMap> modules) {
46 | ModulesFragment fragment = new ModulesFragment();
47 |
48 | Bundle args = new Bundle();
49 | args.putParcelableArrayList("PROJECT_MANAGER", modules.get(OpenBlocksModule.Type.PROJECT_MANAGER));
50 | args.putParcelableArrayList("PROJECT_PARSER", modules.get(OpenBlocksModule.Type.PROJECT_PARSER));
51 | args.putParcelableArrayList("PROJECT_CODE_GUI", modules.get(OpenBlocksModule.Type.PROJECT_CODE_GUI));
52 | args.putParcelableArrayList("PROJECT_LAYOUT_GUI", modules.get(OpenBlocksModule.Type.PROJECT_LAYOUT_GUI));
53 | args.putParcelableArrayList("PROJECT_COMPILER", modules.get(OpenBlocksModule.Type.PROJECT_COMPILER));
54 | fragment.setArguments(args);
55 |
56 | return fragment;
57 | }
58 |
59 | @Override
60 | public void onCreate(Bundle savedInstanceState) {
61 | super.onCreate(savedInstanceState);
62 | if (getArguments() != null) {
63 | modules = new HashMap<>();
64 |
65 | modules.put(OpenBlocksModule.Type.PROJECT_MANAGER, getArguments().getParcelableArrayList("PROJECT_MANAGER"));
66 | modules.put(OpenBlocksModule.Type.PROJECT_PARSER, getArguments().getParcelableArrayList("PROJECT_PARSER"));
67 | modules.put(OpenBlocksModule.Type.PROJECT_CODE_GUI, getArguments().getParcelableArrayList("PROJECT_CODE_GUI"));
68 | modules.put(OpenBlocksModule.Type.PROJECT_LAYOUT_GUI, getArguments().getParcelableArrayList("PROJECT_LAYOUT_GUI"));
69 | modules.put(OpenBlocksModule.Type.PROJECT_COMPILER, getArguments().getParcelableArrayList("PROJECT_COMPILER"));
70 | }
71 | }
72 |
73 | @Override
74 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
75 | Bundle savedInstanceState) {
76 | // Inflate the layout for this fragment
77 | View root = inflater.inflate(R.layout.fragment_modules, container, false);
78 |
79 | RecyclerView modules_list = root.findViewById(R.id.modules_list);
80 | modules_list.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
81 |
82 | ModulesRecyclerViewAdapter adapter = new ModulesRecyclerViewAdapter(modules, requireActivity());
83 | modules_list.setAdapter(adapter);
84 |
85 | return root;
86 | }
87 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/fragments/main/ProjectsFragment.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.fragments.main;
2 |
3 | import android.os.Bundle;
4 |
5 | import androidx.fragment.app.Fragment;
6 | import androidx.recyclerview.widget.LinearLayoutManager;
7 | import androidx.recyclerview.widget.RecyclerView;
8 |
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 |
13 | import com.openblocks.android.R;
14 | import com.openblocks.android.adapters.ProjectRecyclerViewAdapter;
15 | import com.openblocks.moduleinterface.models.OpenBlocksProjectMetadata;
16 |
17 | import java.util.ArrayList;
18 |
19 | /**
20 | * A simple {@link Fragment} subclass.
21 | * Use the {@link ProjectsFragment#newInstance} factory method to
22 | * create an instance of this fragment.
23 | */
24 | public class ProjectsFragment extends Fragment {
25 |
26 | ArrayList projectMetadata;
27 |
28 | public ProjectsFragment() {
29 | // Required empty public constructor
30 | }
31 |
32 | /**
33 | * Use this factory method to create a new instance of
34 | * this fragment using the provided parameters.
35 | *
36 | * @return A new instance of fragment ProjectsFragment.
37 | */
38 | public static ProjectsFragment newInstance(ArrayList projectMetadata) {
39 | ProjectsFragment fragment = new ProjectsFragment();
40 | Bundle args = new Bundle();
41 | args.putParcelableArrayList("projects_metadata", projectMetadata);
42 | fragment.setArguments(args);
43 | return fragment;
44 | }
45 |
46 | @Override
47 | public void onCreate(Bundle savedInstanceState) {
48 | super.onCreate(savedInstanceState);
49 |
50 | if (getArguments() != null) {
51 | this.projectMetadata = getArguments().getParcelableArrayList("projects_metadata");
52 | }
53 | }
54 |
55 | @Override
56 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
57 | Bundle savedInstanceState) {
58 | // Inflate the layout for this fragment
59 | View root = inflater.inflate(R.layout.fragment_projects, container, false);
60 |
61 | RecyclerView projects = root.findViewById(R.id.projectRecyclerView);
62 | ProjectRecyclerViewAdapter adapter = new ProjectRecyclerViewAdapter(projectMetadata);
63 | projects.setLayoutManager(new LinearLayoutManager(requireContext()));
64 | projects.setAdapter(adapter);
65 |
66 | return root;
67 | }
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/fragments/projecteditor/CodeEditFragment.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.fragments.projecteditor;
2 |
3 | import android.os.Bundle;
4 |
5 | import androidx.fragment.app.Fragment;
6 |
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import com.openblocks.android.R;
12 | import com.openblocks.android.modman.ModuleLoader;
13 | import com.openblocks.android.modman.ModuleManager;
14 | import com.openblocks.android.modman.models.Module;
15 | import com.openblocks.moduleinterface.OpenBlocksModule;
16 | import com.openblocks.moduleinterface.callbacks.SaveCallback;
17 | import com.openblocks.moduleinterface.projectfiles.OpenBlocksCode;
18 | import com.openblocks.moduleinterface.projectfiles.OpenBlocksLayout;
19 |
20 | public class CodeEditFragment extends Fragment {
21 |
22 | OpenBlocksCode code;
23 | OpenBlocksLayout layout;
24 | SaveCallback code_save;
25 | OpenBlocksModule.ProjectCodeGUI module_instance;
26 |
27 | public CodeEditFragment(OpenBlocksCode code, OpenBlocksLayout layout, SaveCallback code_save) {
28 | this.code = code;
29 | this.layout = layout;
30 | this.code_save = code_save;
31 | }
32 |
33 | @Override
34 | public void onCreate(Bundle savedInstanceState) {
35 | super.onCreate(savedInstanceState);
36 |
37 | ModuleManager moduleManager = ModuleManager.getInstance();
38 | Module code_ui_module = moduleManager.getActiveModule(OpenBlocksModule.Type.PROJECT_CODE_GUI);
39 | module_instance = ModuleLoader.load(requireContext(), code_ui_module, OpenBlocksModule.ProjectCodeGUI.class);
40 | }
41 |
42 | @Override
43 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
44 | Bundle savedInstanceState) {
45 | // Inflate the layout for this fragment
46 | View root = inflater.inflate(R.layout.fragment_code_edit, container, false);
47 | module_instance.show(requireContext(), root.findViewById(R.id.code_edit_parent), code, layout, code_save);
48 | return root;
49 | }
50 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/fragments/projecteditor/LayoutEditFragment.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.fragments.projecteditor;
2 |
3 | import android.os.Bundle;
4 |
5 | import androidx.fragment.app.Fragment;
6 |
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import com.openblocks.android.R;
12 | import com.openblocks.android.modman.ModuleLoader;
13 | import com.openblocks.android.modman.ModuleManager;
14 | import com.openblocks.android.modman.models.Module;
15 | import com.openblocks.moduleinterface.OpenBlocksModule;
16 | import com.openblocks.moduleinterface.callbacks.SaveCallback;
17 | import com.openblocks.moduleinterface.projectfiles.OpenBlocksCode;
18 | import com.openblocks.moduleinterface.projectfiles.OpenBlocksLayout;
19 |
20 | public class LayoutEditFragment extends Fragment {
21 |
22 | OpenBlocksCode code;
23 | OpenBlocksLayout layout;
24 | SaveCallback layout_save;
25 | OpenBlocksModule.ProjectLayoutGUI module_instance;
26 |
27 | public LayoutEditFragment(OpenBlocksLayout layout, OpenBlocksCode code, SaveCallback code_save) {
28 | this.layout = layout;
29 | this.code = code;
30 | this.layout_save = code_save;
31 | }
32 |
33 | @Override
34 | public void onCreate(Bundle savedInstanceState) {
35 | super.onCreate(savedInstanceState);
36 |
37 | ModuleManager moduleManager = ModuleManager.getInstance();
38 | Module layout_ui_module = moduleManager.getActiveModule(OpenBlocksModule.Type.PROJECT_LAYOUT_GUI);
39 | module_instance = ModuleLoader.load(requireContext(), layout_ui_module, OpenBlocksModule.ProjectLayoutGUI.class);
40 | }
41 |
42 | @Override
43 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
44 | Bundle savedInstanceState) {
45 | // Inflate the layout for this fragment
46 | View root = inflater.inflate(R.layout.fragment_code_edit, container, false);
47 | module_instance.show(requireContext(), root.findViewById(R.id.code_edit_parent), code, layout, layout_save);
48 | return root;
49 | }
50 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/fragments/projecteditor/LogFragment.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.fragments.projecteditor;
2 |
3 | import android.os.Bundle;
4 |
5 | import androidx.fragment.app.Fragment;
6 |
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.TextView;
11 |
12 | import com.openblocks.android.R;
13 | import com.openblocks.android.modman.ModuleLogger;
14 |
15 | // Component is not planned yet, It's currently used just for a placeholder
16 | public class LogFragment extends Fragment {
17 |
18 | ModuleLogger logger = ModuleLogger.getInstance();
19 |
20 | public LogFragment() { }
21 |
22 | @Override
23 | public void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | }
26 |
27 | @Override
28 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
29 | Bundle savedInstanceState) {
30 | // Inflate the layout for this fragment
31 | View root = inflater.inflate(R.layout.fragment_log, container, false);
32 |
33 | // Every time the log is updated, our log text should also be updated
34 | logger.setLiveLog(log -> {
35 | TextView log_text = root.findViewById(R.id.log_text);
36 | log_text.setText(log);
37 | });
38 |
39 | root.findViewById(R.id.clear_log_button).setOnClickListener(v -> logger.clearLog());
40 |
41 | return root;
42 | }
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/helpers/BlockCollectionParser.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.helpers;
2 |
3 | import android.util.Pair;
4 |
5 | import com.openblocks.moduleinterface.OpenBlocksModule;
6 | import com.openblocks.moduleinterface.models.code.ParseBlockTask;
7 |
8 | import java.util.HashMap;
9 |
10 | public class BlockCollectionParser {
11 |
12 | /**
13 | * This function is used to parse blocks that are set by BlocksCollection module
14 | * @param blocks The blocks got from {@link OpenBlocksModule.BlocksCollection#getBlocks()} or something like this: Object[Object[String opcode, String format, ParseBlockTask]]
15 | * @return A HashMap of opcode, Pair of format and ParseBlockTask
16 | */
17 | public static HashMap> parseBlocks(Object[] blocks) {
18 | // Object[Object[String opcode, String format, ParseBlockTask]]
19 |
20 | HashMap> result = new HashMap<>();
21 |
22 | for (Object block_object : blocks) {
23 | Object[] block = (Object[]) block_object;
24 |
25 | String opcode = (String) block[0];
26 | String format = (String) block[1];
27 | ParseBlockTask parseBlockTask = (ParseBlockTask) block[2];
28 |
29 | result.put(opcode, new Pair<>(format, parseBlockTask));
30 | }
31 |
32 | return result;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/helpers/FileHelper.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.helpers;
2 |
3 | import android.util.Log;
4 |
5 | import androidx.annotation.NonNull;
6 | import androidx.core.util.Pair;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.DataInputStream;
10 | import java.io.File;
11 | import java.io.FileInputStream;
12 | import java.io.FileOutputStream;
13 | import java.io.IOException;
14 | import java.io.InputStreamReader;
15 | import java.util.LinkedList;
16 |
17 | public class FileHelper {
18 |
19 | @NonNull
20 | public static String readFile(File file) throws IOException {
21 | return readFile(file.getAbsolutePath());
22 | }
23 |
24 | // Copied from: https://www.journaldev.com/9400/android-external-storage-read-write-save-file
25 | @NonNull
26 | public static String readFile(String path) throws IOException {
27 | StringBuilder output = new StringBuilder();
28 | FileInputStream fis = new FileInputStream(path);
29 | DataInputStream in = new DataInputStream(fis);
30 | BufferedReader br =
31 | new BufferedReader(new InputStreamReader(in));
32 | String strLine;
33 | while ((strLine = br.readLine()) != null) {
34 | output.append(strLine);
35 | }
36 | in.close();
37 | return output.toString();
38 | }
39 |
40 | public static byte[] readFile(final FileInputStream stream) {
41 | class Reader extends Thread {
42 | byte[] array = null;
43 | }
44 |
45 | Reader reader = new Reader() {
46 | public void run() {
47 | LinkedList> chunks = new LinkedList<>();
48 |
49 | // read the file and build chunks
50 | int size = 0;
51 | int globalSize = 0;
52 | do {
53 | try {
54 | int chunkSize = 8192;
55 | // read chunk
56 | byte[] buffer = new byte[chunkSize];
57 | size = stream.read(buffer, 0, chunkSize);
58 | if (size > 0) {
59 | globalSize += size;
60 |
61 | // add chunk to list
62 | chunks.add(new Pair<>(buffer, size));
63 | }
64 | } catch (Exception e) {
65 | // very bad
66 | }
67 | } while (size > 0);
68 |
69 | try {
70 | stream.close();
71 | } catch (Exception e) {
72 | // very bad
73 | }
74 |
75 | array = new byte[globalSize];
76 |
77 | // append all chunks to one array
78 | int offset = 0;
79 | for (Pair chunk : chunks) {
80 | // flush chunk to array
81 | System.arraycopy(chunk.first, 0, array, offset, chunk.second);
82 | offset += chunk.second;
83 | }
84 | }
85 | };
86 |
87 | reader.start();
88 | try {
89 | reader.join();
90 | } catch (InterruptedException e) {
91 | Log.e("Util", "Failed on reading file from storage while the locking Thread", e);
92 | return null;
93 | }
94 |
95 | return reader.array;
96 | }
97 |
98 | public static void writeFile(File file, byte[] data) throws IOException {
99 | if (!file.exists()) {
100 | file.getParentFile().mkdirs();
101 | file.createNewFile();
102 | }
103 | FileOutputStream outputStream = new FileOutputStream(file);
104 | outputStream.write(data);
105 | outputStream.flush();
106 | outputStream.close();
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/modman/ModuleJsonCorruptedException.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.modman;
2 |
3 | // This exception will be thrown if the modules.json is corrupted
4 | public class ModuleJsonCorruptedException extends Exception {
5 | public ModuleJsonCorruptedException(String message) { super(message); }
6 | }
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/modman/ModuleLoader.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.modman;
2 |
3 | import android.content.Context;
4 | import android.widget.Toast;
5 |
6 | import com.openblocks.android.modman.models.Module;
7 | import com.openblocks.moduleinterface.OpenBlocksModule;
8 |
9 | /**
10 | * ModuleLoader is a utility class used to load modules into OpenBlocksModule
11 | */
12 | public class ModuleLoader {
13 |
14 | @SuppressWarnings("unchecked")
15 | // TODO: 3/23/21 restore this
16 | public static T load(Context context, Module module, Class type) {
17 | ModuleManager moduleManager = ModuleManager.getInstance();
18 |
19 | Module project_manager = moduleManager.getActiveModule(OpenBlocksModule.Type.PROJECT_MANAGER);
20 | Class project_manager_class;
21 |
22 | try {
23 | project_manager_class = moduleManager.fetchModule(context, project_manager);
24 |
25 | return (T) project_manager_class.newInstance();
26 | } catch (ClassNotFoundException e) {
27 | e.printStackTrace();
28 |
29 | Toast.makeText(context, "Error whilst loading project manager module " + project_manager.name + ": Wrong classpath", Toast.LENGTH_LONG).show();
30 | } catch (IllegalAccessException | InstantiationException e) {
31 | e.printStackTrace();
32 |
33 | Toast.makeText(context, "Error while instantiating module " + project_manager.name + ": " + e.getMessage(), Toast.LENGTH_LONG).show();
34 | } catch (NullPointerException e) {
35 | e.printStackTrace();
36 |
37 | Toast.makeText(context, "Error while accessing a module: " + e.getMessage(), Toast.LENGTH_SHORT).show();
38 | }
39 |
40 | return null;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/modman/ModuleLogger.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.modman;
2 |
3 | import android.text.Spannable;
4 | import android.text.SpannableString;
5 | import android.text.SpannableStringBuilder;
6 | import android.text.Spanned;
7 | import android.text.style.ForegroundColorSpan;
8 | import android.text.style.StyleSpan;
9 |
10 | import com.openblocks.moduleinterface.OpenBlocksModule;
11 | import com.openblocks.moduleinterface.callbacks.Logger;
12 |
13 | public class ModuleLogger implements Logger {
14 |
15 | static ModuleLogger logger;
16 |
17 | public static ModuleLogger getInstance() {
18 | if (logger == null) {
19 | logger = new ModuleLogger();
20 | }
21 |
22 | return logger;
23 | }
24 |
25 | SpannableStringBuilder log;
26 | Class class_before;
27 |
28 | LiveLog liveLog = log -> { };
29 |
30 |
31 | @Override
32 | public void debug(Class extends OpenBlocksModule> module_class, String text) {
33 | log("DEBUG", module_class, text, 0xFF999999, false);
34 | }
35 |
36 | @Override
37 | public void trace(Class extends OpenBlocksModule> module_class, String text) {
38 | log("TRACE", module_class, text, 0xFFFFDB5A, false);
39 | }
40 |
41 | @Override
42 | public void info(Class extends OpenBlocksModule> module_class, String text) {
43 | log("INFO", module_class, text, 0xFF000000, false);
44 | }
45 |
46 | @Override
47 | public void warn(Class extends OpenBlocksModule> module_class, String text) {
48 | log("WARN", module_class, text, 0XFFFFAD1F, false);
49 | }
50 |
51 | @Override
52 | public void err(Class extends OpenBlocksModule> module_class, String text) {
53 | log("ERROR", module_class, text, 0xFFF31B1B, false);
54 | }
55 |
56 | @Override
57 | public void fatal(Class extends OpenBlocksModule> module_class, String text) {
58 | log("FATAL", module_class, text, 0xFFC80D0D, true);
59 | }
60 |
61 |
62 | private void log(String log_level, Class extends OpenBlocksModule> module_class, String log_text, int color, boolean bold) {
63 | String text = getLogStart(module_class) + " [" + log_level + "]: " + log_text;
64 | int start = log.length();
65 |
66 | log.append(
67 | text,
68 | new ForegroundColorSpan(color),
69 | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
70 | );
71 |
72 | if (bold)
73 | log.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), start, log.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
74 |
75 |
76 | // TODO: 3/21/21 Because some logs might be bit spammy, we might should optimize
77 | // so the UI doesn't freeze if there are soo many log calls
78 | liveLog.onLogChange(getText());
79 | }
80 |
81 |
82 | private String getLogStart(Class extends OpenBlocksModule> clazz) {
83 | // TODO: 3/21/21 Because the module might implement other interfaces,
84 | // we should just get classes that extends OpenBlocksModule
85 | return clazz.getInterfaces()[0].getName() + " " + clazz.getName();
86 | }
87 |
88 | public SpannableString getText() {
89 | return SpannableString.valueOf(log);
90 | }
91 |
92 | public void clearLog() {
93 | log.clear();
94 | }
95 |
96 | public void setLiveLog(LiveLog liveLog) {
97 | this.liveLog = liveLog;
98 | this.liveLog.onLogChange(getText());
99 | }
100 |
101 | public interface LiveLog {
102 | void onLogChange(SpannableString log);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/app/src/main/java/com/openblocks/android/modman/models/Module.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android.modman.models;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import com.openblocks.moduleinterface.OpenBlocksModule;
7 | import com.openblocks.moduleinterface.models.config.OpenBlocksConfig;
8 |
9 | import java.io.File;
10 |
11 | public class Module implements Parcelable {
12 | public String name;
13 | public String description;
14 | public String classpath;
15 | public String filename;
16 |
17 | public int version;
18 | public int lib_version;
19 |
20 | public File jar_file;
21 |
22 | public OpenBlocksModule.Type module_type;
23 |
24 | public Module() { }
25 |
26 | public Module(String filename, String name, String description, String classpath, int version, int lib_version, File jar_file, OpenBlocksModule.Type module_type) {
27 | this.filename = filename;
28 | this.name = name;
29 | this.description = description;
30 | this.classpath = classpath;
31 | this.version = version;
32 | this.lib_version = lib_version;
33 | this.jar_file = jar_file;
34 | this.module_type = module_type;
35 | }
36 |
37 | protected Module(Parcel in) {
38 | name = in.readString();
39 | description = in.readString();
40 | classpath = in.readString();
41 | version = in.readInt();
42 | lib_version = in.readInt();
43 | jar_file = new File(in.readString());
44 | module_type = OpenBlocksModule.Type.valueOf(in.readString());
45 | }
46 |
47 | public static final Creator CREATOR = new Creator() {
48 | @Override
49 | public Module createFromParcel(Parcel in) {
50 | return new Module(in);
51 | }
52 |
53 | @Override
54 | public Module[] newArray(int size) {
55 | return new Module[size];
56 | }
57 | };
58 |
59 | @Override
60 | public int describeContents() {
61 | return 0;
62 | }
63 |
64 | @Override
65 | public void writeToParcel(Parcel dest, int flags) {
66 | dest.writeString(name);
67 | dest.writeString(description);
68 | dest.writeString(classpath);
69 | dest.writeInt(version);
70 | dest.writeInt(lib_version);
71 | dest.writeString(jar_file.getAbsolutePath());
72 | dest.writeString(module_type.toString());
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi-v24/ic_about.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi-v24/ic_add_white.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi-v24/ic_discord.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi-v24/ic_home.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi-v24/ic_settings.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi-v24/ic_website.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-hdpi/ic_about.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_add_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-hdpi/ic_add_white.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_discord.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-hdpi/ic_discord.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-hdpi/ic_github.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-hdpi/ic_home.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-hdpi/ic_settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_website.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-hdpi/ic_website.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-mdpi/ic_about.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_add_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-mdpi/ic_add_white.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_discord.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-mdpi/ic_discord.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-mdpi/ic_github.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-mdpi/ic_home.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-mdpi/ic_settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_website.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-mdpi/ic_website.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xhdpi/ic_about.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_add_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xhdpi/ic_add_white.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_discord.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xhdpi/ic_discord.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xhdpi/ic_github.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xhdpi/ic_home.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xhdpi/ic_settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_website.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xhdpi/ic_website.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xxhdpi/ic_about.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_add_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xxhdpi/ic_add_white.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_discord.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xxhdpi/ic_discord.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xxhdpi/ic_github.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xxhdpi/ic_home.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xxhdpi/ic_settings.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_website.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xxhdpi/ic_website.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_discord.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xxxhdpi/ic_discord.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/drawable-xxxhdpi/ic_github.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_module_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_module_item_ripple.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | -
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_about.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_code.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_compiler.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_dashboard_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_home_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_import.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
13 |
16 |
19 |
22 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_layout.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notifications_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_project_manager.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_project_parser.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_run.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_settings.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/_main_drawer_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_about.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
19 |
20 |
28 |
29 |
30 |
31 |
32 |
33 |
37 |
38 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
20 |
21 |
31 |
32 |
43 |
44 |
48 |
49 |
53 |
54 |
55 |
56 |
63 |
64 |
73 |
74 |
83 |
84 |
85 |
93 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_module_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_project_editor.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
23 |
24 |
25 |
26 |
36 |
37 |
41 |
42 |
46 |
47 |
51 |
52 |
53 |
54 |
58 |
59 |
66 |
67 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_edit_project_metadata.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
30 |
31 |
42 |
43 |
54 |
55 |
56 |
57 |
69 |
70 |
80 |
81 |
82 |
83 |
94 |
95 |
106 |
107 |
108 |
109 |
119 |
120 |
131 |
132 |
133 |
134 |
149 |
150 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_code_edit.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_layout_edit.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_log.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
21 |
22 |
26 |
27 |
32 |
33 |
34 |
35 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_projects.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header_main.xml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
23 |
24 |
30 |
31 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_config_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
20 |
21 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_module_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
25 |
26 |
35 |
36 |
46 |
47 |
59 |
60 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_project_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
20 |
21 |
30 |
31 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/settings_activity.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/_main_drawer_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
15 | -
16 |
17 |
21 |
25 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_main_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
13 |
14 |
18 |
19 | -
20 |
21 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-hdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-mdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #121212
4 | #424242
5 | #1976D2
6 | #1565C0
7 | #e91e63
8 | #2ae91e63
9 | #e91e63
10 |
11 | #ffffff
12 | #ffffff
13 | #ffffff
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ffffff
4 | #ffffff
5 | #2196f3
6 | #1e88e5
7 | #e91e63
8 | #2ae91e63
9 | #e91e63
10 |
11 | #ffffff
12 | #ffffff
13 | #000000
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 | 8dp
7 | 176dp
8 | 16dp
9 | 8dp
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | OpenBlocks
3 |
4 | Docs
5 | Settings
6 | About
7 | Discord
8 | Community
9 | 0.1-alpha
10 |
11 | Hello blank fragment
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/root_preferences.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/test/java/com/openblocks/android/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.openblocks.android;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath "com.android.tools.build:gradle:4.1.2"
9 | classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.4"
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | google()
19 | jcenter()
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
--------------------------------------------------------------------------------
/copy_binaries.bat:
--------------------------------------------------------------------------------
1 | for %f in (
2 |
3 | android-build-tools\aapt\arm64-v8a
4 | android-build-tools\aapt\armeabi-v7a
5 | android-build-tools\aapt\x86
6 | android-build-tools\aapt\x86_64
7 |
8 | android-build-tools\aapt2\arm64-v8a
9 | android-build-tools\aapt2\armeabi-v7a
10 | android-build-tools\aapt2\x86
11 | android-build-tools\aapt2\x86_64
12 |
13 | android-build-tools\zipalign\arm64-v8a
14 | android-build-tools\zipalign\armeabi-v7a
15 | android-build-tools\zipalign\x86
16 | android-build-tools\zipalign\x86_64
17 |
18 | ) do xcopy %f app\src\main\jniLibs
19 |
--------------------------------------------------------------------------------
/copy_binaries.sh:
--------------------------------------------------------------------------------
1 | #/bin/sh
2 |
3 | git submodule update --init
4 |
5 | dest="app/src/main/jniLibs"
6 | mkdir -p $dest
7 |
8 | # Simply copies aapt, aapt2, and zipalign on android-build-tools into app/src/main/resources/lib
9 | cp -r android-build-tools/aapt/arm64-v8a android-build-tools/aapt/armeabi-v7a android-build-tools/aapt/x86 android-build-tools/aapt/x86_64 $dest
10 | cp -r android-build-tools/aapt2/arm64-v8a android-build-tools/aapt2/armeabi-v7a android-build-tools/aapt2/x86 android-build-tools/aapt2/x86_64 $dest
11 | cp -r android-build-tools/zipalign/arm64-v8a android-build-tools/zipalign/armeabi-v7a android-build-tools/zipalign/x86 android-build-tools/zipalign/x86_64 $dest
12 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -XX:+UseParallelGC
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenBlocksTeam/openblocks-app/a6cd2564076acd3f22805c46ac7c8378bb4dbf7b/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Mar 19 08:21:00 CET 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':module-interface'
2 | include ':app'
3 | project(':module-interface').projectDir = new File(rootDir, 'openblocks-module-interface/lib/')
4 | rootProject.name = "OpenBlocks"
--------------------------------------------------------------------------------